2011-09-26 51 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()