这个 XSLT 1.0 样式表...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="kCommon" match="*[starts-with(name(),'fils')]"
use="concat(name(),'|',.)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(name(),'fils')]
[count(key('kCommon',concat(name(),'|',.))) >= 2]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:variable name="this-key" select="concat(name(),'|',.)" />
<xsl:attribute name="id"><xsl:value-of select="
count(preceding::*
[starts-with(name(),'fils')]
[count(.|key('kCommon',$this-key)) =
count( key('kCommon',$this-key)) ]
) + 1" /></xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...将转换此输入...
<Racine>
<el1>
<fils1>context1</fils1>
<fils2>test1</fils2>
<fils1>context1</fils1>
</el1>
<el2>
<fils1>context2</fils1>
<fils2>test2</fils2>
<fils1>context2</fils1>
</el2>
<el3>
<fils1>context1</fils1>
</el3>
</Racine>
...进入...
<Racine>
<el1>
<fils1 id="1">context1</fils1>
<fils2>test1</fils2>
<fils1 id="2">context1</fils1>
</el1>
<el2>
<fils1 id="1">context2</fils1>
<fils2>test2</fils2>
<fils1 id="2">context2</fils1>
</el2>
<el3>
<fils1 id="3">context1</fils1>
</el3>
</Racine>
解释
我们为具有通用名称和通用文本内容的 fils 元素构建一个键 ('kCommon')。我们寻找在他们的键组中至少有两个成员的元素——换句话说,filX 类型的元素具有与至少一个其他 filX 元素相同的名称和文本。这是我们的最后一个模板。
对于每个这样的公共元素,我们构建了两个集合:
公共组中所有前面的 fil 元素的集合。这一套是由...
设置 1
preceding::*[starts-with(name(),'fils')]
而这个节点的通用名+内容组,也就是……
设置 2
key('kCommon',concat(name(),'|',.))
但是因为我们将引用 concat(name(),'|',.) quiet 几次,并且在我们无法直接访问此上下文节点的地方,我们只需计算 concat() 并替换为 Set 2像这样。Set 2 现在可以快速计算。
设置 2
key('kCommon',$this-key)
然后我们使用Kaysian 方法取一个集合交集。
$set1[count(.|$set2)=count($set2)]
这个交集是所有志同道合的元素的集合。我们只是将它们数起来并加一个,这为我们提供了 id 属性的序数。