使用XSLT 1.0,下面的解决方案是工作 - 测试与您的示例XML 6个元素:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<xsl:apply-templates select="/foo/bar"/>
</xsl:template>
<xsl:template match="bar">
<xsl:for-each select="*/node()">
<xsl:if test="(position()-1) mod(3) = 0">
<data>
<xsl:call-template name="grouping">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="amount" select="3"/>
</xsl:call-template>
</data>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="grouping">
<xsl:param name="position" select="0"/>
<xsl:param name="amount" select="0"/>
<xsl:copy-of select="//bar/*[$position]"/>
<xsl:if test="$amount > $position or ($position mod(3) > 0)">
<xsl:call-template name="grouping">
<xsl:with-param name="position" select="$position + 1"/>
<xsl:with-param name="amount" select="$amount"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
结果:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
</data>
<data>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
</data>
作为简短的说明 - 在模板匹配 “栏中的” 所有元素节点在
<xsl:for-each select="*/node()">
通过使用<xsl:if test="(position()-1) mod(3) = 0">
(w对于第一个节点和第三个节点,其值为0),称为“分组”的模板被称为提供3个节点的生成组。这个模板用参数位置(当前节点的位置)和数量 - 要在每个组中复制的节点数量来调用。
分组模板复制当前节点 - <xsl:copy-of select="//bar/*[$position]"/>
- 检查是否已经生成了3个节点 - <xsl:if test="$amount > $position or ($position mod(3) > 0)">
- 并再次调用自身,以计数器的形式递增位置,因此下一个节点将被复制。
为防万一它不明显 - 只要不是3的倍数,分组模板将被调用$amount > $position
,所以前3个节点将被复制,并且所有后续节点的$position mod(3) > 0
只要不是3的倍数。在你的xml中第7个元素,这将被复制为data
-group中的单个元素。
这是*分组*问题(执行搜索)。如果您使用XSLT 1.0或2.0,解决方案会非常不同 - 请选择一个(这些标签意味着互斥)。 – 2014-09-29 18:15:18