使用 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
(但不是 p4
或 p5
)。
在 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 本身没有办法绑定变量)。
在 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
(但不是 p4
或 p5
)。
在 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 本身没有办法绑定变量)。