<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>
Run Code Online (Sandbox Code Playgroud)
我需要使用XPath检索节点列表,其中每个节点必须满足以下条件:
节点至少有一个子文本节点
如果节点(或祖先轴中最近的节点)具有属性"ok",则该值必须为"yes"
当任何祖先是结果的一部分时,排除节点
所以在我的样本中,我想得到<c>和<e>.节点<d>被排除,因为它是子节点<c>,这是结果的一部分.
我用条件(1)开始使用这个表达式//*[count(./text()[normalize-space()])>0].它返回<c>,<d>,<e> 和<f>.我不知道如何排除<d>
我将这分为两步.首先,仅考虑条件编号1和2.
//*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
Run Code Online (Sandbox Code Playgroud)
给定的XML中的问题作为输入,上面的xpath返回3个元素:<c>,<d>,和<e>.
下一步将实现条件号3.这可以通过重复第一步中使用的相同谓词来完成,但现在用于ancestor::*代替当前节点.然后使用not()我们希望祖先失败条件no 1和2来否定重复的谓词(我们希望当前节点的祖先不是结果的一部分):
[not(
ancestor::*[text()[normalize-space()]]
[
ancestor-or-self::*[not(@ok)]
or
ancestor-or-self::*[@ok][1][@ok='yes']
]
)
]
Run Code Online (Sandbox Code Playgroud)
将两个步骤组合在一起,您将获得以下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']
]
)
]
Run Code Online (Sandbox Code Playgroud)
[]最终xpath中的每个外部谓词()按顺序表示条件号1,2和3.