Запрос Xpath не вернет результаты

Я пытаюсь вернуть некоторые результаты из запроса Xpath, но он не будет правильно выбирать элементы. Я использую следующий код:

public function getTrustPilotReviews($amount)
{
$trustPilotUrl = 'https://www.trustpilot.co.uk/review/purplegriffon.com';
$html5 = new HTML5;
$document = $html5->loadHtml(file_get_contents($trustPilotUrl));
$document->validateOnParse = true;
$xpath = new DOMXpath($document);
$reviewsDomNodeList = $xpath->query('//div[@id="reviews-container"]//div[@itemprop="review"]');
$reviews = new Collection;

foreach ($reviewsDomNodeList as $key => $reviewDomElement)
{
$xpath = new DOMXpath($reviewDomElement->ownerDocument);

if ((int) $xpath->query('//*[@itemprop="ratingValue"]')->item($key)->getAttribute('content') >= 4)
{
$review = [
'title'     => 'Test',
'author'    => $xpath->query('//*[@itemprop="author"]')->item($key)->nodeValue,
'date'      => $xpath->query('//*[@class="ndate"]')->item($key)->nodeValue,
'rating'    => $xpath->query('//*[@itemprop="ratingValue"]')->item($key)->nodeValue,
'body'      => $xpath->query('//*[@itemprop="reviewBody"]')->item($key)->nodeValue,
];

$reviews->add((object) $review);
}
}

return $reviews->take($amount);
}

Этот код ничего не вернет:

//div[@id="reviews-container"]//div[@itemprop="review"]

Но если я изменю это на:

//*[@id="reviews-container"]//*[@itemprop="review"]

Это частично работает, но не возвращает правильные результаты.

0

Решение

Похоже, вы используете HTML5-PHP библиотека. Если вам нужно, вы должны использовать пространства имен. Библиотека загружает HTML5 в документ XHTML. Вы можете проверить это, если сохраните документ DOM в формате XML. Вывод будет примерно таким:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
...
</html>

Поэтому, если вы используете XPath, вам нужно зарегистрироваться и задать префикс для пространства имен XHTML и использовать его для имен элементов.

...
$xpath = new DOMXPath($document);
$xpath->registerNamespace('x', 'http://www.w3.org/1999/xhtml');

$reviewNodes= $xpath->evaluate(
'//x:div[@id="reviews-container"]//x:div[@itemprop="review"]'
);
foreach ($reviewNodes as $reviewNode) {
...
}
...

У вас есть условие внутри цикла, которое может быть частью внешнего XPath, используемого для получения отзывов:

$expression =
'//x:div[@id="reviews-container"]
//x:div[
@itemprop="review" and
(.//*[@itemprop = "ratingValue"]/@content > 4)
]'

Не использовать DOMXPath::query() но DOMXPath::evaluate()Позволяет получить скаляры напрямую. Вторым аргументом для методов является контекстный узел. Используйте относительные пути расположения (без / в начале выражения).

 ...
foreach ($reviewNodes as $reviewNode) {
$review = [
'title' => 'Test',
'author'=> $xpath->evaluate('string(.//*@itemprop="author"])', $reviewNode),
'date'=> $xpath->evaluate('string(.//*[@class="ndate"])', $reviewNode),
'rating'=> $xpath->evaluate('string(.//*[@class="ratingValue"])', $reviewNode),
'body'=> $xpath->evaluate('string(.//*[@class="reviewBody"])', $reviewNode)
];
...
}
4

Другие решения

Благодаря Viper-7, biberu и salathe в ## php IRC я ​​теперь работаю с использованием:

public function getTrustPilotReviews($amount)
{
$context = stream_context_create(array('ssl' => array('verify_peer' => false)));

$url = 'https://www.trustpilot.co.uk/review/purplegriffon.com';
$data = file_get_contents($url, false, $context);

libxml_use_internal_errors(true);

$doc = new \DOMDocument();
$doc->loadHTML($data);

$xpath = new DOMXpath($doc);

$reviews = new Collection;

foreach($xpath->query('//div[@id="reviews-container"]/div[@itemprop="review"]') as $node)
{
$xpath = new DOMXpath($doc);
$rating = $xpath->query('.//*[@itemprop="ratingValue"]', $node)->item(0)->getAttribute('content');

if ($rating >= 4)
{
$review = [
'title'     => $xpath->evaluate('normalize-space(descendant::*[@itemprop="headline"]/a)', $node),
'author'    => $xpath->evaluate('normalize-space(descendant::*[@itemprop="author"])', $node),
'date'      => $xpath->evaluate('normalize-space(descendant::*[@class="ndate"])', $node),
'rating'    => $xpath->evaluate('number(descendant::*[@itemprop="ratingValue"]/@content)', $node),
'body'      => $xpath->evaluate('normalize-space(descendant::*[@itemprop="reviewBody"])', $node),
];

$reviews->add((object) $review);
}
}

return $reviews->take($amount);
}
0

По вопросам рекламы [email protected]