使用 XPath 查找最顶层的后续元素

Find top-most following elements with XPath

在 XPath 中,我知道我可以 select 使用 /following::* 所有以下元素,但是我想 避免 还 selecting 包含在任何以下元素中的子元素。

例如,给定此文档:

<body>
    <div id="div1">
        <p id="p1">...</p>
        <p id="p2">
            <span id="span1"></span>
            <span id="span2"><i id="i1">...</i></span>
        </p>
        <p id="p3">...</p>
    </div>
    <div id="div2">
        <p id="p4">...</p>
        <p id="p5">...</p>
    </div>
</body>

如果我有 span1 selected,我想 select span2(但不是 i1),p3,和 div2(但不是 p4p5)。

在 Python 中,我的代码可能类似于:

>>> lxml.html.fromstring(document).xpath('//*[@id="span1"]/following::*')
[<Element span at 0x1082bd680>,
 <Element i at 0x1082bd4f0>,
 <Element p at 0x1082bd770>,
 <Element div at 0x1082bd360>,
 <Element p at 0x1082bd7c0>,
 <Element p at 0x1082bdef0>]

但我想要返回的是:

[<Element span at 0x1082bd680>,
 <Element p at 0x1082bd770>,
 <Element div at 0x1082bd360>]

编辑:@kjhughes 的回答让我完成了 90% 的工作。因为现实生活中的例子可能没有我可以轻松用来匹配的 ID,所以我最终编写了如下代码:

find_following = lxml.html.etree.XPath(
    "following::*[not(../preceding::*[. = node()])]"
)

这个 XPath,

//*[@id="span1"]/following::*[not(../preceding::*[@id="span1"])]

选择目标 span 元素之后的元素,其父元素没有目标 span 元素作为前置元素,

<span id="span2"><i id="i1">...</i></span>
<p id="p3">...</p>
<div id="div2"> <p id="p4">...</p> <p id="p5">...</p> </div>

根据要求。

XPath 3.1 具有函数 outermost()outermost(following::*) 选择以下所有元素,不包括节点集中另一个元素的后代元素。

XPath 2.0 允许 following::* except following::*/descendant::*.

在 XPath 1.0 中,您可以将 ($A except $B) 表示为 $A[count(.|$B)=count($B)]。 (尽管这并不是那么有用,因为 XPath 本身没有办法绑定变量)。