XPath - 获取具有条件的文本节点的父节点

Ial*_*ale 4 xpath

<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检索节点列表,其中每个节点必须满足以下条件:

  1. 节点至少有一个子文本节点

  2. 如果节点(或祖先轴中最近的节点)具有属性"ok",则该值必须为"yes"

  3. 当任何祖先是结果的一部分时,排除节点

所以在我的样本中,我想得到<c><e>.节点<d>被排除,因为它是子节点<c>,这是结果的一部分.

我用条件(1)开始使用这个表达式//*[count(./text()[normalize-space()])>0].它返回<c>,<d>,<e><f>.我不知道如何排除<d>

har*_*r07 8

我将这分为两步.首先,仅考虑条件编号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.