2011-07-22 50 views
3

我有包含一些文檔的xml:陣地分組使用XSLT

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

H =的文件和L =線路項頭。在這個例子中,具有兩個H,這意味着兩個文件,其編號爲doc1和doc2。 doc1有三個訂單項,而doc2有一個訂單項。

如何將數據使用XSLT版本1得到這個結果轉換:

<documents> 
    <document> 
     <header> 
      <number>doc1</number> 
     </header> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
    </document> 
    <document> 
     <header> 
      <number>doc2</number> 
     </header> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
    </document> 
</documents> 
+1

那麼 - 你有什麼嘗試過自己?你在哪裏遇到麻煩? –

+0

好問題,+1。使用密鑰查看我的答案,獲得完整,簡單易用的XSLT 1.0解決方案。 :) –

+0

還使用'添加了更短的XSLT 2.0解決方案「 –

回答

5

這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="kFollowing" 
    match="line[starts-with(field,'L:')]" 
    use="generate-id(preceding-sibling::line 
         [starts-with(field,'H:')] 
         [1] 
        )"/> 

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

<xsl:template match="line[starts-with(field,'H:')]"> 
    <document> 
    <header> 
    <number><xsl:value-of select="substring-after(field,'H:')"/></number> 
    <line-item> 
    <xsl:apply-templates mode="inGroup" select= 
     "key('kFollowing', generate-id())"/> 
    </line-item> 
    </header> 
    </document> 
</xsl:template> 

<xsl:template match="line" mode="inGroup"> 
    <line-number> 
    <xsl:value-of select="substring-after(field,'L:')"/> 
    </line-number> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

產生想要的,正確的結果

<documents> 
    <document> 
     <header> 
     <number>doc1</number> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
     </header> 
    </document> 
    <document> 
     <header> 
     <number>doc2</number> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
     </header> 
    </document> 
</documents> 

說明:使用鍵方便地指定和選擇的相鄰「線」之後的「報頭」的完整組。

+0

感謝您的回答。 – Petras

+0

@Petras:不客氣 - 您也可能對我的第二個答案感興趣,它提供了一個更短的XSLT 2.0解決方案。 –

3

這裏也是一個XSLT 2.0溶液,使用<xsl:for-each-group starting-with="...">

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

<xsl:template match="/*"> 
    <documents> 
     <xsl:for-each-group select="*" 
      group-starting-with="line[starts-with(field,'H:')]"> 
      <document> 
      <header> 
      <number><xsl:value-of select="substring-after(field,'H:')"/></number> 
      <line-item> 
      <xsl:apply-templates select="current-group()[position() >1]"/> 
      </line-item> 
      </header> 
      </document> 
     </xsl:for-each-group> 
    </documents> 
</xsl:template> 

<xsl:template match="line"> 
    <line-number> 
    <xsl:value-of select="substring-after(field,'L:')"/> 
    </line-number> 
</xsl:template> 
</xsl:stylesheet> 

當施加到所提供的XML文檔

<document> 
    <line id="0"> 
     <field id="0"><![CDATA[H:doc1]]></field> 
    </line> 
    <line id="1"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
    <line id="2"> 
     <field id="0"><![CDATA[L:2]]></field> 
    </line> 
    <line id="3"> 
     <field id="0"><![CDATA[L:3]]></field> 
    </line> 
    <line id="4"> 
     <field id="0"><![CDATA[H:doc2]]></field> 
    </line> 
    <line id="5"> 
     <field id="0"><![CDATA[L:1]]></field> 
    </line> 
</document> 

有用,正確的結果產生

<documents> 
    <document> 
     <header> 
     <number>doc1</number> 
     <line-item> 
      <line-number>1</line-number> 
      <line-number>2</line-number> 
      <line-number>3</line-number> 
     </line-item> 
     </header> 
    </document> 
    <document> 
     <header> 
     <number>doc2</number> 
     <line-item> 
      <line-number>1</line-number> 
     </line-item> 
     </header> 
    </document> 
</documents> 

說明<xsl:for-each-group>,其group-starting-with屬性,該current-group()功能。