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

val*_*nko 6 html xpath dom 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>
Run Code Online (Sandbox Code Playgroud)

最糟糕的是“图像容器”的深度可以在任何级别。

我尝试使用的 Xpath:

//div[contains(@class, 'post-content')]//*[not(contains(@class, 'image-container'))]
Run Code Online (Sandbox Code Playgroud)

我应该使用什么 Xpath 来排除“some_element”和任何深度的“image-container”的任何其他子元素以及“image-container”元素本身?

此示例中的输出应为:

<p>
    <moredepth>
        <...>

            <p>text1</p>
            <li>text2</li>
        </...>
    </moredepth>
</p>
Run Code Online (Sandbox Code Playgroud)

PS是否可以使用CSS进行这样的选择?

hel*_*cha 5

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

A:从 下降的元素//div[contains(@class, 'post-content')],不包括当前元素(因为您不想要 root div):

//*[ancestor::div[contains(@class, 'post-content')]]
Run Code Online (Sandbox Code Playgroud)

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

//*[not(ancestor-or-self::*[contains(@class, 'image-container')])] 
Run Code Online (Sandbox Code Playgroud)

这两组的交集是您问题的解决方案。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')])]) ]
Run Code Online (Sandbox Code Playgroud)

这将从您的示例代码中选择以下元素:

/div/p
/div/p/moredepth
/div/p/moredepth/...
/div/p/moredepth/.../p
/div/p/moredepth/.../li
Run Code Online (Sandbox Code Playgroud)

排除spandiv不需要的类及其后代匹配的 和 。

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


Mat*_*ler 3

一旦路径表达式将 XML 片段返回给您,XPath 就不允许对其进行操作。因此,您不能选择moredepth

//moredepth
Run Code Online (Sandbox Code Playgroud)

没有得到所有该元素节点的结果,包括您想要排除的所有后代节点:

<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>
Run Code Online (Sandbox Code Playgroud)

你能做的就是只选择 的子节点moredepth

//div[contains(@class, 'post-content')]/p/moredepth/*[not(contains(@class,'image-container'))]
Run Code Online (Sandbox Code Playgroud)

这将产生(各个结果用 分隔-------):

<p>text1</p>
-----------------------
<li>text2</li>
Run Code Online (Sandbox Code Playgroud)