使用xpath查找重复的同级

使用xpath查找重复的同级,xpath,duplicates,xpath-2.0,siblings,Xpath,Duplicates,Xpath 2.0,Siblings,如何使用Xpath仅查找至少具有相似/相等同级节点的节点 例如: <root> <parent> <node>...</node> <node_unique>...</node_unique> <node>...</node> <another_one>...</another_one> <another_one>...&

如何使用Xpath仅查找至少具有相似/相等同级节点的节点

例如:

<root>
  <parent>
    <node>...</node>
    <node_unique>...</node_unique>
    <node>...</node>
    <another_one>...</another_one>
    <another_one>...</another_one>
  </parent>
</root>

...
...
...
...
...
在这个例子中,xpath应该只选择
,因为它们出现了不止一次


我花了几个小时试图找到一个解决方案,但没有成功(现在我认为XPath是不可能的…。

使用单个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]]
<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>
<node>...</node>
<another_one>...</another_one>
更简洁的表达式

/*/*/*
   [name() = following-sibling::*/name()
  and
    not(name() = preceding-sibling::*/name())
   ]
/*/*/*[index-of(/*/*/*/name(), name())[2]]
<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>
<node>...</node>
<another_one>...</another_one>
基于XSLT2.0的验证

/*/*/*
   [name() = following-sibling::*/name()
  and
    not(name() = preceding-sibling::*/name())
   ]
/*/*/*[index-of(/*/*/*/name(), name())[2]]
<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>
<node>...</node>
<another_one>...</another_one>

在提供的XML文档上应用此转换时:

<root>
  <parent>
    <node>...</node>
    <node_unique>...</node_unique>
    <node>...</node>
    <another_one>...</another_one>
    <another_one>...</another_one>
  </parent>
</root>

...
...
...

+1,非常有表现力和简洁的回答。但是,先生,我认为可能有其他的方式。@Cylian,总是有“其他方式”--我们必须尝试提供最简洁的解决方案,同时也是一个有效的解决方案。我真的有点困惑为什么使用
/*/*/*
,不仅仅是
/*/*
,但当我惊讶地尝试使用它时,我发现没有结果节点在选择。为什么会这样?
/*/*/*
有什么特别的意思吗?@Cylian,
/*/*/*/*/*/*
selects顶级元素的所有孙子。