Xml XSLT将项目移动到同一级别的其他标记中

Xml XSLT将项目移动到同一级别的其他标记中,xml,xslt,xpath,Xml,Xslt,Xpath,xslt有一个问题: 这是输入文件: <root> <header/> <item/> … other n-1 <item/> <header/> <item/> … other m-1 <item/> </root> …其他n-1 …其他m-1 因此,标题和项位于同一级别(/root)。 必须将其转换为以下格式: <root2> &l

xslt有一个问题:

这是输入文件:

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

…其他n-1
…其他m-1
因此,标题和项位于同一级别(/root)。 必须将其转换为以下格式:

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

…//第一个n项向上
…//上一个m项
因此,基本上,第一个n项必须在第一个标题中移动,而第二组项必须在第二个标题中移动。知道怎么得到这个吗

谢谢

随机化样本XML:

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

1.
2.
3.
5.
6.
7.
使用分组的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.
2.
3.
5.
6.
7.

这是一个更简单、更有效的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>
<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>
<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>
将此转换应用于同一XML文档(如上)时,会产生相同的正确结果

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

1.
2.
3.
5.
6.
7.

解释:对每个组使用
xsl:。可能会有一个比当前接受的解决方案更简单、更高效的解决方案。还添加了一个XSLT 2.0解决方案。为两个解决方案中的每一个都添加了说明。