2011-09-26 25 views
3

我有這個問題對XSLT:XSLT在同一水平移動其他標記內的物品

這是輸入文件:

<root> 
    <header/> 
    <item/> 
    … other n-1 <item/> 
    <header/> 
    <item/> 
    … other m-1 <item/> 
    </root> 

SO報頭和項目在同一水平(/根) 。 它必須在東西被轉換象:

<root2> 
    <header2> 
    <item2/> 
    …<item2/> // the first n-items up 
    </header2> 
    <header2> 
    <item2/> 
    …<item2/> // the last m-items up 
    </header2> 
</root2> 

所以基本上在第一n項必須在第一報頭中移動,同時第二項目組必須在第二報頭被移動。任何想法如何得到這個?

感謝

隨機化

+0

好問題,+1。比目前接受的解決方案更簡單和更有效的解決方案是可能的。 –

+0

還添加了XSLT 2.0解決方案。 –

+0

爲兩種解決方案中的每一種添加了解釋。 –

回答

1

示例XML:

<root> 
    <header/> 
    <item>1</item> 
    <item>2</item> 
    <item>3</item> 
    <header/> 
    <item>5</item> 
    <item>6</item> 
    <item>7</item> 
</root> 

XSLT使用分組:

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

    <xsl:key name="k" match="item" use="count(preceding-sibling::header)"/> 

    <xsl:template match="/"> 
     <root2> 
      <xsl:apply-templates select="root/item[generate-id(.) = generate-id(key('k', count(preceding-sibling::header)))]" mode="a"/> 
     </root2> 
    </xsl:template> 

    <xsl:template match="item" mode="a"> 
     <header2> 
      <xsl:apply-templates select="key('k', count(preceding-sibling::header))"/> 
     </header2> 
    </xsl:template> 

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

</xsl:stylesheet> 

或簡單的特定XSLT:

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

    <xsl:template match="/"> 
     <root2> 
      <header2> 
       <xsl:apply-templates select="root/item[count(preceding-sibling::header) = 1]"/> 
      </header2> 
      <header2> 
       <xsl:apply-templates select="root/item[count(preceding-sibling::header) = 2]"/> 
      </header2> 
     </root2> 
    </xsl:template> 

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

</xsl:stylesheet> 

兩者產生相同的輸出:

<root2> 
    <header2> 
    <item>1</item> 
    <item>2</item> 
    <item>3</item> 
    </header2> 
    <header2> 
    <item>5</item> 
    <item>6</item> 
    <item>7</item> 
    </header2> 
</root2> 
+0

你是男人! :)謝謝 – Randomize

+0

@Randomize,不客氣! –

0

這是一個更簡單的更有效的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:key name="kFollowing" match="item" 
    use="generate-id(preceding-sibling::header[1])"/> 

<xsl:template match="/*"> 
    <root> 
    <xsl:apply-templates select="header"/> 
    </root> 
</xsl:template> 

<xsl:template match="header"> 
    <heather2> 
    <xsl:copy-of select="key('kFollowing', generate-id())"/> 
    </heather2> 
</xsl:template> 
</xsl:stylesheet> 

當施加於以下這種轉變XML文檔

<root> 
    <header/> 
    <item>1</item> 
    <item>2</item> 
    <item>3</item> 
    <header/> 
    <item>5</item> 
    <item>6</item> 
    <item>7</item> 
</root> 

有用,正確的結果產生

<root> 
    <heather2> 
     <item>1</item> 
     <item>2</item> 
     <item>3</item> 
    </heather2> 
    <heather2> 
     <item>5</item> 
     <item>6</item> 
     <item>7</item> 
    </heather2> 
</root> 

說明

的關鍵在於以這樣的方式,對於一個header任何緊以下item元件是由匹配的定義的headergenerate-id()

二, 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:template match="/*"> 
    <root> 
    <xsl:for-each-group select="item" 
     group-adjacent= 
     "generate-id(preceding-sibling::header[1])"> 
    <header2> 
     <xsl:sequence select="current-group()"/> 
    </header2> 
    </xsl:for-each-group> 
    </root> 
</xsl:template> 
</xsl:stylesheet> 

當該變換是在相同的XML文檔(上文)中,相同的正確的結果產生施加:

<root> 
    <header2> 
     <item>1</item> 
     <item>2</item> 
     <item>3</item> 
    </header2> 
    <header2> 
     <item>5</item> 
     <item>6</item> 
     <item>7</item> 
    </header2> 
</root> 

說明:使用的xsl:for-each-groupgroup-adjacentcurrent-group()