这些是不可能用单个 XPath 1.0 表达式选择的(由于 XPath 1.0 中缺少范围变量)。
一种可能的解决方案是选择所有/*/*/* 元素,然后使用该元素的name() 获取每个元素的名称,然后评估/*/*/*[name() = $currentName][2](其中$currentName 应替换为刚刚的名称获得。如果最后一个表达式选择一个元素,那么currentName 是一个至少出现两次的名称 - 因此您保留该元素。对所有元素及其名称执行此操作。作为辅助步骤,可能会删除名称(和选定的元素)通过将它们放在哈希表中。
在 Xpath 2.0 中,使用单个 XPath 表达式选择给定父级的所有子级是很简单的,这些子级至少有一个同名的兄弟:
/*/*/*
[name() = following-sibling::*/name()
and
not(name() = preceding-sibling::*/name())
]
更简洁的表达式:
/*/*/*[index-of(/*/*/*/name(), name())[2]]
基于 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:copy-of select=
"/*/*/*[index-of(/*/*/*/name(), name())[2]]"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<root>
<parent>
<node>...</node>
<node_unique>...</node_unique>
<node>...</node>
<another_one>...</another_one>
<another_one>...</another_one>
</parent>
</root>
上面的 XPath 表达式被求值,并且从这个求值元素中选择的元素被复制到输出中:
<node>...</node>
<another_one>...</another_one>
注意:有关相关问题/答案,请参阅this。