XSLT在同一级别的其他标记内移动项目

时间:2011-09-26 14:32:19

标签: xml xslt xpath

我对xslt:

有这个问题

这是输入文件:

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

所以标题和项目处于同一级别(/ root)。 它必须转换为:

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

所以基本上第一个n项必须在第一个标题中移动,而第二个项必须在第二个标题中移动。知道如何获得这个吗?

由于

随机化

2 个答案:

答案 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>

答案 1 :(得分: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元素都与此generate-id()的{​​{1}}匹配。

<强> II。 XSLT 2.0解决方案:

header

将此转换应用于同一XML文档(上图)时,会生成相同的正确结果

<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>

解释:使用<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-adjacent