xpath通过包含值的父属性排除元素及其所有子元素

时间:2015-02-26 09:17:21

标签: html dom xpath css-selectors

标记示例:

<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进行这样的选择?

2 个答案:

答案 0 :(得分:4)

您可以应用Kaysian方法来获取集合的交集。你有两套:

答:来自//div[contains(@class, 'post-content')]的元素,不包括当前元素(因为您不想要根div):

//*[ancestor::div[contains(@class, 'post-content')]]

B:来自//*[not(contains(@class, 'image-container'))]的元素,包括当前元素(因为您要排除整个树,包括divspan):

//*[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

排除与不受欢迎的类及其后代匹配的spandiv

然后,您可以向表达式添加额外的步骤,以准确过滤出您需要的文本或节点。

答案 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>