如何用XPath在指定节点集合中按@u属性过滤唯一元素?
XPath 去重问题:基于指定节点集合过滤重复@u属性值
先来看你的原始XML结构:
<r> <x> <s> <a u="1"/> <a u="2"/> </s> <t> <a u="1"/> <a u="4"/> </t> </x> <y> <a u="4"/> <a u="5"/> <a u="4"/> <a u="1"/> </y> </r>
你想要过滤/r/x//a节点中@u属性重复的元素,只保留每个@u值第一次出现的节点,预期结果是:
Element='' Element='' Element=''
但你用表达式/r/x//a[not(@u=preceding-sibling::node()/@u)]得到的结果不符合预期,多了一个<a u="1"/>,原因你也点出来了:preceding-sibling::node()只能查找当前节点同一父元素下的前序同级节点,<t>下的<a u="1"/>的前序同级只有<t>内部的节点,看不到<s>里的那个<a u="1"/>,所以它不会被过滤掉。
下面给你两种不同XPath版本的解决方案,都是基于/r/x//a整个节点集合来做去重:
XPath 2.0+ 简洁写法
如果你的环境支持XPath 2.0及以上,可以用序列操作来实现,逻辑是保留每个@u值在整个节点序列中第一次出现的节点:
/r/x//a[index-of(/r/x//a/@u, @u)[1] = position()]
简单解释:
/r/x//a/@u生成所有目标节点的@u属性值序列index-of(..., @u)[1]找到当前节点@u值在序列中第一次出现的位置- 只有当前节点在整个
/r/x//a序列中的位置等于这个第一次出现的位置时,才会被选中
XPath 1.0 兼容写法
如果只能用XPath 1.0(没有distinct-values这类高级函数),可以通过统计前序节点的数量来判断:
/r/x//a[count(preceding::a[ancestor::x and @u = current()/@u]) = 0]
逻辑是:
preceding::a[ancestor::x]限定只查找/r/x范围内的所有前序<a>节点- 判断当前节点的@u值在这些前序节点中从未出现过,也就是该@u值的第一个实例
这两种写法都能得到你预期的结果,完美实现基于指定节点集合的去重。
内容的提问来源于stack exchange,提问作者erdal.karaca
相关产品推荐
相关产品推荐

