如何找到具有相同子节点的节点 [英] How to find nodes with same children
问题描述
我有以下 xml.请注意,节点 n1 和 n3 具有相同的子节点(顺序可以不同).如何编写 XSL 转换来识别此类节点?
I have following xml. Note that node n1 and n3 have same children (order can be different). How can I write an XSL transformation to identify such nodes?
<Document>
<Node name="n1">
<Item value="v1">
<Item value="v2">
<Item value="v3">
</Node>
<Node name="n2">
<Item value="p1">
<Item value="p2">
<Item value="p3">
</Node>
<Node name="n3">
<Item value="v3">
<Item value="v1">
<Item value="v2">
</Node>
</Document>
推荐答案
这是一个完整的 XSLT 1.0 解决方案,它足够通用,即使 Node
允许有任何名字的孩子:
Here is a complete XSLT 1.0 solution that is general enough so that it would produce correct results even when a Node
is allowed to have children with any name:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kNodeBySign" match="Node" use="@signature"/>
<xsl:template match="/*">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="ext:node-set($vrtfPass1)"/>
</xsl:template>
<xsl:template match="Node">
<Node name="{@name}">
<xsl:variable name="vSignature">
<xsl:for-each select="*">
<xsl:sort select="name()"/>
<xsl:sort select="@value"/>
<xsl:value-of select="concat(name(),'+++',@value)"/>
</xsl:for-each>
</xsl:variable>
<xsl:attribute name="signature">
<xsl:value-of select="$vSignature"/>
</xsl:attribute>
</Node>
</xsl:template>
<xsl:template match="/" mode="pass2">
<xsl:for-each select=
"Node[generate-id()
=
generate-id(key('kNodeBySign',@signature)[1])
]
">
<Node name="{@name}">
<xsl:variable name="vNodesInGroup">
<xsl:for-each select=
"key('kNodeBySign',@signature)[position()>1]">
<xsl:value-of select="concat(@name, ' ')"/>
</xsl:for-each>
</xsl:variable>
<xsl:attribute name="matches">
<xsl:value-of select="$vNodesInGroup"/>
</xsl:attribute>
</Node>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于此 XML 文档时:
<Document>
<Node name="n1">
<Item value="v1"/>
<Item value="v2"/>
<Item value="v3"/>
</Node>
<Node name="n2">
<Item value="p1"/>
<Item value="p2"/>
<Item value="p3"/>
</Node>
<Node name="n3">
<Item value="v3"/>
<Item value="v1"/>
<Item value="v2"/>
</Node>
<Node name="n4">
<Item value="p3"/>
<Item value="v1"/>
<Item value="v2"/>
</Node>
<Node name="n5">
<Item value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
</Node>
<Node name="n6">
<Item value="v2"/>
<Item value="v1"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
<Node name="n7">
<Item value="v1"/>
<Item value="v1"/>
<Item value="v2"/>
<Item value="v3"/>
<Item value="v4"/>
</Node>
</Document>
产生想要的、正确的结果:
<Node name="n1" matches="n3 n5 "/>
<Node name="n2" matches=""/>
<Node name="n4" matches=""/>
<Node name="n6" matches=""/>
<Node name="n7" matches=""/>
说明:
这是一个两遍的转换.
This is a two-pass transformation.
第一遍的结果是一个 XML 片段,其中包含 Node
元素及其 name
属性和一个新添加的属性:signature
.这是所有子项的名称和值的串联(以正常的排序形式).在这种具体情况下,pass1 的结果如下:
The result of the first pass is an XML fragment containing Node
elements with their name
attribute and one newly added attribute: signature
. This is the concatenation of the names and values of all children (in normal, sorted form). The result of pass1 in this concrete case is the following:
在第 2 轮中,我们使用 Muenchian 方法按 signature
属性对所有 Node
元素进行分组.每个组中的第一个 Node
在输出中用一个新属性 matches
表示,其值是以下元素的 name
属性的空格分隔连接当前组中剩余的 Node
元素.
In pass 2 we use the Muenchian method for grouping all Node
elements by their signature
attribute. The first Node
in every group is represented in the output with a new attribute matches
whose value is the space-delimited concatenation of the name
attributes of the remaining Node
elements in the current group.
这篇关于如何找到具有相同子节点的节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!