xpath 通过包含值的父属性排除元素及其所有子元素
Posted
技术标签:
【中文标题】xpath 通过包含值的父属性排除元素及其所有子元素【英文标题】:xpath exclude element and all its children by parent attribute containing a value 【发布时间】:2015-04-28 14:13:26 【问题描述】:标记示例:
<div class="post-content">
<p>
<moredepth>
<...>
<span class="image-container float_right">
<div class="some_element">
image1
</div>
<p>do not need this</p>
</span>
<div class="image-container float_right">
image2
</div>
<p>text1</p>
<li>text2</li>
</...>
</moredepth>
</p>
</div>
最糟糕的是“图像容器”的深度可以在任何级别。
我尝试使用的Xpath:
//div[contains(@class, 'post-content')]//*[not(contains(@class, 'image-container'))]
我应该使用什么 Xpath 才能排除“some_element”和任何深度的“image-container”的任何其他子级以及“image-container”元素本身?
本例中的输出应为:
<p>
<moredepth>
<...>
<p>text1</p>
<li>text2</li>
</...>
</moredepth>
</p>
附:是否可以使用 CSS 进行这样的选择?
【问题讨论】:
请编辑您的帖子并包含您期望的输出(发布此 html)。 为什么不能选择外部的p
和moredepth
元素?你只想要moredepth
的孩子吗?
我需要选择 p 和更多深度。但我需要排除包含“图像容器”及其所有子元素的类
@MathiasMüller 再次编辑了输出标记的问题
【参考方案1】:
您可以应用 Kaysian 方法来获得集合的交集。你有两套:
A:从//div[contains(@class, 'post-content')]
下降的元素,不包括当前元素(因为你不想要根div
):
//*[ancestor::div[contains(@class, 'post-content')]]
B:来自//*[not(contains(@class, 'image-container'))]
的元素,包括当前元素(因为要排除整个树,包括div
和span
):
//*[not(ancestor-or-self::*[contains(@class, 'image-container')])]
这两组的交集是解决您问题的方法。 Kaysian 方法的公式为:A [ count(. | B) = count(B) ]
。将其应用于您的问题,您需要的结果是:
//*[ancestor::div[contains(@class, 'post-content')]]
[ count(. | //*[not(ancestor-or-self::*[contains(@class, 'image-container')])])
=
count(//*[not(ancestor-or-self::*[contains(@class, 'image-container')])]) ]
这将从您的示例代码中选择以下元素:
/div/p
/div/p/moredepth
/div/p/moredepth/...
/div/p/moredepth/.../p
/div/p/moredepth/.../li
排除与不需要的类及其后代匹配的span
和div
。
然后,您可以向表达式添加额外的步骤,以准确过滤掉您需要的文本或节点。
【讨论】:
太棒了!not(ancestor-or-self::*)
的事情奏效了。万一有人需要它,我需要类 link-list
中没有 aside
祖先的所有 ul
元素,所以我写了 "//ul[contains(@class, 'link-list') and not(ancestor-or-self::aside)]"
。【参考方案2】:
一旦 XML 片段通过路径表达式返回给您,XPath 就不允许对其进行操作。所以,你不能选择moredepth
:
//moredepth
没有得到这个元素节点的all结果,包括你想排除的所有后代节点:
<moredepth>
<span class="image-container float_right">
<div class="some_element">
image1
</div>
<p>do not need this</p>
</span>
<div class="image-container float_right">
image2
</div>
<p>text1</p>
<li>text2</li>
</moredepth>
你可以只选择moredepth
的子节点:
//div[contains(@class, 'post-content')]/p/moredepth/*[not(contains(@class,'image-container'))]
将产生(由-------
分隔的单个结果):
<p>text1</p>
-----------------------
<li>text2</li>
【讨论】:
虽然,这个答案并没有解决我的问题,但它是正确的。您不能用 XPath 做到这一点。我最终为这个任务编写了我的自定义脚本。以上是关于xpath 通过包含值的父属性排除元素及其所有子元素的主要内容,如果未能解决你的问题,请参考以下文章