按 Xsl 中子节点的值对 xml 节点进行分组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4711039/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Grouping xml nodes by value of a child in Xsl
提问by Harold Sota
<root>
<element>
<id>1</id>
<group>first</group>
</element>
<element>
<id>2</id>
<group>second</group>
</element>
<element>
<id>3</id>
<group>first</group>
</element>
...
<root>
How I can group my elements by the group name in xslt 1.0. the output:
如何按 xslt 1.0.0 中的组名对元素进行分组。输出:
<root>
<group name="first">
<element>
<id>1</id>
<group>first</group>
</element>
<element>
<id>3</id>
<group>first</group>
</element>
</group>
<group name="second">
<element>
<id>2</id>
<group>second</group>
</element>
</group>
</root>
Any ideas?
有任何想法吗?
回答by Tim C
This is a job for Muenchian Grouping. You will numerous examples of it within the XSLT tag here on StackOverflow.
这是 Muenchian Grouping 的工作。您将在 StackOverflow 上的 XSLT 标记中找到大量示例。
First, you need to define a key to help you group the groups
首先,您需要定义一个键来帮助您对组进行分组
<xsl:key name="groups" match="group" use="."/>
This will look up groupelements for a given group name.
这将查找给定组名称的组元素。
Next, you need to match all the occurrences of the first instance of each distince group name. This is done with this scary looking statement
接下来,您需要匹配每个区分组名称的第一个实例的所有匹配项。这是通过这个看起来很可怕的陈述完成的
<xsl:apply-templates select="element/group[generate-id() = generate-id(key('groups', .)[1])]"/>
i.e Match group elements which happen to be the first occurence of that element in our key.
即匹配恰好是该元素在我们的键中第一次出现的组元素。
When you have matched the distinct group nodes, you can then loop through all other group nodes with the same name (where $currentGroup is a variable holding the current group name)
当您匹配了不同的组节点后,您可以遍历所有其他具有相同名称的组节点(其中 $currentGroup 是保存当前组名称的变量)
<xsl:for-each select="key('groups', $currentGroup)">
Putting this altogether gives
把这完全给
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="groups" match="group" use="."/>
<xsl:template match="/root">
<root>
<xsl:apply-templates select="element/group[generate-id() = generate-id(key('groups', .)[1])]"/>
</root>
</xsl:template>
<xsl:template match="group">
<xsl:variable name="currentGroup" select="."/>
<group>
<xsl:attribute name="name">
<xsl:value-of select="$currentGroup"/>
</xsl:attribute>
<xsl:for-each select="key('groups', $currentGroup)">
<element>
<id>
<xsl:value-of select="../id"/>
</id>
<name>
<xsl:value-of select="$currentGroup"/>
</name>
</element>
</xsl:for-each>
</group>
</xsl:template>
</xsl:stylesheet>
Applying this on your sample XML gives the following result
在您的示例 XML 上应用它会得到以下结果
<root>
<group name="first">
<element>
<id>1</id>
<name>first</name>
</element>
<element>
<id>3</id>
<name>first</name>
</element>
</group>
<group name="seccond">
<element>
<id>2</id>
<name>seccond</name>
</element>
</group>
</root>
回答by Dimitre Novatchev
I. Here is a complete and very short XSLT 1.0 solution:
I. 这是一个完整且非常简短的 XSLT 1.0 解决方案:
<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="kElsByGroup" match="element" use="group"/>
<xsl:template match="/*">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match=
"element[generate-id()=generate-id(key('kElsByGroup',group)[1])]">
<group name="{group}">
<xsl:copy-of select="key('kElsByGroup',group)"/>
</group>
</xsl:template>
<xsl:template match=
"element[not(generate-id()=generate-id(key('kElsByGroup',group)[1]))]"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
当此转换应用于提供的 XML 文档时:
<root>
<element>
<id>1</id>
<group>first</group>
</element>
<element>
<id>2</id>
<group>second</group>
</element>
<element>
<id>3</id>
<group>first</group>
</element>
</root>
the wanted, correct result is produced:
产生了想要的、正确的结果:
<root>
<group name="first"><element>
<id>1</id>
<group>first</group>
</element><element>
<id>3</id>
<group>first</group>
</element></group>
<group name="second"><element>
<id>2</id>
<group>second</group>
</element></group>
</root>
Do note:
请注意:
The use of the Muenchian method for grouping. This is the most efficient grouping method in XSLT 1.0.
The use of AVT(Attribute Value Template) to specify a literal result element and its variable - value attribute as one whole. Using AVTs simplifies coding and yields shorter and more understandable code.
使用Muenchian 方法进行分组。这是 XSLT 1.0 中最有效的分组方法。
使用 AVT(属性值模板)来指定一个文字结果元素及其变量值属性作为一个整体。使用 AVT 可以简化编码并生成更短、更易于理解的代码。
II. An even shorter XSLT 2.0 solution:
二、一个更短的 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="/*">
<root>
<xsl:for-each-group select="element" group-by="group">
<group name="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the same XML document (above), the same correct result is again produced.
当此转换应用于同一个 XML 文档(上图)时,会再次产生相同的正确结果。
Do note:
请注意:
.1. The use of the <xsl:for-each-group>XSLT 2.0 instruction.
.1. 使用的<xsl:for-each-group>XSLT 2.0指令。
.2. The use of the standard XSLT 2.0 functions current-group()and current-grouping-key()
.2. 使用标准 XSLT 2.0 函数current-group()和current-grouping-key()
回答by lweller
<xsl:template match="group[not(.=preceding::group)]">
<xsl:variable name="current-group" select="." />
<xsl:for-each select="//root/element[group=$current-group]">
<group>
<id><xsl:value-of select="id"/></id>
</group>
</xsl:for-each>
</xsl:template>

