Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT根据childnode上的条件在输出中写入父级_Xml_Xslt - Fatal编程技术网

Xml XSLT根据childnode上的条件在输出中写入父级

Xml XSLT根据childnode上的条件在输出中写入父级,xml,xslt,Xml,Xslt,我想根据一些条件输出一个xml 这是我的输入XML <YIORDER01> <IDOC> <E1ORHDR> <E1OROPR> <VORNR>0010</VORNR> <E1OROPR_MAT> <MATNR>M0003-01</MATNR&g

我想根据一些条件输出一个xml

这是我的输入XML

<YIORDER01>
    <IDOC>
        <E1ORHDR>
            <E1OROPR>
                <VORNR>0010</VORNR>
                <E1OROPR_MAT>
                    <MATNR>M0003-01</MATNR>
                    <YE1OROPR_MAT>
                        <STTXT>REL</STTXT>
                        <MTART>ZPAR</MTART>
                        <POSTP>L</POSTP>
                    </YE1OROPR_MAT>
                </E1OROPR_MAT>
                <E1OROPR_MAT>
                    <MATNR>M0003-01</MATNR>
                    <YE1OROPR_MAT>
                        <STTXT>REL</STTXT>
                        <MTART>XYZ</MTART>
                        <POSTP>M</POSTP>
                    </YE1OROPR_MAT>
                </E1OROPR_MAT>
            </E1OROPR>
            <E1OROPR>
                <VORNR>0020</VORNR>
                <E1OROPR_MAT>
                    <MATNR>M0003-01</MATNR>
                    <YE1OROPR_MAT>
                        <STTXT>REL</STTXT>
                        <MTART>ZPAR</MTART>
                        <POSTP>L</POSTP>
                    </YE1OROPR_MAT>
                </E1OROPR_MAT>
            </E1OROPR>
        </E1ORHDR>
    </IDOC>
</YIORDER01>

0010
M0003-01
雷尔
ZPAR
L
M0003-01
雷尔
XYZ
M
0020
M0003-01
雷尔
ZPAR
L
输出是这样的

<PartOrderList>
   <PartOrder>
      <OperationBONumber>0010</OperationBONumber>
      <PartOrderLine>
         <MaterialNumber>M0003-01</MaterialNumber>
         <ShipmentType>REL</ShipmentType>
      </PartOrderLine>
   </PartOrder>
   <PartOrder>
      <OperationBONumber>0020</OperationBONumber>
   </PartOrder>
</PartOrderList>

0010
M0003-01
雷尔
0020
我的XSLT是这样的

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="YIORDER01">
        <xsl:element name="PartOrderList">
            <xsl:for-each select="IDOC/E1ORHDR/E1OROPR">
                <xsl:element name="PartOrder">
                    <xsl:element name="OperationBONumber">
                        <xsl:value-of select="VORNR"/>
                    </xsl:element>
                    <xsl:for-each select="E1OROPR_MAT">
                        <xsl:if test="YE1OROPR_MAT/MTART = &apos;ZPAR&apos; and YE1OROPR_MAT/POSTP = &apos;L&apos;">
                            <xsl:element name="PartOrderLine">
                                <xsl:element name="MaterialNumber">
                                    <xsl:value-of select="MATNR"/>
                                </xsl:element>
                                <xsl:element name="ShipmentType">
                                    <xsl:value-of select="YE1OROPR_MAT/STTXT"/>
                                </xsl:element>
                            </xsl:element>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

这里的问题是,我不想在输出中使用第二个“PartOrder”标记,因为它没有任何“PartOrderLine”子级

