PHP 8.4中使用Dom\HTMLDocument为何无法通过标签选择器查询元素?
PHP 8.4 Dom\HTMLDocument中XPath查询指定标签返回0的问题
尝试使用PHP 8.4新增的
Dom\HTMLDocument类统计页面中所有div标签数量,编写代码后发现使用//div查询返回0个结果,但//*能找到包含div在内的6个元素。带类名的复杂选择器只要用*代替具体标签就能正常工作,代码如下:
<?php $html = <<<HTML <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Example</title> </head> <body> <div>Hello</div> </body> </html> HTML; $doc = Dom\HTMLDocument::createFromString($html); $xpath = new Dom\XPath($doc); // No divs found: $divs = $xpath->query('//div'); echo $divs->count(); // 0 // 6 elements found, including the div: $anyTags = $xpath->query('//*'); echo $anyTags->count(); // 6
问题出在HTML命名空间上。Dom\HTMLDocument会自动将所有HTML元素放入默认的HTML命名空间(http://www.w3.org/1999/xhtml),但默认创建的Dom\XPath实例不会自动识别这个命名空间,直接用标签名查询时会匹配不到命名空间内的元素。
解决方法
有两种可行的修复方式:
- 注册HTML命名空间并使用带前缀的XPath表达式
$doc = Dom\HTMLDocument::createFromString($html); $xpath = new Dom\XPath($doc); // 注册HTML命名空间,前缀设为html $xpath->registerNamespace('html', 'http://www.w3.org/1999/xhtml'); // 使用带前缀的查询语法 $divs = $xpath->query('//html:div'); echo $divs->count(); // 输出1
- 使用
local-name()匹配标签本地名称
无需注册命名空间,直接通过元素的本地名称进行查询:
$divs = $xpath->query('//*[local-name()="div"]'); echo $divs->count(); // 输出1
第一种方法更规范,适合复杂的XPath查询场景;第二种方法更简洁,适合简单的标签查询需求。
内容的提问来源于stack exchange,提问作者Robo Robok
相关产品推荐
相关产品推荐

