DOMXPath查询包含Unicode字符的属性

3

是否可以访问包含Unicode类名的元素?

实际上,我正在访问这个网站,但它们的类名以Unicode字符U+1F41D HONEYBEE为前缀。

$html = file_get_contents('https://www.honestbee.my/en/groceries/stores/bens-independent-grocer/products/720365');
$doc = new \DOMDocument();
$doc->loadHTML($html);

$xpath = new \DOMXpath($doc);

$elements = $xpath->query("//[@class='ap0']");
if (!is_null($elements)) {
    foreach ($elements as $element) {
        echo "<br/>[". $element->nodeName. "]";

        $nodes = $element->childNodes;
        foreach ($nodes as $node) {
            echo $node->nodeValue. "\n";
        }
    }
}

很遗憾,它抛出了错误。

ErrorException  : DOMXPath::query(): Invalid expression                                                                                                     
 at /paht/to/test-dom.php:83                                                                        
   79|         $doc->loadHTML($html);                                       
   80|                                                                      
   81|         $xpath = new \DOMXpath($doc);                                
   82|                                                                      
 > 83|         $elements = $xpath->query("//[@class='ap0']");             
   84|         if (!is_null($elements)) {                                   
   85|             foreach ($elements as $element) {                        
   86|                 echo "<br/>[". $element->nodeName. "]";              
   87|                                                                      

Exception trace:

1   DOMXPath::query("//[@class='ap0']")                                  
    /paht/to/test-dom.php:83

我指的是这里的表情编码,尝试使用\uD83Dap0也不起作用。


你试过使用"//[@class='&#x1F41D;ap0']"吗?我不确定你从哪里得到了D83D,因为它是一个不同的字符。 - miken32
尝试了几种不同的方法,似乎没有什么作用。我最接近的是 $elements = $xpath->query("//*[@class[contains(., 'ap0')]]"); - miken32
@miken32 谢谢。但是 contains 不能确保目标元素正确。 - Js Lim
3个回答

4

我之前深入研究了字符编码等相关知识,在尝试$doc->saveHTML()时发现所有的Unicode字符都被破坏了。我的猜测是DOMDocument::loadHTML将一切视为ISO-8859-1,这是HTML 4的默认编码。因此,通过添加XML文档声明我们可以欺骗它以UTF-8解析。这样就可以通过类名搜索,无论它使用了哪些字符:

<?php
$html = file_get_contents('https://www.honestbee.my/en/groceries/stores/bens-independent-grocer/products/720365');
$prologue = '<?xml encoding="UTF-8">';
$doc = new \DOMDocument();
$doc->loadHTML($prologue . $html);
$xpath = new \DOMXpath($doc);
$elements = $xpath->query("//div[@class='ap0']");
foreach ($elements as $element) {
    echo "<br/>[". $element->nodeName. "]";
    $nodes = $element->childNodes;
    foreach ($nodes as $node) {
        echo $node->nodeValue. " \n";
    }
}

值得注意的是,您遇到的“无效表达式”错误并不是由于bee造成的,而是因为您没有在查询中指定元素名称。在我的答案中,我使用了div,如果您想搜索所有元素,可以使用*。请保留HTML标记。

你的回答救了我! - Benjamin
我在从HTML读取Unicode文本时遇到了编码问题。你的回答很有帮助!谢谢! - Khaled
你救了我的命。 - undefined

0

实际上我正在使用Rct567/DomQuery。作者已经修复了这个问题。

对于那些遇到同样问题的人,我建议使用这个包。


0

一个解决方法是将特定的已知的Unicode字符属性替换为ASCII字符串。在执行XPATH查询之前,即时进行此操作。

例如:$html = preg_replace("/ap0/u", 'Beeap0123456', $html);

或者,str_replace函数应该能够用映射数组替换Unicode属性名称数组。

然后,XPATH查询表达式将是一个直接的ASCII表达式:'//*[@class="Beeap0123456"]'

(在替换的ASCII字符串中添加一个唯一的字符串可能会减少文档包含其他类似属性时的混淆机会。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接