XSLT将多个源节点映射到同一目标节点

时间:2014-04-22 21:37:24

标签: xslt

我们有一组订单作为单个XML。其中一条线是强制性的,称为主线,每个订单只有一条,并且在标题级别没有任何重复。还有两种不是强制性的行类型,但可以为每个订单重复。以下是输入XML示例,输出只是行的集合。

包括主线,所有可选线和所有自定义线在内的所有线都需要根据每个订单映射到目标上的相同元素。

    <orderDetails>
   <data>
      <order>
         <poNumber>1234</poNumber>
         <storeNumber>35</storeNumber>
         <itemNumber>1895550045</itemNumber>
         <mainLine>
            <referenceNumber>I1</referenceNumber>
            <basicInstallCostAmount>100</basicInstallCostAmount>
            <basicInstallQuantity>12</basicInstallQuantity>
         </mainLine>
         <optionalLines>
            <optionalLine>
               <referenceNumber>OP10</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>15</orderQuantity>
               <orderRetailAmount>200</orderRetailAmount>
            </optionalLine>
            <optionalLine>
               <referenceNumber>OP105</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>23</orderQuantity>
               <orderRetailAmount>655</orderRetailAmount>
            </optionalLine>
         </optionalLines>
         <customLines>
            <customLine>
               <referenceNumber>C100</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>123</orderQuantity>
               <orderRetailAmount>12300</orderRetailAmount>
            </customLine>
            <customLine>
               <referenceNumber>C1337</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>357</orderQuantity>
               <orderRetailAmount>143</orderRetailAmount>
            </customLine>
         </customLines>
      </order>
      <order>
         <poNumber>5678</poNumber>
         <storeNumber>52</storeNumber>
         <itemNumber>0005554433</itemNumber>
         <mainLine>
            <referenceNumber>I21</referenceNumber>
            <basicInstallCostAmount>3000</basicInstallCostAmount>
            <basicInstallQuantity>35</basicInstallQuantity>
         </mainLine>
         <optionalLines>
            <optionalLine>
               <referenceNumber>OP134</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>1500</orderQuantity>
               <orderRetailAmount>350000</orderRetailAmount>
            </optionalLine>
         </optionalLines>
         <customLines>
            <customLine>
               <referenceNumber>C140</referenceNumber>
               <duoiCode>EA</duoiCode>
               <orderQuantity>13</orderQuantity>
               <orderRetailAmount>100</orderRetailAmount>
            </customLine>
         </customLines>
      </order>
   </data>
</orderDetails>

预期产出 -

<PoHeadersCollection>
   <PoHeaders>
      <poNumber>1234</poNumber>
      <storeNumber>35</storeNumber>
      <itemNumber>1895550045</itemNumber>
      <PoLinesCollection>
         <PoLines>
            <partNumber>I1</partNumber>
            <Quantity>12</Quantity>
            <installType>Basic</installType>
            <lineAmount>100</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>OP10</partNumber>
            <Uom>EA</Uom>
            <Quantity>15</Quantity>
            <installType>Optional</installType>
            <lineAmount>200</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>OP105</partNumber>
            <Uom>EA</Uom>
            <Quantity>23</Quantity>
            <installType>Optional</installType>
            <lineAmount>655</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>C100</partNumber>
            <Uom>EA</Uom>
            <Quantity>123</Quantity>
            <installType>Custom</installType>
            <lineAmount>12300</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>C1337</partNumber>
            <Uom>EA</Uom>
            <Quantity>357</Quantity>
            <installType>Custom</installType>
            <lineAmount>143</lineAmount>
         </PoLines>
      </PoLinesCollection>
   </PoHeaders>
   <PoHeaders>
      <poNumber>5678</poNumber>
      <storeNumber>52</storeNumber>
      <itemNumber>0005554433</itemNumber>
      <PoLinesCollection>
         <PoLines>
            <partNumber>I21</partNumber>
            <Quantity>35</Quantity>
            <installType>Basic</installType>
            <lineAmount>3000</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>OP134</partNumber>
            <Uom>EA</Uom>
            <Quantity>1500</Quantity>
            <installType>Optional</installType>
            <lineAmount>350000</lineAmount>
         </PoLines>
         <PoLines>
            <partNumber>C140</partNumber>
            <Uom>EA</Uom>
            <Quantity>13</Quantity>
            <installType>Custom</installType>
            <lineAmount>100</lineAmount>
         </PoLines>
      </PoLinesCollection>
   </PoHeaders>
</PoHeadersCollection>

我尝试使用for-each并在循环内尝试为其余的线类型应用模板,但它重复所有节点。

下面是我试图使用的XSLT,并且缺少如何在for循环中单独应用当前节点的模板 -

