2012-07-15 115 views
1

我熟悉XSLT的基礎知識,但是我遇到了一個奇怪的情況,我似乎無法弄清楚。我很抱歉這麼久,但我會很感激你能提供的任何幫助。使用XSLT添加屬性,然後使用該新屬性進行排序

我對由我無法控制的軟件產品生成的XML進行轉換。產品導出如下所示的數據:

<header> 
    <data> 
    </data> 
</header> 
<transaction> 
    <B1_PG1 ts='1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76'><data></data></B1_PG2> 
    <B2_PG1 ts='1139977698718.77'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78'><data></data></B2_PG2> 
    <B2_PG1 ts='1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81'><data></data></B3_PG1> 
</transaction> 

其中軟件產品按照接收它們的順序導出數據頁面。我需要將這些頁面按自定義順序排序,以便處理到另一個系統中。所以,我創建了一個查找的文件,看起來像這樣來定義我的自定義排序順序:

(PageSequences.xml)

<pages> 
    <page id="B2_PG1" sequence="1000" /> 
    <page id="B2_PG2" sequence="1010" /> 
    <page id="B3_PG1" sequence="2000" /> 
    <page id="B1_PG1" sequence="3000" /> 
    <page id="B1_PG2" sequence="3010" /> 
</pages> 

我再根據元素名稱查找該序列,串聯,與時間戳,並使用以下XSLT注入的屬性到元素:

<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:variable name='page-seqs' select='document("PageSequences.xml")/pages/page'/> 

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

    <xsl:template match="transaction"> 
     <transaction> 

      <xsl:for-each select="child::node()"> 
       <xsl:variable name='localname' select='local-name()'/> 
       <xsl:copy> 
        <xsl:attribute name="sequence"> 
         <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
        </xsl:attribute> 
        <xsl:apply-templates select="@*|node()"> 
         <xsl:sort select="@sequence" /> 
        </xsl:apply-templates> 
       </xsl:copy> 
      </xsl:for-each> 
     </transaction> 
     </xsl:template> 

</xsl:stylesheet> 

我遇到的問題是,標籤似乎並不奏效。我希望以下內容:

<transaction> 
    <B2_PG1 ts='1139977698718.77' sequence='1000-1139977698718.77'><data></data></B2_PG1> 
    <B2_PG1 ts='1139977698718.79' sequence='1000-1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78' sequence='1010-1139977698718.78'><data></data></B2_PG2> 
    <B2_PG2 ts='1139977698718.80' sequence='1010-1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81' sequence='2000-1139977698718.81'><data></data></B3_PG1> 
    <B1_PG1 ts='1139977698718.75' sequence='3000-1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76' sequence='3010-1139977698718.76'><data></data></B1_PG2> 
</transaction> 

,但我發現:

<transaction> 
    <B1_PG1 ts='1139977698718.75' sequence='3000-1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76' sequence='3010-1139977698718.76'><data></data></B1_PG2> 
    <B2_PG1 ts='1139977698718.77' sequence='1000-1139977698718.77'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78' sequence='1010-1139977698718.78'><data></data></B2_PG2> 
    <B2_PG1 ts='1139977698718.79' sequence='1000-1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.80' sequence='1010-1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81' sequence='2000-1139977698718.81'><data></data></B3_PG1> 
</transaction> 

另外,請讓我知道,如果你認爲我在錯誤的方式接近這一點。我試圖避免使用java/c#/ perl/etc ...來保持轉換儘可能便攜。出於性能原因,我也想避免執行兩次轉換。謝謝!

回答

0

你的問題是代碼

<xsl:copy> 
    <xsl:attribute name="sequence"> 
     <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
    </xsl:attribute> 
    <xsl:apply-templates select="@*|node()"> 
     <xsl:sort select="@sequence" /> 
    </xsl:apply-templates> 
</xsl:copy> 

尤其是應用模板該塊內。首先,在此階段,您已經複製並輸出「B-PG」元素,並且所有應用模板正在處理其子節點。其次,排序只適用於輸入文檔,而不是任何額外的屬性添加到輸出文檔。

然後你可以做什麼,把你把事務子節點複製到一個變量中的結果,然後用一個排序遍歷該變量。這將是同一個XSLT文檔中的「雙向轉換」。但是,在這種情況下,這是沒有必要的。您只需簡單地匹配所有事務子節點,並在排序

<xsl:sort select="$page-seqs[@id=local-name(current())]/@sequence" /> 

這裏指定序列號的查詢是完整的XSLT

<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:variable name="page-seqs" select="document('C:\lookup.xml')/pages/page"/> 

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

    <xsl:template match="transaction"> 
     <transaction> 
     <xsl:apply-templates select="child::node()"> 
      <xsl:sort select="$page-seqs[@id=local-name(current())]/@sequence"/> 
     </xsl:apply-templates> 
     </transaction> 
    </xsl:template> 
</xsl:stylesheet> 

當適用於您的樣本文件(減去元件,因爲目前的XML樣品沒有很好地形成),下面是輸出

<transaction> 
    <B2_PG1 ts="1139977698718.77"> 
     <data/> 
    </B2_PG1> 
    <B2_PG1 ts="1139977698718.79"> 
     <data/> 
    </B2_PG1> 
    <B2_PG2 ts="1139977698718.78"> 
     <data/> 
    </B2_PG2> 
    <B2_PG2 ts="1139977698718.80"> 
     <data/> 
    </B2_PG2> 
    <B3_PG1 ts="1139977698718.81"> 
     <data/> 
    </B3_PG1> 
    <B1_PG1 ts="1139977698718.75"> 
     <data/> 
    </B1_PG1> 
    <B1_PG2 ts="1139977698718.76"> 
     <data/> 
    </B1_PG2> 
</transaction> 

待辦事項噸最好使用apply-templates來替換每一個,這就是我在這裏所做的。

+0

這是完美的蒂姆,非常感謝。它允許我執行排序而不需要添加屬性所需的傳遞。它將允許對任何元素進行自定義排序。 – 2012-07-16 02:13:26

1

您創建的屬性存在於要放置在結果樹中的新構建的元素上,但它不存在於要排序的源樹中的元素上。

另一個問題是,你沒有排序交易元素的孩子,但它的孫子。

我懷疑你想要的東西是這樣的:

  <xsl:for-each select="child::node()"> 
       <xsl:sort select="concat($page-seqs[@id=local-name(current())]/@sequence, '-', @ts)"/> 
       <xsl:variable name='localname' select='local-name()'/> 
       <xsl:copy> 
        <xsl:attribute name="sequence"> 
         <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
        </xsl:attribute> 
        <xsl:apply-templates select="@*|node()"/> 
       </xsl:copy> 
      </xsl:for-each> 

,以避免重複計算(一旦在xsl:排序,一旦產生輸出屬性)的唯一方法是做兩遍,一個添加屬性,下一個排序。這種做法的方式在XSLT 1.0和2.0之間有所不同,並且您沒有說明您正在使用哪種方法。兩種方法是相當可行的,但在你的情況下,我懷疑重複計算的單次傳球效率更高(儘管你必須測量兩者以找出答案)。

+0

邁克爾,我很欣賞你試圖讓我的平均XSLT理念工作不足,這也可以做到。 – 2012-07-16 02:15:05