XSLT用于展平特定的XML节点

时间:2011-10-13 20:21:59

标签: xml xslt

我收到的格式如下所示。我正在编写一些代码来转换XML,使得只有特定的节点才会被淘汰。

<TransactionRequest>
  <OrderRequests>
    <OrderRequest>
      <ReferenceNumber>1234567</ReferenceNumber>
      <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
      <IsRush>true</IsRush>
      <ShippingAddress>
        <Name>Tom Hanks</Name>
        <Address1>1123 Canada Way</Address1>
        <City>Burnaby</City>
        <Province>BC</Province>
        <PostalCode>V3B13B</PostalCode>
        <HomePhone>6048871121</HomePhone>
        <BusinessPhone>6041232342</BusinessPhone>
      </ShippingAddress>
      <ProgramType>C2</ProgramType>
      <Comments>Deliver to the receptionist</Comments>
      <Items>
        <Item>
          <Sku>UN10004</Sku>
          <Quantity>2</Quantity>
        </Item>
        <Item>
          <Sku>UN980011</Sku>
          <Quantity>1</Quantity>
        </Item>
      </Items>
    </OrderRequest>
  </OrderRequests>
  <TraceRequests>
    <TraceRequest>
      <ReferenceNumber>23432345</ReferenceNumber>
      <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
      <OriginalReferenceNumber>1234567</OriginalReferenceNumber>
      <Comments>Trace Items</Comments>
      <TraceItems>
        <TraceItem>
          <Sku>UN10004</Sku>
          <Quantity>2</Quantity>
          <ShipmentNumber>CM88888990</ShipmentNumber>
        </TraceItem>
        <TraceItem>
          <Sku>UN980011</Sku>
          <ProductCode>AA0091</ProductCode>
          <Quantity>1</Quantity>
          <ShipmentNumber>DDP123123123</ShipmentNumber>
        </TraceItem>
      </TraceItems>
    </TraceRequest>
  </TraceRequests>
</TransactionRequest>

我希望结果看起来像后面的XML。区别在于此XML,TraceRequest节点将按每个Items / Item节点拆分一个,方法是为每个Items / Item复制一次父信息。

<?xml version="1.0"?>
<TransactionRequest>
  <OrderRequests>
    <OrderRequest>
      <ReferenceNumber>1234567</ReferenceNumber>
      <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
      <IsRush>true</IsRush>
      <ShippingAddress>
        <Name>Tom Hanks</Name>
        <Address1>1123 Canada Way</Address1>
        <City>Burnaby</City>
        <Province>BC</Province>
        <PostalCode>V3B13B</PostalCode>
        <HomePhone>6048871121</HomePhone>
        <BusinessPhone>6041232342</BusinessPhone>
      </ShippingAddress>
      <ProgramType>C2</ProgramType>
      <Comments>Deliver to the receptionist</Comments>
      <Items>
        <Item>
          <Sku>UN10004</Sku>
          <Quantity>2</Quantity>
        </Item>
        <Item>
          <Sku>UN980011</Sku>
          <Quantity>1</Quantity>
        </Item>
      </Items>
    </OrderRequest>
  </OrderRequests>
  <TraceRequests>
    <TraceRequest>
      <ReferenceNumber>23432345</ReferenceNumber>
      <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
      <OriginalReferenceNumber>1234567</OriginalReferenceNumber>
      <Comments>Trace Items</Comments>
      <Sku>UN10004</Sku>
      <Quantity>2</Quantity>
      <ShipmentNumber>CM88888990</ShipmentNumber>
    </TraceRequest>
    <TraceRequest>
      <ReferenceNumber>23432345</ReferenceNumber>
      <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
      <OriginalReferenceNumber>1234567</OriginalReferenceNumber>
      <Comments>Trace Items</Comments>
      <Sku>UN980011</Sku>
      <ProductCode>AA0091</ProductCode>
      <Quantity>1</Quantity>
      <ShipmentNumber>DDP123123123</ShipmentNumber>
    </TraceRequest>
  </TraceRequests>
</TransactionRequest>

我似乎无法生成XSLT来仅展平TraceRequest元素的特定子节点元素。

2 个答案:

答案 0 :(得分:2)

您可以通过使用特殊情况的额外模板覆盖标准身份转换来实现此目的。

