2010-09-30 107 views
1

我需要改造以下重複圖案基團的非嵌套的XML結構以XML樹結構

<root> 
    <bar>bar 1</bar> 
    <baz>baz 1</baz> 
    <qux>qux 1</qux> 
    <bar>bar 2</bar> 
    <baz>baz 2</baz> 
    <qux>qux 2</qux> 
</root> 

向該;

<root> 
    <foo> 
     <bar>bar 1</bar> 
     <baz>baz 1</baz> 
     <qux>qux 1</qux> 
    </foo> 
    <foo> 
     <bar>bar 2</bar> 
     <baz>baz 2</baz> 
     <qux>qux 2</qux> 
    </foo> 
</root> 

但是不想使用循環解決方案。

+0

好問題(+1)。看到我的答案是一個有效的解決方案,同時它是通用的,並且沒有任何元素名稱硬編碼。 :) – 2010-09-30 15:31:01

回答

1

許多很多解決方案。這一次使用細粒度遍歷:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()|@*" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()[1]|@*"/> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="bar"> 
     <foo> 
      <xsl:call-template name="identity"/> 
     </foo> 
     <xsl:apply-templates select="following-sibling::bar[1]"/> 
    </xsl:template> 
    <xsl:template match="qux"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()[1]|@*"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<root> 
    <foo> 
     <bar>bar 1</bar> 
     <baz>baz 1</baz> 
     <qux>qux 1</qux> 
    </foo> 
    <foo> 
     <bar>bar 2</bar> 
     <baz>baz 2</baz> 
     <qux>qux 2</qux> 
    </foo> 
</root> 

其他的解決方案:用的按鍵風格。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kElementByPrecedingBar" match="root/*[not(self::bar)]" 
        use="generate-id(preceding-sibling::bar[1])"/> 
    <xsl:template match="node()|@*" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="bar" mode="wrap"> 
     <foo> 
      <xsl:apply-templates select=".|key('kElementByPrecedingBar', 
               generate-id())"/> 
     </foo> 
    </xsl:template> 
    <xsl:template match="root"> 
     <xsl:copy> 
      <xsl:apply-templates select="bar" mode="wrap"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
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="*[not(name()=name(/*/*[1]))]" 
    use="generate-id(preceding-sibling::*[name()=name(/*/*[1])][1])"/> 

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

<xsl:template match="/*/*"/> 

<xsl:template match="/*/*[name()=name(/*/*[1])]"> 
    <foo> 
    <xsl:apply-templates select=".|key('kFollowing', generate-id())" mode="copy"/> 
    </foo> 
</xsl:template> 

<xsl:template match="*" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<root> 
    <bar>bar 1</bar> 
    <baz>baz 1</baz> 
    <qux>qux 1</qux> 
    <bar>bar 2</bar> 
    <baz>baz 2</baz> 
    <qux>qux 2</qux> 
</root> 

產生想要的,正確的結果

<root> 
    <foo> 
     <bar>bar 1</bar> 
     <baz>baz 1</baz> 
     <qux>qux 1</qux> 
    </foo> 
    <foo> 
     <bar>bar 2</bar> 
     <baz>baz 2</baz> 
     <qux>qux 2</qux> 
    </foo> 
</root> 

請注意

  1. 改造並不需要知道和硬編碼的元素名稱 - 它只是使用一個事實,即元素名稱的順序重複。

  2. 使用密鑰查找組的所有成員。

  3. 使用模式以多種方式處理相同的節點。