我有以下输入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节点。由于重复不在重复的父节点中,因此不可能使用for-each。我正在探索for-each-group的选项,但不确定这是否适用。非常感谢任何建议。
答案 0 :(得分:0)
使用XSLT 1.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>
简短解释 - 在模板匹配&#34; bar&#34;所有元素节点都在
中处理<xsl:for-each select="*/node()">
通过使用<xsl:if test="(position()-1) mod(3) = 0">
(第一个节点和每个第三个节点为0),名为&#34的模板;分组&#34;被调用以提供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
用于所有后续节点,只要它为&#39} ; s不是3的倍数。如果有例如xml中的第7个元素,它将被复制为data
- 组中的单个元素。
答案 1 :(得分:0)
就像你原先想的那样,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>