<doc ok="yes">
<a>
<b>
<c>
aa
<d ok="yes">
bb
</d>
cc
</c>
</b>
</a>
<e>
ee
</e>
<f ok="no">
no
</f>
</doc>
我需要使用XPath检索节点列表,其中每个节点必须满足以下条件:
节点至少有一个子文本节点
如果节点(或祖先轴中最近的节点)具有属性"ok"
,则值必须为"yes"
当任何祖先是结果的一部分时,排除节点
因此,在我的示例中,我想获得<c>
和<e>
。节点<d>
被排除,因为它是<c>
的子节点,它是结果的一部分。
我已使用此表达式//*[count(./text()[normalize-space()])>0]
启动条件(1)。它会返回<c>
,<d>
,<e>
和<f>
。我不知道如何排除<d>
答案 0 :(得分:8)
我会把这分为两步。 首先,只考虑条件编号1和2。
//*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
将XML视为输入,xpath上方返回3个元素:<c>
,<d>
和<e>
。
下一步将实现条件号3.可以通过重复第一步中使用的相同谓词来完成,但现在用于ancestor::*
而不是当前节点。然后使用not()
否定重复的谓词,因为我们希望祖先在1和1的条件下失败。 2(我们希望当前节点的祖先不是结果的一部分):
[not(
ancestor::*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
)
]
将两个步骤组合在一起,您将获得以下xpath:
//*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
[not(
ancestor::*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
)
]
最终xpath中的每个外部谓词([]
)按顺序表示条件no 1,2和3.