2010-09-30 84 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. 使用模式以多种方式处理相同的节点。