如何在XPath 1.0中实现从元素集合排除指定XPath匹配元素?
XPath 1.0 实现集合差集方案
核心需求
已知XPath通过|运算符合并节点集(取并集),例如//div | //span可获取所有div和span元素。现需在XPath 1.0环境下实现集合差集:获取第一个XPath匹配的所有元素中,不属于第二个XPath匹配集合的元素(无法使用XPath 2.0的except运算符)。
关键原理
XPath 1.0没有直接的节点集比较运算符,但可以通过count()函数判断节点是否属于目标集合:
- 对于当前节点
.和排除集合$exclude-set,如果count(. | $exclude-set)的结果等于count($exclude-set),说明当前节点已经在排除集合中(合并后集合大小不变)。 - 用
not()取反,即可得到不在排除集合中的节点,也就是我们需要的差集结果。
另外也可以用generate-id()函数(每个节点的唯一ID)判断当前节点的ID是否存在于排除集合的ID中,但该方法在排除集合元素较多时需要逐个比较,不如count()方法通用。
示例解法
示例1:从//tr/td中排除内容为<td>1</td>和<td>4</td>的元素
首先将需要排除的元素合并为一个节点集://td[text()='1'] | //td[text()='4'],然后套用差集公式:
//tr/td[not(count(. | //td[text()='1'] | //td[text()='4']) = count(//td[text()='1'] | //td[text()='4']))]
如果是针对内容直接过滤,也可以简化为:
//tr/td[not(text()='1' or text()='4')]
示例2:从//div中排除三个特定XPath匹配的元素
先将三个排除用的XPath通过|合并为一个排除集合,再套用公式:
//div[not(count(. | //span[@class="sp"]/p/div[1] | //html/body/div/span/div | //p[@id="para"]/div/p/div) = count(//span[@class="sp"]/p/div[1] | //html/body/div/span/div | //p[@id="para"]/div/p/div))]
该表达式会从所有div元素中,剔除三个指定XPath匹配的3个元素,最终得到642个目标元素。
常见误区说明
直接使用not(//td[text()='1'])无法达到预期效果,因为not()在这里判断的是整个节点集是否为空,而不是判断当前节点是否属于该集合,必须通过节点集合并后的计数对比,才能实现精准的节点归属判断。
内容的提问来源于stack exchange,提问作者CaptainCsaba
相关产品推荐
相关产品推荐

