Атрибут запроса DOMXPath, содержащий символ 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 не работает


person Js Lim    schedule 11.04.2019    source источник
comment
Вы пробовали "//[@class='&#x1F41D;ap0']"? Не уверен, где вы взяли D83D, это другой персонаж.   -  person miken32    schedule 11.04.2019
comment
Пробовал несколько разных вещей, ничего не работает. Ближайшее, что у меня было, было $elements = $xpath->query("//*[@class[contains(., 'ap0')]]");   -  person miken32    schedule 11.04.2019
comment
@miken32 Спасибо. Но contains не может убедиться, что нацеливается на правильный элемент   -  person Js Lim    schedule 11.04.2019


Ответы (3)


Ну, я прошелся по кроличьей норе кодировок символов и еще много чего, прежде чем попробовать $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";
    }
}

Также стоит отметить, что ваша ошибка «недопустимое выражение» возникла не из-за пчелы, а из-за того, что в вашем запросе не было имени элемента. В своем ответе я использовал div, если вы хотите найти все элементы, которые вы можете использовать *.

person miken32    schedule 12.04.2019
comment
Вы спасли меня этим ответом! - person Benjamin; 13.05.2020
comment
У меня возникла проблема с кодировкой при чтении текста Unicode из HTML. Ваш ответ был полезен! Спасибо! - person Khaled; 01.07.2021

На самом деле я использую Rct567/DomQuery. Автор уже исправил проблему.

Для тех, кто сталкивается с той же проблемой, я рекомендую использовать этот пакет.

person Js Lim    schedule 16.04.2019

Одним из способов обхода является замена определенного известного атрибута символа Юникода строкой ASCII. Делайте это на лету, непосредственно перед выполнением запроса XPATH.

Пример: $html = preg_replace(/????ap0/u, 'Beeap0123456', $html);

Кроме того, функция str_replace должна иметь возможность заменить массив имен атрибутов Unicode сопоставленным массивом имен атрибутов ASCII.

Тогда выражение запроса XPATH будет прямым ASCII-выражением: '//*[@class=Beeap0123456]'

(Добавление уникальной строки к замещающей строке ASCII может снизить вероятность путаницы, если документ содержит другие подобные атрибуты.)

person saeng    schedule 28.06.2020