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\x20for
、Known for
和Known for
等。但它们没有用。幸运的是,我偶然发现了这篇 Using XPATH to search text containing 帖子,并尝试在我的 windows 10 电脑上的 sublime 3 编辑器中手动按下 Alt + 0160
。表达式看起来像这样Known<0xa0>for
——它起作用了。
我的问题 1 是为什么 xpath 不接受普通空格
或文字 &#160;
?***页面源将其命名为Known&#160;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
不符合<0xa0>
并且反过来$result
不正确(错误)。
整个php代码比较复杂,要搜索的词很多。所以我把代码归结为一个更简单的任务。像Known for
这样的词是动态的并被输入到函数中。
【问题讨论】:
&nbsp;
与Unicode non-breaking space不一样,后者与传统空间不一样。你可以试试text normalization techniques 或者RegEx
【参考方案1】:
您声称“***页面源将其命名为 Known&#160for
”,这根本不是真的,它具有 Known&#160;for
。其次,您将&#160
称为文字,即使您的意思是&#160;
,这也不是文字,它是HTML 数字字符引用,即HTML 必须不使用文字字符的转义机制。当然,您的 XPath 不适用于 HTML 源代码,您已将字符串提供给 loadHtml
方法,该方法使用 HTML 解析器来解析 HTML 源字符串,因此生成的 DOM 树肯定没有任何表示&#160;
或 &nbnsp;
的形式,它只有一个带有 Unicode 字符的文本节点,其中之一是带有十进制 Unicode 160 或十六进制 U00A0 的字符。
XPath 和 PHP 都不需要您将 PHP 字符串文字 (https://www.php.net/manual/en/language.types.string.php) 中的该字符转义为 <0xa0>
,它应该是 \xA0
。
对于问题的第二部分,您希望从$xpath->query("//table[@class[contains(.,'infobox')]]//tr[th='Known<0xa0>for']/th/text()")
获得什么样的价值?一个 DOM 节点列表?通过将该变量放入 $xpath->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&#160
是一个错字,我的意思是&#160;
。 #2 在要查询的表达式中输入 \xA0
不起作用,而是 \xc2\xa0
起作用(可能是因为我的 php 文件以 utf-8 格式保存)。 #3 我修复了 question-2 中的代码。 #4..[待续...]
#4 这是我的理解,$xpath = new DomXPath("<html>&#0160;</html>"); $xpath->query("\xc2\xa0")
首先抓取已解析并因此转换为 utf 字符串的 html 输出。现在,query
尝试将该 html 输出与我的表达式相匹配。所以我的表达式应该与预期的浏览器的 html 输出相同,即 utf 字符串。
目前还不清楚你想实现什么,我猜你想用th
识别tr
和Known for
,然后访问兄弟td
单元格。但这没有文本节点子节点,而是包含一个链接。因此,似乎使用单个表达式来选择 //tr[th='Known\u00A0for']/td
就足以为您提供 td
。
我以不同的方式完成了第二部分。我有一个函数,它接受Known\xc2\xa0for
、Born
和Died
等作为参数,然后返回它们对应的td
值。我只是使用$intro["td"] = $intro["th"][0]->nextSibling;
。最初(在我的问题中)我使用的是 $domDomoc->saveHTML($tmp[0]);
这个,但似乎 saveHTML
将 \xc2\xa0
转换为普通空格 utf 字符。【参考方案2】:
XPath 被设计为托管在其他编程语言(在您的情况下为 PHP)中,并且它没有自己的转义约定,而是依赖于宿主语言的转义约定。因此,您在 XPath 表达式中输入 NBSP (xa0) 字符的方式与在任何其他 PHP 字符串文字中输入的方式相同,例如 \xA0
。
&#xa0;
适用于 XPath 托管在 XML 中,&nbsp;
适用于托管在 HTML 中,但不适用于托管在 PHP 中。
您问“这背后的计算机科学是什么?”。基本上,这是为了避免双重转义问题。当诸如正则表达式之类的子语言具有转义约定(例如,\\
代表\
)然后以具有类似转义约定的另一种语言托管时,您最终不得不将\
写为\\\\
(或@ 987654328@ 为&amp;amp;
)。由于 XPath 是专门为在其他语言中托管而设计的,因此他们决定使用宿主语言转义功能而不是叠加自己的功能。
【讨论】:
因此,在 XPath 表达式中输入 NBSP (xa0) 字符的方式与在任何其他 PHP 字符串文字中输入的方式相同。好的,我可以通过按空格在php中编写NBSP,即` `,但这在xpath表达式中不起作用。 按空格键肯定会给你一个普通的空格,而不是一个不间断的空格。以上是关于php 8 中的 xpath 如何处理?的主要内容,如果未能解决你的问题,请参考以下文章