这里有一个更简单的解决方案(完全是“推式”方法,没有 <xsl:for-each>
,没有嵌套,没有 <xsl:variable>
,没有 current()
,没有 //
,没有轴):
<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="kGoodsByType" match="/*/*" use="a"/>
<xsl:template match=
"/*/*[generate-id()
=
generate-id(key('kGoodsByType', a)[1])
]
">
<group type="{a}">
<xsl:apply-templates select="key('kGoodsByType', a)/b"/>
</group>
</xsl:template>
<xsl:template match="b">
<value v="{.}"/>
</xsl:template>
<xsl:template match="*/* | text()" priority="-1"/>
</xsl:stylesheet>
当应用于所提供的XML文档时,此转换会发生以下情况:
<Test>
<grapes>
<a>TypeA</a>
<b>value1</b>
</grapes>
<oranges>
<a>TypeB</a>
<b>value2</b>
</oranges>
<apples>
<a>TypeA</a>
<b>value3</b>
</apples>
</Test>
期望的、正确的结果已经生成:
<group type="TypeA">
<value v="value1"/>
<value v="value3"/>
</group>
<group type="TypeB">
<value v="value2"/>
</group>
解释:使用a
子节点的字符串值作为键,对/*/*
进行Muenchian分组。
II. XSLT 2.0解决方案:
<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="/*">
<xsl:for-each-group select="*/a" group-by=".">
<group type="{current-grouping-key()}">
<xsl:sequence select="current-group()/../b"/>
</group>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
当对同一XML文档(如上所示)进行此转换时,将产生相同的正确结果:
<group type="TypeA">
<b>value1</b>
<b>value3</b>
</group>
<group type="TypeB">
<b>value2</b>
</group>
解释:
<xsl:for-each-group>
用于根据指定的分组条件对节点集合进行分组,然后在每个分组上执行相应的操作。
current-group()
返回当前分组中的所有节点。
current-grouping-key()
返回当前分组使用的分组键。