【问题标题】:How to compare conetent with two tags using Xpath如何使用 Xpath 将内容与两个标签进行比较
【发布时间】:2021-05-23 18:30:32
【问题描述】:

我有以下 $html 内容的场景。我想检查 html 内容是否以没有任何文本内容的媒体(图像或视频、iframe)开头,如第三种情况。

//第一个p标签和图片标签之间没有内容

   $html =  '<p dir="ltr"><img src="imageurl"  class="img"><br></p>
    <div>some content </div>';

//第一个p标签和video标签之间没有内容

 $html =  '<p dir="ltr"><video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video></p>
<div>some content </div>';

//在第一个 p 标签内有内容

 $html =  '<p dir="ltr">here we have text<img src="imageurl"  class="img"><br></p>
<div>some content </div>';

我试过这样但没有运气,请指教

$dom = new DOMDocument();
$dom->loadHTML($html);//that's HTML of my document, string
$xpath = new DOMXPath($dom);
$xpath_resultset =  $xpath->query("p/following-sibling::node()[not(preceding-sibling::img) and not(self::img)]");

【问题讨论】:

  • 那么这三种场景你想接受哪一种呢?
  • 我的问题中提到的 @endeavour first 2 html 输出是真实场景,第三个 html 输出在第一个

    标签与

    之间有内容

标签: php html xpath


【解决方案1】:

由于 p 是根节点,所以需要在开头添加一个斜杠。

如果第一个内容是带有文本的 text(),则检查 p

/p[node()[1][self::text()][normalize-space()!='']]

如果第一个内容(忽略空格)是 img 或 video,则检查 p

/p[(video|img)[not(preceding-sibling::text()[normalize-space()!=''])]]

两个 XPath 都将忽略子节点之间的非预期空白。

也就是说,如果 p 是这样的:

<p dir="ltr"> <img src="imageurl"  class="img"/><br/></p>

第二个 XPath 会找到它,而不是第一个。

如果你想匹配一个完整的 html 文件中的所有 p,你可以使用:

//p[node()[1][self::text()][normalize-space()!='']]

//p[(video|img)[not(preceding-sibling::text()[normalize-space()!=''])]]

【讨论】:

  • 我没有在我的回答中考虑“意外空白”的情况。感谢您了解这一点。
  • @Siebe Jongebloed 我试过了,但它没有给我输出 false 。请指教 $html = '


    '; $dom = 新的 DOMDocument(); $dom->loadHTML($html);//这是我的文档的HTML,字符串 $xpath = new DOMXPath($dom); $result = $xpath->query("p[(video|img)[not(preceding-sibling::text()[normalize-space()!=''])]]"); var_dump($result);死;
  • XPath 缺少斜杠。
  • 最初的问题并不完全清楚“内容”是什么意思。我意识到纯文本是非常隐含的,但是像这样的场景呢:&lt;p dir="ltr"&gt;&lt;b&gt;content&lt;/b&gt;&lt;img src="imageurl" class="img"/&gt;&lt;br/&gt;&lt;/p&gt;&lt;div&gt;some content &lt;/div&gt;。当我回复(任何内容)时,我正在考虑这种情况。
  • @candishdd:前面有斜线还有什么运气吗?
【解决方案2】:

尚不完全清楚您要定位哪个元素(p、img 或视频),或者您是否只是希望 XPath 在不符合您的要求时不选择任何内容,因此无论是什么都无关紧要满足要求时选择。

如果选择 p 是可以接受的,那么这种方法应该可行。

p[./((node() | text())[1][self::img or self::video])]

如果在其所有元素/文本子项中,第一个子项是 img 或 video,则选择 p。

如果您需要选择第一个子项(img 或视频),则稍微移动一下表达式即可:

p/(((node() | text())[1][self::img or self::video]))

如果它是一个 img/video 元素,则返回 p 的第一个元素/文本子元素。

我希望如何修改它以包含 iframe(如原始问题中所述)是不言自明的。

【讨论】:

  • 如果下一个兄弟是图像或视频,我想检查第一个

    标签是否没有任何内容。 (检查

    vs

    vs

  • 我试过这样的 //p[@dir='ltr'][1]/text()/following-sibling::img 或 //p[@dir='ltr' ][1]/text()/following-sibling::video 但对我不起作用
  • 请向我展示一个您正在考虑的场景,其中我的建议未能满足您的要求。如果在第一个 img 或 video 之前有任何文本或节点,这些表达式将无法选择任何内容。
  • @DavidDenenberg 由于 text() 是 node() 的一种,所以使用 node() 就足够了。见即*.com/a/11744783/3710053
最近更新 更多