首先,当您匹配 TraceRequest 节点时,您希望直接跳到匹配的 TraceItem 节点,您将在其中进行复制。在这种情况下,当前的 TraceRequest 节点可以作为参数传入,以便以后复制其chidlren。

<xsl:template match="TraceRequest">
   <xsl:apply-templates select="TraceItems/TraceItem">
      <xsl:with-param name="TraceRequestNode" select="."/>
   </xsl:apply-templates>
</xsl:template>

然后,当匹配 TraceItem 时,您只需复制通过参数传入的 TraceRequest 的子项(不包括 TraceItems 节点) ,以及您当前所在的 TraceItem 节点的子节点。

<xsl:template match="TraceItem">
   <xsl:param name="TraceRequestNode"/>
   <TraceRequest>
      <xsl:apply-templates select="$TraceRequestNode/*[not(self::TraceItems)]"/>
      <xsl:apply-templates select="@*|node()"/>
   </TraceRequest>
</xsl:template>

所以,给定完整的XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes" />

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="TraceRequest">
      <xsl:apply-templates select="TraceItems/TraceItem">
         <xsl:with-param name="TraceRequestNode" select="."/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="TraceItem">
      <xsl:param name="TraceRequestNode"/>
      <TraceRequest>
         <xsl:apply-templates select="$TraceRequestNode/*[not(self::TraceItems)]"/>
         <xsl:apply-templates select="@*|node()"/>
      </TraceRequest>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出如下:

<TransactionRequest>
   <OrderRequests>
      <OrderRequest>
         <ReferenceNumber>1234567</ReferenceNumber>
         <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
         <IsRush>true</IsRush>
         <ShippingAddress>
            <Name>Tom Hanks</Name>
            <Address1>1123 Canada Way</Address1>
            <City>Burnaby</City>
            <Province>BC</Province>
            <PostalCode>V3B13B</PostalCode>
            <HomePhone>6048871121</HomePhone>
            <BusinessPhone>6041232342</BusinessPhone>
         </ShippingAddress>
         <ProgramType>C2</ProgramType>
         <Comments>Deliver to the receptionist</Comments>
         <Items>
            <Item>
               <Sku>UN10004</Sku>
               <Quantity>2</Quantity>
            </Item>
            <Item>
               <Sku>UN980011</Sku>
               <Quantity>1</Quantity>
            </Item>
         </Items>
      </OrderRequest>
   </OrderRequests>
   <TraceRequests>
      <TraceRequest>
         <ReferenceNumber>23432345</ReferenceNumber>
         <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
         <OriginalReferenceNumber>1234567</OriginalReferenceNumber>
         <Comments>Trace Items</Comments>
         <Sku>UN10004</Sku>
         <Quantity>2</Quantity>
         <ShipmentNumber>CM88888990</ShipmentNumber>
      </TraceRequest>
      <TraceRequest>
         <ReferenceNumber>23432345</ReferenceNumber>
         <TransactionTime>2010-11-16T00:00:00-08:00</TransactionTime>
         <OriginalReferenceNumber>1234567</OriginalReferenceNumber>
         <Comments>Trace Items</Comments>
         <Sku>UN980011</Sku>
         <ProductCode>AA0091</ProductCode>
         <Quantity>1</Quantity>
         <ShipmentNumber>DDP123123123</ShipmentNumber>
      </TraceRequest>
   </TraceRequests>
</TransactionRequest>

答案 1 :(得分:0)

好的,我想我在下面运行XSLT回答了我自己的问题:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="TransactionRequest">
    <TransactionRequest>
      <xsl:copy-of select="OrderRequests"/>
      <TraceRequests>
        <xsl:for-each select="TraceRequests/TraceRequest/TraceItems/TraceItem">
          <TraceRequest>
            <xsl:copy-of select="../../ReferenceNumber"/>
            <xsl:copy-of select="../../TransactionTime"/>
            <xsl:copy-of select="../../OriginalReferenceNumber"/>
            <xsl:copy-of select="../../Comments"/>

            <xsl:copy-of select="Sku"/>
            <xsl:copy-of select="Quantity"/>
            <xsl:copy-of select="ShipmentNumber"/>
            <xsl:copy-of select="ProductCode"/>
            <xsl:copy-of select="DropShipPoNumber"/>
          </TraceRequest>
        </xsl:for-each>
      </TraceRequests>
   </TransactionRequest>
  </xsl:template>
</xsl:stylesheet>