<xsl:stylesheet version="1.0">
  <xsl:template match="/">
    <PoHeadersCollection>
      <xsl:for-each select="/orderDetails/data/order">
        <ThdIconxPoHeaders>
          <poNumber>
            <xsl:value-of select="poNumber"/>
          </poNumber>
          <storeNumber>
            <xsl:value-of select="storeNumber"/>
          </storeNumber>
          <itemNumber>
            <xsl:value-of select="itemNumber"/>
          </itemNumber>
          <PoLinesCollection>
            <PoLines>
              <partNumber>
                <xsl:value-of select="mainLine/referenceNumber"/>
              </partNumber>
              <Uom>
                <xsl:value-of select="mainLine/duoiCode"/>
              </Uom>
              <Quantity>
                <xsl:value-of select="mainLine/basicInstallQuantity"/>
              </Quantity>
              <installType>
                <xsl:text disable-output-escaping="no">Basic</xsl:text>
              </installType>
              <lineAmount>
                <xsl:value-of select="mainLine/basicInstallCostAmount"/>
              </lineAmount>
            </PoLines>          
            <xsl:apply-templates select="//*[local-name()='optionalLine']"/>
            <xsl:apply-templates select="//*[local-name()='customLine']"/>
          </PoLinesCollection>
        </PoHeaders>
      </xsl:for-each>
    </PoHeadersCollection>
  </xsl:template>
  <xsl:template match="*[local-name()='optionalLine']">
    <PoLines>
      <partNumber>
        <xsl:value-of select="referenceNumber"/>
      </partNumber>
      <Uom>
        <xsl:value-of select="duoiCode"/>
      </Uom>
      <Quantity>
        <xsl:value-of select="orderQuantity"/>
      </Quantity>
      <installType>
        <xsl:text disable-output-escaping="no">Optional</xsl:text>
      </installType>
    </PoLines>
  </xsl:template>
  <xsl:template match="*[local-name()='customLine']">
    <PoLines>
      <partNumber>
        <xsl:value-of select="referenceNumber"/>
      </partNumber>
      <Uom>
        <xsl:value-of select="duoiCode"/>
      </Uom>
      <Quantity>
        <xsl:value-of select="orderQuantity"/>
      </Quantity>
      <installType>
        <xsl:text disable-output-escaping="no">Custom</xsl:text>
      </installType>
    </PoLines>
  </xsl:template>
</xsl:stylesheet>

请建议。

提前致谢, 集塔

1 个答案:

答案 0 :(得分:0)

您的问题是绝对路径,例如

<xsl:apply-templates select="//*[local-name()='optionalLine']"/>

每次都会从文档中的每个顺序中选择相应类型的所有行。相反,您需要使用 relative 路径而不使用前导斜杠

<xsl:apply-templates select="optionalLines/optionalLine"/>

只查找您当前正在查看的订单中的那些行。

就我个人而言,我会将整块大块分解成较小的模板,以捕捉不同类型线条之间的共性。

<xsl:template match="/">
  <PoHeadersCollection>
    <xsl:apply-templates select="orderDetails/data/order" />
  </PoHeadersCollection>
</xsl:template>

<xsl:template match="order">
  <PoHeaders>
    <xsl:copy-of select="poNumber | storeNumber | itemNumber" />
    <PoLinesCollection>
      <!-- process all the different types of line in one go -->
      <xsl:apply-templates select="mainLine
                    | optionalLines/optionalLine
                    | customLines/customLine" />
    </PoLinesCollection>
  </PoHeaders>
</xsl:template>

<xsl:template match="mainLine | optionalLine | customLine">
  <PoLines>
    <xsl:apply-templates select="referenceNumber"/>
    <xsl:apply-templates select="duoiCode"/><!-- won't exist for main line -->
    <xsl:apply-templates select="basicInstallQuantity | orderQuantity"/>
    <xsl:apply-templates select="." mode="lineType" />
    <xsl:apply-templates select="basicInstallCostAmount | orderRetailAmount"/>
  </PoLines>
</xsl:template>

<xsl:template match="referenceNumber">
  <partNumber><xsl:apply-templates/></partNumber>
</xsl:template>

<xsl:template match="duoiCode">
  <Uom><xsl:apply-templates/></Uom>
</xsl:template>

<!-- etc. for other elements -->

并使用特殊模板模式来处理installType

<xsl:template match="mainLine" mode="lineType">
  <installType>Basic</installType>
</xsl:template>

<xsl:template match="optionalLine" mode="lineType">
  <installType>Optional</installType>
</xsl:template>

<xsl:template match="customLine" mode="lineType">
  <installType>Custom</installType>
</xsl:template>