2011-03-18 79 views
2

我需要按照以下方式對XML示例進行排序:首先對所有ShippingPoint進行排序,然後根據第一個ShippingPoint和最後一個根據第一個ShippingPoint貨物。所以基本上我試圖根據它們應該開始的日期對所有的傳輸進行排序。對XML進行遞歸排序 - 只對內部節點進行排序

現在,我找到了一個使用XSL遞歸的解決方案,只是Cargos和ShippingPoints按預期排序 - 最外層的Transport節點沒有。我想知道我在這裏做錯了什麼。 MSXML(VS2008)和Saxon解析器都給了我完全相同的結果。

示例XML代碼:

<?xml version="1.0" encoding="utf-8"?> 
<Transports> 
    <Transport ID="1893"> 
     <Cargos> 
      <Cargo ID="1532" > 
       <ShippingPoints> 
        <ShippingPoint ID="1600" ArrivesOn="2011-04-07T12:00:00" /> 
        <ShippingPoint ID="1601" ArrivesOn="2011-04-08T12:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1532"> 
       <ShippingPoints> 
        <ShippingPoint ID="1601" ArrivesOn="2011-03-08T12:00:00" /> 
        <ShippingPoint ID="1600" ArrivesOn="2011-02-07T12:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 

    <Transport ID="1891" > 
     <Cargos> 
      <Cargo ID="1529" > 
       <ShippingPoints> 
        <ShippingPoint ID="1594" ArrivesOn="2011-04-14T12:00:00" /> 
        <ShippingPoint ID="1595" ArrivesOn="2011-04-04T13:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1530" > 
       <ShippingPoints> 
        <ShippingPoint ID="1597" ArrivesOn="2011-04-09T18:00:00" /> 
        <ShippingPoint ID="1596" ArrivesOn="2011-04-04T12:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 

    <Transport ID="1892"> 
     <Description/> 
     <Cargos> 
      <Cargo ID="1531" > 
       <ShippingPoints> 
        <ShippingPoint ID="1599" ArrivesOn="2011-04-06T18:00:00" /> 
        <ShippingPoint ID="1598" ArrivesOn="2011-04-05T12:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1531" > 
       <ShippingPoints> 
        <ShippingPoint ID="1599" ArrivesOn="2011-04-02T18:00:00" /> 
        <ShippingPoint ID="1598" ArrivesOn="2011-04-03T12:00:00" /> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 
</Transports> 

XSLT代碼:

<?xml version="1.0" encoding="UTF-8"?> 

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xsl:output method="xml" version="1.0" encoding="UTF-8" /> 

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

    <xsl:template match="ShippingPoints"> 
     <xsl:copy> 
      <xsl:apply-templates select="ShippingPoint"> 
       <xsl:sort select="@ArrivesOn" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Cargos"> 
     <xsl:copy> 
      <xsl:apply-templates select="Cargo"> 
       <xsl:sort select="ShippingPoints/ShippingPoint[1]/@ArrivesOn" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Transports"> 
     <xsl:copy> 
      <xsl:apply-templates select="Transport"> 
       <xsl:sort select="Cargos/Cargo[1]/ShippingPoints/ShippingPoint[1]/@ArrivesOn"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

回答

3

除非我不明白這一點,否則您正在尋找按最小@ArrivesOn後裔排序。最短的樣式表:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:copy-of select="@*"/> 
      <xsl:apply-templates select="node()"> 
       <xsl:sort select="min(.//@ArrivesOn/xs:dateTime(.))"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<Transports> 
    <Transport ID="1893"> 
     <Cargos> 
      <Cargo ID="1532"> 
       <ShippingPoints> 
        <ShippingPoint ID="1600" ArrivesOn="2011-02-07T12:00:00"/> 
        <ShippingPoint ID="1601" ArrivesOn="2011-03-08T12:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1532"> 
       <ShippingPoints> 
        <ShippingPoint ID="1600" ArrivesOn="2011-04-07T12:00:00"/> 
        <ShippingPoint ID="1601" ArrivesOn="2011-04-08T12:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 
    <Transport ID="1892"> 
     <Description/> 
     <Cargos> 
      <Cargo ID="1531"> 
       <ShippingPoints> 
        <ShippingPoint ID="1599" ArrivesOn="2011-04-02T18:00:00"/> 
        <ShippingPoint ID="1598" ArrivesOn="2011-04-03T12:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1531"> 
       <ShippingPoints> 
        <ShippingPoint ID="1598" ArrivesOn="2011-04-05T12:00:00"/> 
        <ShippingPoint ID="1599" ArrivesOn="2011-04-06T18:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 
    <Transport ID="1891"> 
     <Cargos> 
      <Cargo ID="1530"> 
       <ShippingPoints> 
        <ShippingPoint ID="1596" ArrivesOn="2011-04-04T12:00:00"/> 
        <ShippingPoint ID="1597" ArrivesOn="2011-04-09T18:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
      <Cargo ID="1529"> 
       <ShippingPoints> 
        <ShippingPoint ID="1595" ArrivesOn="2011-04-04T13:00:00"/> 
        <ShippingPoint ID="1594" ArrivesOn="2011-04-14T12:00:00"/> 
       </ShippingPoints> 
      </Cargo> 
     </Cargos> 
    </Transport> 
</Transports> 
+0

這樣做 - 簡單而乾淨。謝謝! – dawidw 2011-03-22 07:43:59

+0

@dawidw:不客氣。 – 2011-03-22 20:26:56

0

如果你想一步步轉變,那麼你應該使用模式和變量來存儲臨時結果,如下面的XSLT 2.0示例:

<?xml version="1.0" encoding="UTF-8"?> 

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

    <xsl:output method="xml" version="1.0" indent="yes" encoding="UTF-8" /> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/"> 
     <xsl:variable name="t1"> 
     <xsl:apply-templates mode="step1"/> 
     </xsl:variable> 
     <xsl:variable name="t2"> 
     <xsl:apply-templates select="$t1/node()" mode="step2"/> 
     </xsl:variable> 
     <xsl:apply-templates select="$t2/node()"/> 
    </xsl:template> 

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

    <xsl:template match="ShippingPoints" mode="step1"> 
     <xsl:copy> 
      <xsl:apply-templates select="ShippingPoint"> 
       <xsl:sort select="@ArrivesOn" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Cargos" mode="step2"> 
     <xsl:copy> 
      <xsl:apply-templates select="Cargo"> 
       <xsl:sort select="ShippingPoints/ShippingPoint[1]/@ArrivesOn" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Transports"> 
     <xsl:copy> 
      <xsl:apply-templates select="Transport"> 
       <xsl:sort select="Cargos/Cargo[1]/ShippingPoints/ShippingPoint[1]/@ArrivesOn"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

我認爲這是做你想用XSLT 2.0程序SSOR。

+0

感謝@馬丁。這也在這裏工作,但由於我不需要一步一步地進行轉換,所以我去了@alejandro建議的東西。 – dawidw 2011-03-22 07:45:46