在XSLT中对节点进行分组

时间:2014-04-10 10:27:44

标签: xml xslt

我有一个XML文件结构如下:

<root>
 <a>...</a>
 <b>...</b>
 <a>...</a>
 <a>...</a>
 <comment>...</comment>
 <a>...</a>
 <b>...</b>
 <comment>...</comment>
 <a>...</a>
 <b>...</b>
</root>

我想使用XSLT对其进行转换,以便将ab的每个序列收集到一个<div>中,如下所示:

<root>
 <div>
  <a>...</a>
  <b>...</b>
  <a>...</a>
  <a>...</a>
 </div>
 <comment>...</comment>
 <div>
  <a>...</a>
  <b>...</b>
 </div>
 <comment>...</comment>
 <div>
  <a>...</a>
  <b>...</b>
 </div>
</root>

我的第一次尝试是将<div>...</div>放入root,然后将comment包裹在</div>...<div>中(请注意标记的反转),但是&#39 ;不允许在XSLT中使用。我怎么能这样做?

以下问题与我的相关,但它涉及计算固定ab s,而我想计算a s和b s直到我点击comment

2 个答案:

答案 0 :(得分:3)

以下是如何在 XSLT 1.0中实现

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="group-by-comment" match="root/*" use="count(preceding-sibling::comment)" />

<xsl:template match="/root">
    <xsl:copy>
        <!-- process children of root using group mode -->
        <xsl:apply-templates select="*" mode="group"/>
    </xsl:copy>
</xsl:template>

<!-- [group mode] for each child of root that is first in its group: -->
<xsl:template match="*[count(. | key('group-by-comment', count(preceding-sibling::comment))[1]) = 1]" mode="group">
    <div>
        <!-- process the entire group -->
        <xsl:apply-templates select="key('group-by-comment', count(preceding-sibling::comment))"/>
    </div>
</xsl:template>

<!-- [group mode] special rule for the dividing comment element -->
<xsl:template match="comment" mode="group">
    <xsl:copy-of select="."/>
</xsl:template>

<!-- process group members -->
<xsl:template match="*">
    <xsl:copy-of select="."/>
</xsl:template>

<!-- exclude the dividing comment element from the processed group -->
<xsl:template match="comment"/>

</xsl:stylesheet>

应用于以下测试输入

<root>
    <alpha id="1"/>
    <bravo id="2"/>
    <charlie id="3"/>
    <alpha id="4"/>
    <bravo id="5"/>
    <comment id="6"/>
    <charlie id="7"/>
    <alpha id="8"/>
    <bravo id="9"/>
    <comment id="10"/>
    <alpha id="11"/>
    <charlie id="12"/>
</root>

结果是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <div>
      <alpha id="1"/>
      <bravo id="2"/>
      <charlie id="3"/>
      <alpha id="4"/>
      <bravo id="5"/>
   </div>
   <comment id="6"/>
   <div>
      <charlie id="7"/>
      <alpha id="8"/>
      <bravo id="9"/>
   </div>
   <comment id="10"/>
   <div>
      <alpha id="11"/>
      <charlie id="12"/>
   </div>
</root>

答案 1 :(得分:2)

John,考虑使用XSLT 2.0(自2007年开始使用)和XSLT 2.0处理器(如Saxon 9),您可以轻松使用

<xsl:template match="root">
  <xsl:copy>
    <xsl:for-each-group select="*" group-adjacent="boolean(self::a | self::b)">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
          <div>
            <xsl:copy-of select="current-group()"/>
          </div>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>