Я пытаюсь проанализировать удаленный файл XML, который действителен:
$xml = simplexml_load_file('http://feeds.feedburner.com/HammersInTheHeart?format=xml');
Корневой элемент – это feed
, и я пытаюсь его захватить с помощью:
$nodes = $xml->xpath('/feed'); //also tried 'feed', without slash
Кроме того, он не находит никаких узлов.
print_r($nodes); //empty array
Или любые узлы любого типа, если я ищу их по имени тега, на самом деле:
$nodes = $xml->xpath('//entry'); print_r($nodes); //empty array
Однако он находит узлы, если я использую подстановочные знаки, например
$nodes = $xml->xpath('/*/*[4]'); print_r($nodes); //node found
Что происходит?
В отличие от DOM, SimpleXML не имеет понятия объекта документа, а только элементов. Поэтому, если вы загружаете XML, вы всегда получаете элемент документа.
$feed = simplexml_load_file($xmlFile); var_dump($feed->getName());
Вывод:
string(4) "feed"
Это означает, что все выражения Xpath должны относиться к этому элементу или абсолютному. Простая feed
не будет работать, поскольку контекст уже является элементом feed
.
Но вот еще одна причина. URL-адрес является фидом Atom. Итак, элементы XML в пространстве имен http://www.w3.org/2005/Atom
. Магический синтаксис SimpleXMLs распознает пространство имен по умолчанию для некоторых вызовов, но Xpath этого не делает. Здесь нет пространства имен по умолчанию в Xpath. Вам нужно будет зарегистрировать их с префиксом и использовать этот префикс в выражениях Xpath.
$feed = simplexml_load_file($xmlFile); $feed->registerXpathNamespace('a', 'http://www.w3.org/2005/Atom'); foreach ($feed->xpath('/a:feed/a:entry[position() < 3]') as $entry) { var_dump((string)$entry->title); }
Вывод:
string(24) "Sharing the goals around" string(34) "Kouyate inspires Hammers' comeback"
Однако в SimpleXML регистрация должна выполняться для каждого объекта, на который вы вызываете метод xpath()
.
Использование Xpath с DOM немного отличается, но намного более мощным.
$document = new DOMDocument(); $document->load($xmlFile); $xpath = new DOMXpath($document); $xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom'); foreach ($xpath->evaluate('/a:feed/a:entry[position() < 3]') as $entry) { var_dump($xpath->evaluate('string(a:title)', $entry)); }
Вывод:
string(24) "Sharing the goals around" string(34) "Kouyate inspires Hammers' comeback"
Выражение Xpath с использованием DOMXpath::evaluate()
может возвращать скалярные значения.