php 8 中的 xpath 如何处理?

Posted

技术标签:

【中文标题】php 8 中的 xpath 如何处理?【英文标题】:How does xpath in php 8 deal with  ? 【发布时间】:2022-01-20 23:45:29 【问题描述】:

我正在尝试使用纯 php 废弃 Wikipedia 页面,并一直在使用 xpath->query 搜索 dom。我正在尝试在此***页面https://en.wikipedia.org/wiki/Ajmal_Kasab 上选择具有文本Known for 的节点,该文本位于文本2008 Mumbai attacks 之前的右侧表格中。我用DOMDocument::loadhtml 加载了页面,然后执行了以下操作:

var_dump( $value->saveHTML($xpath->query( "//table[@class[contains(.,'infobox')]]//tr[th='Known for']/th/text()" )[0])  ); 

我尝试了Known\x20forKnown forKnown for 等。但它们没有用。幸运的是,我偶然发现了这篇 Using XPATH to search text containing   帖子,并尝试在我的 windows 10 电脑上的 sublime 3 编辑器中手动按下 Alt + 0160。表达式看起来像这样Known<0xa0>for——它起作用了。

我的问题 1 是为什么 xpath 不接受普通空格 或文字  ?***页面源将其命名为Known for。如果我有 Linux 或其他文本编辑器怎么办?目前,我在本地工作,它也可以在我的基于 Linux 的服务器上工作吗?这背后的计算机科学是什么?

其次我需要将包含空格的xpath 结果集转换为存储<0xa0> 的php 变量。我有:

$tmp = $xpath->query("//table[@class[contains(.,'infobox')]]//tr[th='Known<0xa0>for']/th/text()");
$tmp = $domDomoc->saveHTML($tmp[0]);
$result = $xpath->query("//table[@class[contains(.,'infobox')]]//tr[th='$tmp']/td/text()");

似乎变量$tmp 不符合&lt;0xa0&gt; 并且反过来$result 不正确(错误)。

整个php代码比较复杂,要搜索的词很多。所以我把代码归结为一个更简单的任务。像Known for 这样的词是动态的并被输入到函数中。

【问题讨论】:

&amp;nbsp;与Unicode non-breaking space不一样,后者与传统空间不一样。你可以试试text normalization techniques 或者RegEx 【参考方案1】:

您声称“***页面源将其命名为 Known&amp;#160for”,这根本不是真的,它具有 Known&amp;#160;for。其次,您将&amp;#160 称为文字,即使您的意思是&amp;#160;,这也不是文字,它是HTML 数字字符引用,即HTML 必须不使用文字字符的转义机制。当然,您的 XPath 不适用于 HTML 源代码,您已将字符串提供给 loadHtml 方法,该方法使用 HTML 解析器来解析 HTML 源字符串,因此生成的 DOM 树肯定没有任何表示&amp;#160;&amp;nbnsp; 的形式,它只有一个带有 Unicode 字符的文本节点,其中之一是带有十进制 Unicode 160 或十六进制 U00A0 的字符。

XPath 和 PHP 都不需要您将 PHP 字符串文字 (https://www.php.net/manual/en/language.types.string.php) 中的该字符转义为 &lt;0xa0&gt;,它应该是 \xA0

对于问题的第二部分,您希望从$xpath-&gt;query("//table[@class[contains(.,'infobox')]]//tr[th='Known&lt;0xa0&gt;for']/th/text()") 获得什么样的价值?一个 DOM 节点列表?通过将该变量放入 $xpath-&gt;query("//table[@class[contains(.,'infobox')]]//tr[th='$tmp']/td/text()") 中的另一个 PHP 字符串文字中,您希望实现什么?

如果您想从 XPath 评估中获取 PHP 字符串,请使用不返回节点而是返回字符串的表达式(string(//th) 将返回具有第一个 th 元素的字符串值的字符串)并使用 @987654335 @ 方法,而不是 query 方法,例如

$doc = new DOMDocument();
$doc->loadHTML(file_get_contents('https://en.wikipedia.org/wiki/Ajmal_Kasab'));
$xpath  = new DOMXPath($doc);
$value = $xpath->evaluate("string(//tr[th = 'Known\u00A0for']/td)");
echo $value;

【讨论】:

#1 &amp;#160 是一个错字,我的意思是&amp;#160;。 #2 在要查询的表达式中输入 \xA0 不起作用,而是 \xc2\xa0 起作用(可能是因为我的 php 文件以 utf-8 格式保存)。 #3 我修复了 question-2 中的代码。 #4..[待续...] #4 这是我的理解,$xpath = new DomXPath("&lt;html&gt;&amp;#0160;&lt;/html&gt;"); $xpath-&gt;query("\xc2\xa0") 首先抓取已解析并因此转换为 utf 字符串的 html 输出。现在,query 尝试将该 html 输出与我的表达式相匹配。所以我的表达式应该与预期的浏览器的 html 输出相同,即 utf 字符串。 目前还不清楚你想实现什么,我猜你想用th 识别trKnown for,然后访问兄弟td 单元格。但这没有文本节点子节点,而是包含一个链接。因此,似乎使用单个表达式来选择 //tr[th='Known\u00A0for']/td 就足以为您提供 td 我以不同的方式完成了第二部分。我有一个函数,它接受Known\xc2\xa0forBornDied 等作为参数,然后返回它们对应的td 值。我只是使用$intro["td"] = $intro["th"][0]-&gt;nextSibling;。最初(在我的问题中)我使用的是 $domDomoc-&gt;saveHTML($tmp[0]); 这个,但似乎 saveHTML\xc2\xa0 转换为普通空格 utf 字符。【参考方案2】:

XPath 被设计为托管在其他编程语言(在您的情况下为 PHP)中,并且它没有自己的转义约定,而是依赖于宿主语言的转义约定。因此,您在 XPath 表达式中输入 NBSP (xa0) 字符的方式与在任何其他 PHP 字符串文字中输入的方式相同,例如 \xA0

&amp;#xa0; 适用于 XPath 托管在 XML 中,&amp;nbsp; 适用于托管在 HTML 中,但不适用于托管在 PHP 中。

您问“这背后的计算机科学是什么?”。基本上,这是为了避免双重转义问题。当诸如正则表达式之类的子语言具有转义约定(例如,\\ 代表\)然后以具有类似转义约定的另一种语言托管时,您最终不得不将\ 写为\\\\(或@ 987654328@ 为&amp;amp;amp;)。由于 XPath 是专门为在其他语言中托管而设计的,因此他们决定使用宿主语言转义功能而不是叠加自己的功能。

【讨论】:

因此,在 XPath 表达式中输入 NBSP (xa0) 字符的方式与在任何其他 PHP 字符串文字中输入的方式相同。好的,我可以通过按空格在php中编写NBSP,即` `,但这在xpath表达式中不起作用。 按空格键肯定会给你一个普通的空格,而不是一个不间断的空格。

以上是关于php 8 中的 xpath 如何处理?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 PHP 请求中的长标头声明?

PHP如何处理jquery post过来的$serialize数据

20 个案例教你在 Java 8 中如何处理日期和时间?

C++:如何处理 NULL 值(例如来自数据库)?

PHP 中如何处理并发请求(使用线程、线程池或子进程)

PHP/GD:如何处理 jpg 透明度?