用于转换xml的XSLT样式表

时间:2012-05-11 20:25:35

标签: xslt

我正在尝试创建一个xslt样式表来转换xml。我研究了muenchian方法,但我不熟悉它是如何工作的。我遇到了困难,因为每个ManifestNo都可以有任意数量的SequenceNo。我试图将源xml中的平面订单分组到目标xml中具有嵌套Stop详细信息的订单。

<Orders>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>3524771-01</CustomerOrderNo>
    <Weight>180</Weight>
  </Order>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>3524771-02</CustomerOrderNo>
    <Weight>250</Weight>
  </Order>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>3524728-01</CustomerOrderNo>
    <Weight>25</Weight>
    </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>5464565-01</CustomerOrderNo>
    <Weight>150</Weight>
  </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>5874565-02</CustomerOrderNo>
    <Weight>125</Weight>
  </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>3524888-01</CustomerOrderNo>
    <Weight>95</Weight>
  </Order>
</Orders>

<Orders>
     <Order>
        <ManifestNo>283749</ManifestNo>
        <Warehouse>35</Warehouse> 
        <Stop>
            <SequenceNo>1</SequenceNo>
            <Freight>
                <CustomerOrderNo>3524771-01</CustomerOrderNo>
                <Weight>180</Weight>
            </Freight>
            <Freight>
                <CustomerOrderNo>3524771-02</CustomerOrderNo>
                <Weight>250</Weight>
            </Freight>
        </Stop>
        <Stop>
            <SequenceNo>2</SequenceNo>
            <Freight>
                <CustomerOrderNo>3524728-01</CustomerOrderNo>
                <Weight>25</Weight>
            </Freight>
            <Freight>
                <CustomerOrderNo>3524771-02</CustomerOrderNo>
                <Weight>250</Weight>
            </Freight>
        </Stop>
         </Order>
        <Order>
        <ManifestNo>283750</ManifestNo>
        <Warehouse>50</Warehouse> 
        <Stop>
            <SequenceNo>1</SequenceNo>
            <Freight>
                <CustomerOrderNo>5464565-01</CustomerOrderNo>
                <Weight>150</Weight>
            </Freight>
        </Stop>
        <Stop>
            <SequenceNo>2</SequenceNo>
            <Freight>
                <CustomerOrderNo>5874565-02</CustomerOrderNo>
                <Weight>125</Weight>
            </Freight>
            <Freight>
                <CustomerOrderNo>3524888-0</CustomerOrderNo>
                <Weight>95</Weight>
            </Freight>
        </Stop>
         </Order>
    </Orders>

1 个答案:

答案 0 :(得分:1)

<强>予。这个XSLT 1.0转换:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:key name="kOrderByNum" match="Order"
      use="ManifestNo"/>

     <xsl:key name="kSeqInOrder" match="SequenceNo"
      use="concat(../ManifestNo, '+', .)"/>

     <xsl:key name="kSeqByOrderNo" match="SequenceNo"
      use="../ManifestNo"/>

     <xsl:template match="Order"/>
     <xsl:template match="SequenceNo"/>

   <xsl:template match="/*">
     <Orders>
      <xsl:apply-templates/>
     </Orders>
     </xsl:template>

     <xsl:template match=
      "Order
         [generate-id()
         =
          generate-id(key('kOrderByNum', ManifestNo)[1])
          ]">
      <Order>
        <xsl:copy-of select="ManifestNo|Warehouse"/>

        <xsl:apply-templates select=
        "key('kSeqByOrderNo', ManifestNo)
          [generate-id()
          =
           generate-id(key('kSeqInOrder',
                           concat(../ManifestNo, '+', .)
                           )[1]
                      )
           ]
        "/>
      </Order>
     </xsl:template>

     <xsl:template match="SequenceNo[true()]">
      <Stop>
        <xsl:copy-of select="."/>
        <xsl:apply-templates mode="inGroup" select=
        "key('kSeqInOrder',
              concat(../ManifestNo, '+', .))"/>
      </Stop>
     </xsl:template>

     <xsl:template match="SequenceNo" mode="inGroup">
      <Freight>
        <xsl:copy-of select="../CustomerOrderNo|../Weight"/>
      </Freight>
     </xsl:template>
   </xsl:stylesheet>

应用于提供的XML文档时:

<Orders>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>3524771-01</CustomerOrderNo>
    <Weight>180</Weight>
  </Order>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>3524771-02</CustomerOrderNo>
    <Weight>250</Weight>
  </Order>
  <Order>
    <ManifestNo>283749</ManifestNo>
    <Warehouse>35</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>3524728-01</CustomerOrderNo>
    <Weight>25</Weight>
    </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>1</SequenceNo>
    <CustomerOrderNo>5464565-01</CustomerOrderNo>
    <Weight>150</Weight>
  </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>5874565-02</CustomerOrderNo>
    <Weight>125</Weight>
  </Order>
  <Order>
    <ManifestNo>283750</ManifestNo>
    <Warehouse>50</Warehouse>
    <SequenceNo>2</SequenceNo>
    <CustomerOrderNo>3524888-01</CustomerOrderNo>
    <Weight>95</Weight>
  </Order>
</Orders>

会产生想要的正确结果:

<Orders>
   <Order>
      <ManifestNo>283749</ManifestNo>
      <Warehouse>35</Warehouse>
      <Stop>
         <SequenceNo>1</SequenceNo>
         <Freight>
            <CustomerOrderNo>3524771-01</CustomerOrderNo>
            <Weight>180</Weight>
         </Freight>
         <Freight>
            <CustomerOrderNo>3524771-02</CustomerOrderNo>
            <Weight>250</Weight>
         </Freight>
      </Stop>
      <Stop>
         <SequenceNo>2</SequenceNo>
         <Freight>
            <CustomerOrderNo>3524728-01</CustomerOrderNo>
            <Weight>25</Weight>
         </Freight>
      </Stop>
   </Order>
   <Order>
      <ManifestNo>283750</ManifestNo>
      <Warehouse>50</Warehouse>
      <Stop>
         <SequenceNo>1</SequenceNo>
         <Freight>
            <CustomerOrderNo>5464565-01</CustomerOrderNo>
            <Weight>150</Weight>
         </Freight>
      </Stop>
      <Stop>
         <SequenceNo>2</SequenceNo>
         <Freight>
            <CustomerOrderNo>5874565-02</CustomerOrderNo>
            <Weight>125</Weight>
         </Freight>
         <Freight>
            <CustomerOrderNo>3524888-01</CustomerOrderNo>
            <Weight>95</Weight>
         </Freight>
      </Stop>
   </Order>
</Orders>

<强> II。 XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kSeqByOrderNo" match="SequenceNo"
      use="../ManifestNo"/>

 <xsl:template match="/*">
   <Orders>
     <xsl:for-each-group select="Order" group-by="ManifestNo">
      <Order>
        <xsl:copy-of select="ManifestNo|Warehouse"/>

        <xsl:for-each-group select="key('kSeqByOrderNo', ManifestNo)"
         group-by=".">
         <xsl:copy-of select="."/>
         <Stop>
          <xsl:apply-templates select="current-group()"/>
         </Stop>
        </xsl:for-each-group>
      </Order>
     </xsl:for-each-group>
   </Orders>
 </xsl:template>

 <xsl:template match="SequenceNo">
   <Freight>
     <xsl:copy-of select="../CustomerOrderNo|../Weight"/>
   </Freight>
 </xsl:template>
</xsl:stylesheet>