xslt中使用的规则:

  • 为输入中的每个“E1OROPR”在输出中创建“PartOrder”标记
  • 仅当“MTART”=“ZPAR”和“POST”=“L”时,才在“PartOrder”内创建“PartOrderLine”标记
  • 如果输出中没有有效的“PartOrderLine”标记,请不要创建任何“PartOrder”标记
  • 使用xslt,我能够实现规则1和2,但不知道如何实现规则3。
    有什么方法可以使用xslt实现这一点吗


    请提供帮助。

    您需要将条件作为谓词添加到每个select表达式的外部
    ,以便只为您知道的每个over元素生成至少一个
    PartOrderLine

    <xsl:for-each select="IDOC/E1ORHDR/E1OROPR[
          E1OROPR_MAT/YE1OROPR_MAT[MTART = 'ZPAR' and POSTP = 'L']]">
    

    仅供参考:以下是我的做法。这种方法的优点是:

    • 您的有效行规则只定义一次,因此如果您更改逻辑,它将同时更改POs和POLINE
    • 如果你想修改任何东西,每一条数据都很容易找到
    • 所有模板都可以并行运行,(通常)在多处理器机器上运行得更快

    
    有效的
    无效的
    

    也就是说,为了进一步改进这一点,可能还有很多工作要做/您选择的选项应该取决于您最适合使用的代码(在某种程度上;显然,任何新方法都有一个学习曲线,可能会导致最初的不适,因此这一点应该考虑到长期考虑).

    旁注:我会避免使用for-each循环;XSLT被设计成以功能的方式工作;因此,使用模板执行for-each而不是显式for-each循环更符合语言的预期用途(一旦您了解了这种方法,您将获得更好的性能并使事情更易于维护。注意:您的示例数据中还包含一个额外的r,这可能会导致它看起来像是工作代码有缺陷-
    ZPAR
    r
    是的,John,感谢您指出这一点。我已经编辑了这个问题。
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
      <xsl:output method="xml" indent="yes"/>
    
      <!-- Part Order List -->
      <xsl:template match="/*">
        <xsl:element name="PartOrderList">
          <xsl:apply-templates select=".//E1OROPR" /> 
        </xsl:element>
      </xsl:template>
    
      <!-- Part Order List > Part Order -->
      <xsl:template match="//E1OROPR">
        <xsl:variable name="IsValid">
          <xsl:call-template name="HasOrIsValidPOLine" />
        </xsl:variable>
        <xsl:if test="$IsValid='VALID'"> <!-- only display the part order if there's a valid line under it-->
          <xsl:element name="PartOrder">
            <xsl:apply-templates select=".//VORNR" />
            <xsl:apply-templates select=".//E1OROPR_MAT" />
          </xsl:element>
        </xsl:if>
      </xsl:template>
    
      <!-- Part Order List > Part Order > Operational BO Number -->
      <xsl:template match="//VORNR">
        <xsl:element name="OperationBONumber">
          <xsl:value-of select="text()"/>
        </xsl:element>
      </xsl:template>
    
      <!-- Part Order List > Part Order > Part Order Line -->
      <xsl:template match="//E1OROPR_MAT">
        <xsl:variable name="IsValid">
          <xsl:call-template name="HasOrIsValidPOLine" />
        </xsl:variable>
        <xsl:if test="$IsValid='VALID'">
          <!-- only display the part order line if it's valid-->
          <xsl:element name="PartOrderLine">
            <xsl:apply-templates select=".//MATNR" />
            <xsl:apply-templates select=".//STTXT" />
          </xsl:element>
        </xsl:if>
      </xsl:template>
    
      <!-- Part Order List > Part Order > Part Order Line > Material Number -->
      <xsl:template match="//MATNR">
        <xsl:element name="MaterialNumber">
          <xsl:value-of select="text()"/>
        </xsl:element>
      </xsl:template>
    
      <!-- Part Order List > Part Order > Part Order Line > Shipment Type -->
      <xsl:template match="//STTXT">
        <xsl:element name="ShipmentType">
          <xsl:value-of select="text()"/>
        </xsl:element>
      </xsl:template>
    
      <xsl:template name="HasOrIsValidPOLine">
        <xsl:choose>
          <xsl:when test=".//MTART/text() = 'ZPAR' and .//POSTP/text() = 'L'">VALID</xsl:when>
          <xsl:otherwise>INVALID</xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
    </xsl:stylesheet>