W3docs

xpath()

SimpleXMLElement::xpath() выполняет XPath-запрос к XML-документу, загруженному расширением SimpleXML PHP.

Введение

SimpleXMLElement::xpath() выполняет XPath-запрос к XML-документу, загруженному расширением SimpleXML в PHP, и возвращает совпадающие узлы. Без него можно обходить XML-дерево только по свойствам ($xml->book->title); с его помощью можно перейти сразу к любому узлу — на любой глубине — используя единственное путевое выражение, например //book/title.

На этой странице описано, что возвращает xpath(), наиболее часто используемый синтаксис XPath, как читать атрибуты и работать с пространствами имён, а также типичные подводные камни.

Синтаксис

public SimpleXMLElement::xpath(string $expression): array|false
  • $expression — XPath-выражение для вычисления, относительное к узлу, на котором оно вызывается.
  • Возвращаетмассив объектов SimpleXMLElement для каждого совпадающего узла, пустой массив, если ничего не найдено, или false при некорректном выражении.

Поскольку результат всегда является массивом, его обычно перебирают с помощью foreach, даже если ожидается единственное совпадение.

Первый пример

В приведённых ниже примерах используется simplexml_load_string(), чтобы их можно было запустить без внешнего файла:

<?php

$data = <<<XML
<library>
    <book genre="fiction">
        <title>The Pragmatic Programmer</title>
        <author>Hunt</author>
    </book>
    <book genre="reference">
        <title>PHP Cookbook</title>
        <author>Sklar</author>
    </book>
</library>
XML;

$xml = simplexml_load_string($data);

// Select every <title> anywhere under the root.
foreach ($xml->xpath('//title') as $title) {
    echo $title . "\n";
}

Вывод:

The Pragmatic Programmer
PHP Cookbook

//title означает «любой элемент title на любой глубине». Цикл выводит каждый результат; приведение SimpleXMLElement к строке (выполняемое неявно через echo) возвращает текстовое содержимое элемента.

Распространённые XPath-выражения

ВыражениеВыбирает
/library/bookэлементы book, являющиеся прямыми дочерними элементами корневого library
//bookкаждый элемент book на любой глубине
//book/titleдочерний элемент title каждого book
//book[1]первый book (индексация в XPath начинается с 1, а не с 0)
//book[@genre='fiction']книги, у которых атрибут genre равен fiction
//book[author='Sklar']книги с дочерним элементом <author> со значением Sklar
//@genreкаждый узел-атрибут genre

Фильтрация с помощью предиката

Предикат в квадратных скобках оставляет только узлы, соответствующие условию:

<?php

$data = <<<XML
<library>
    <book genre="fiction"><title>Dune</title></book>
    <book genre="reference"><title>PHP Cookbook</title></book>
</library>
XML;

$xml = simplexml_load_string($data);

$fiction = $xml->xpath("//book[@genre='fiction']");
echo $fiction[0]->title . "\n";  // Dune
echo count($fiction) . " match\n"; // 1 match

Вывод:

Dune
1 match

Чтение атрибута внутри предиката использует @, а чтение атрибута из результирующего узла — синтаксис массива: (string) $book['genre']. Подробнее см. атрибуты.

Работа с пространствами имён XML

Если документ объявляет пространства имён, простой путь вроде //book вернёт ничего — парсеру нужен префикс пространства имён. Сначала зарегистрируйте префикс с помощью registerXPathNamespace(), а затем используйте его в выражении:

<?php

$data = <<<XML
<lib:library xmlns:lib="http://example.com/lib">
    <lib:book><lib:title>Clean Code</lib:title></lib:book>
</lib:library>
XML;

$xml = simplexml_load_string($data);
$xml->registerXPathNamespace('l', 'http://example.com/lib');

foreach ($xml->xpath('//l:book/l:title') as $title) {
    echo $title . "\n";  // Clean Code
}

Вывод:

Clean Code

Зарегистрированный префикс (l) является локальным для вашего запроса — он не обязан совпадать с префиксом, используемым в документе (lib); должен совпадать только URI пространства имён.

Подводные камни

  • Всегда проверяйте результат. xpath() возвращает false при некорректном выражении и пустой массив при отсутствии совпадений. Конструкция foreach (($xml->xpath($e) ?: []) as $n) защищает от обоих случаев.
  • Результаты — это объекты, не строки. Используйте приведение (string), когда нужен текст: (string) $node.
  • XPath индексируется с 1. //book[1] — первая книга; [0] не существует.
  • Важен контекст. Вызов xpath('title') на узле book выполняет поиск относительно этого узла, тогда как ведущий / или // выполняет поиск от корня документа независимо от места вызова.

Заключение

SimpleXMLElement::xpath() превращает глубокий, повторяющийся обход дерева в единственный декларативный запрос. В сочетании с предикатами и регистрацией пространств имён он позволяет точно указывать нужные узлы. Используйте его вместе с simplexml_load_string() или расширенным API SimpleXML для чтения и преобразования XML всего в нескольких строках.

Практика

Практика
Для чего используется XPath в PHP?
Для чего используется XPath в PHP?
Was this page helpful?