我有以下输入xml,想知道XSLT是否可以处理这样的转换。如果可以,如何实现?
输入xml:
<foo>
<bar>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
...
..
</bar>
</foo>
输出xml:
<data>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
</data>
<data>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
</data>
....
在上面的例子中可能有更多重复的A、B、C节点。由于重复不在重复父节点中,因此不可能分别使用。我一直在探索每个小组的选项,但不确定这是否适用。如有任何建议,不胜感激。
使用XSLT1.0,以下解决方案正在使用具有6个元素的示例XML进行工作测试:
<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">
(对于第一个节点和每第三个节点为0),调用名为"grouping"的模板来提供3个节点的生成组。调用此模板时,参数为position(当前节点的位置)和amount(每组中要复制的节点数量)
分组模板复制当前节点<xsl:copy-of select="//bar/*[$position]"/>
-检查是否已经生成了3个节点<xsl:if test="$amount > $position or ($position mod(3) > 0)">
-并再次调用自己,将位置作为计数器递增,因此将复制下一个节点
只是为了防止这一点不明显——将为$amount > $position
调用分组模板,因此将复制前3个节点,并为$position mod(3) > 0
调用所有后续节点,只要它不是3的倍数。如果xml中有第7个元素,那么它将作为data
-组中的单个元素进行复制。
正如您最初所想,xsl:for-each-group
将是完美的;使用group-starting-with
属性。
XML输入
<foo>
<bar>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
<A>111</A>
<B>222</B>
<C>333</C>
</bar>
</foo>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:for-each-group select="bar/*" group-starting-with="A">
<data>
<xsl:apply-templates select="current-group()"/>
</data>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
XML输出(格式不符合原始问题中的规定)
<data>
<A>xxx</A>
<B>yyy</B>
<C>zzz</C>
</data>
<data>
<A>aaa</A>
<B>bbb</B>
<C>ccc</C>
</data>
<data>
<A>111</A>
<B>222</B>
<C>333</C>
</data>