标记示例:
<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>
P.S。是否可以使用CSS进行这样的选择?
答案 0 :(得分:4)
您可以应用Kaysian方法来获取集合的交集。你有两套:
答:来自//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
。
然后,您可以向表达式添加额外的步骤,以准确过滤出您需要的文本或节点。
答案 1 :(得分:2)
一旦路径表达式返回给你,XPath就不允许操作XML片段。因此,您无法选择moredepth
:
//moredepth
没有得到此元素节点的所有结果,包括您要排除的所有后代节点:
<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>