Перейти к основному содержимому

XPath

Разработчику Аналитику Тестировщику

Введение​

XPath (XML Path Language) — язык адресации узлов в XML- и HTML-подобных деревьях. XPath используют в XSLT, XQuery, Schematron, в API .NET (XmlDocument.SelectNodes), Java (javax.xml.xpath), в тестах и инструментах (xmlstarlet, браузерные DevTools).

Базовый XML для примеров ниже:

<library>
<book id="1" genre="classic">
<title>Война и мир</title>
<author>Лев Толстой</author>
<price>450</price>
</book>
<book id="2" genre="novel">
<title>Мастер и Маргарита</title>
<author>Михаил Булгаков</author>
<price>380</price>
</book>
</library>

Основы XML: глава XML. Синтаксис XPath в XSLT-паттернах (match) — XSLT.


Терминология​

ТерминОписание
Узел (node)Элемент, атрибут, текст, комментарий, PI, корень документа
Контекстный узелУзел, относительно которого вычисляется выражение
Контекстная позицияПорядковый номер среди узлов, отобранных предыдущим шагом
Контекстный размерОбщее число таких узлов
Шаг (step)Ось + тест узла, например child::book
Путь (location path)Цепочка шагов: /library/book/title
ПредикатУсловие в [...], сужающее набор узлов
Последовательность узловУпорядоченный набор узлов (результат многих выражений)

Типы узлов в XPath 1.0:

  • element, attribute, text, comment, processing-instruction, namespace, root

Синтаксис путей​

Абсолютный и относительный путь​

ЗаписьСмысл
/libraryОт корня документа к элементу library
bookДочерние book контекстного элемента
//authorВсе author на любой глубине (ось descendant-or-self)
.Текущий контекстный узел
..Родитель (parent::node())
@idАтрибут id текущего элемента
text()Текстовые дочерние узлы

Примеры к документу выше:

/library/book /* все книги */
/library/book[1]/title /* заголовок первой книги */
/library/book[@id='2'] /* книга с id=2 */
//author /* оба автора */
//book[price > 400]/title /* дорогие книги — заголовки */

Тесты узлов​

ТестПример
По имени элементаbook, title
По имени атрибута@genre
Универсальный* (любой элемент), @* (любой атрибут)
По типу узлаnode(), text(), comment()
По локальному имени с NSВ XPath 2.0+ — QName; в 1.0 часто префиксы в документе

Оси (axes)​

Ось задаёт направление обхода дерева относительно контекстного узла.

ОсьСокращениеЧто выбирает
child(по умолчанию)Прямые дочерние элементы
attribute@Атрибуты
descendantВсе потомки
descendant-or-self// в начале шагаУзел и все потомки
parent..Родитель
ancestorВсе предки
ancestor-or-selfУзел и предки
following-siblingСледующие соседи
preceding-siblingПредыдущие соседи
followingВсе узлы после в документе
precedingВсе узлы до в документе
self.Сам контекстный узел
namespaceУзлы пространств имён

Полная запись шага: ось::тестузла[предикат].

/descendant::book[@genre='classic']/child::title
ancestor::library
following-sibling::book[1]

Базис: Операторы — оператор, операнд и приоритет в коде.


Операторы и выражения​

Сравнение и логика​

ОператорПример
=, !=[@id='2'], [author != '']
<, <=, >, >=[price > 400] (числа — если типизировано; в 1.0 часто лексикографически)
and, or, not()[genre='novel' and price < 400]

Арифметика (XPath 1.0 — над числами в выражениях)​

+, -, *, div, mod — например //book[position() mod 2 = 1] (нечётные позиции).


Объединение путей​

| — объединение двух наборов узлов:

//book/title | //book/author

Полезные функции (XPath 1.0)​

ФункцияНазначение
position()Позиция в текущем списке
last()Размер списка
count(//book)Число узлов
contains(s, sub)Подстрока
starts-with(s, p)Префикс строки
normalize-space(s)Обрезка пробелов
string(), number(), boolean()Приведение типов
concat(a, b, ...)Склейка строк
//book[contains(author, 'Толстой')]
//book[last()]/title
count(//book[@genre='novel'])

XPath 2.0/3.0 (XQuery, Saxon, современный .NET) добавляют типы, регулярные выражения, for, if, последовательности — см. справочник по XML (раздел XDM).


XPointer — адрес фрагмента в URI​

XPath выбирает узлы внутри уже загруженного документа. XPointer (XML Pointer Language) решает другую задачу: указать фрагмент XML в URL — "возьми не весь chapter.xml, а элемент с id="intro"".

Схема:

https://example.com/doc.xml#xpointer(id('intro'))
https://example.com/doc.xml#xpointer(/book/chapter[3])

XPointer опирается на XPath и расширяет его термами (в ранних спецификациях W3C):

ТермНазначение
id('name')Элемент с атрибутом типа ID или xml:id="name"
element(/1/2/3)Путь по номерам дочерних элементов от корня
xpointer(expr)Обёртка над XPath-выражением
xmlns(...)Объявление префикса для XPath внутри URI

Пример для документа с отделами:

<company>
<department id="sales">
<employee><name>Sarah Bellum</name></employee>
</department>
<department id="marketing">...</department>
</company>
XPointerЧто выберет
id('sales')<department id="sales">
xpointer(//employee[1]/name)Первый <name> среди сотрудников
xpointer(/company/department[2])Второй отдел

XInclude использует XPointer в атрибуте xpointer, когда нужен не весь включаемый файл:

<xi:include href="chapter1.xml" xpointer="xpointer(//*[@id='summary'])"/>

Современный стандарт — XPointer Framework и элементные схемы (element()); поддержка в инструментах неравномерна. Для новых проектов чаще включают целые файлы через XInclude или собирают документ в коде. Подробнее — справочник по XML, XLink.

ID и IDREF (DTD) и xml:id — простой способ пометить якорь без полного XPointer: href="doc.xml#section-3" работает, если у элемента id="section-3".


Практические примеры​

ЗадачаВыражение
Все идентификаторы книг//book/@id
Первая книга(//book)[1] или //book[1] *
Книги без цены//book[not(price)]
Суммарно жанры//book/@genre
Заголовок родительской книги для author//author/ancestor::book/title

* В XPath 1.0 //book[1] — первая книга в каждом контексте предиката; для "первой в документе" надёжнее (//book)[1].

Чит-лист: cheatsheets.zip/xpath

Play ITЗагрузка интерактивного демо…


Где применяется XPath​

  • XSLT — атрибуты select, match, test;
  • XPointer / XInclude — фрагмент документа в URI;
  • XSD 1.1 — ограничения assert;
  • Schematron — правила валидации;
  • Тестирование API — проверка тела SOAP/XML;
  • Конфигурации — Spring, Maven, MSBuild (внутренние селекторы в плагинах);
  • Браузер — оценка XPath в консоли для XML/SVG.
Практическое задание

По XML-библиотеке выше напишите запросы: (1) все цены; (2) книги дороже 400; (3) заголовок книги с id=2; (4) число книг жанра novel. Проверьте в демо на этой странице.