XPath谓词中descendant-or-self与ancestor-or-self的用法疑问
问题解答
为什么要用ancestor-or-self而不是descendant-or-self?
你要排除的是PurchaseOrder1节点下的所有符合条件的PurchaseOrder,这些目标排除节点的本质是:它们是PurchaseOrder1的后代节点。判断逻辑应该聚焦于「当前节点是否处于PurchaseOrder1的管辖范围内」——也就是当前节点本身或者它的祖先节点中存在PurchaseOrder1。
- 用
ancestor-or-self::PurchaseOrder1:检查当前节点自身或其所有祖先节点里是否有PurchaseOrder1。如果有,说明该节点在PurchaseOrder1的层级下,需要排除,not()之后就会把它过滤掉,完全匹配你的需求。 - 用
descendant-or-self::PurchaseOrder1:检查的是当前节点自身或其所有后代节点里是否有PurchaseOrder1。但你要排除的节点是PurchaseOrder1的后代,它们自身下面根本不存在PurchaseOrder1,这个条件永远不成立,not()之后就会把这些节点保留下来,自然达不到排除效果。
简单说:你搞反了检查方向——要查的是「这个节点是不是在PurchaseOrder1里面」,而不是「这个节点里面有没有PurchaseOrder1」。
替代表达式
根据你的需求(获取OrderDate为1999-10-22的PurchaseOrder,排除PurchaseOrder1下的所有节点),以下几种写法都可以:
1. 简化祖先检查(假设PurchaseOrder1不是PurchaseOrder类型)
如果PurchaseOrder1是容器节点而非PurchaseOrder本身,可去掉self::直接检查祖先:
//PurchaseOrder[@OrderDate="1999-10-22" and not(ancestor::PurchaseOrder1)]
2. 先排除容器再找节点
先定位PurchaseOrders下非PurchaseOrder1的节点,再在这些节点范围内筛选符合条件的PurchaseOrder:
/PurchaseOrders/*[not(self::PurchaseOrder1)]/descendant-or-self::PurchaseOrder[@OrderDate="1999-10-22"]
3. 直接路径匹配(适用于PurchaseOrder为PurchaseOrders直接子节点的场景)
如果PurchaseOrder都是PurchaseOrders的直接子节点,无多层嵌套,写法可以更简洁:
/PurchaseOrders/PurchaseOrder[@OrderDate="1999-10-22" and not(parent::PurchaseOrder1)]
4. 使用except运算符(XPath 2.0+支持)
若你的环境支持XPath 2.0及以上版本,可通过集合差集实现:
//PurchaseOrder[@OrderDate="1999-10-22"] except //PurchaseOrder1//PurchaseOrder[@OrderDate="1999-10-22"]
内容的提问来源于stack exchange,提问作者user2759835
相关产品推荐
相关产品推荐

