xpath根据包含值的父属性排除元素及其所有子级



标记示例:

<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 containers"元素本身?

本例中的输出应为:

<p>
    <moredepth>
        <...>
            <p>text1</p>
            <li>text2</li>
        </...>
    </moredepth>
</p>

第页。S.是否可以使用CSS进行这样的选择?

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

A: 从//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及其后代。

然后,您可以向表达式添加额外的步骤,以准确地筛选出所需的文本或节点。

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>

最新更新