XPath

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

XPath (XML Path Language) — язык запросов к элементам XML-документа. Разработан для организации доступа к частям документа XML в файлах трансформации XSLT и является стандартом консорциума W3C. XPath призван реализовать навигацию по DOM в XML. В XPath используется компактный синтаксис, отличный от принятого в XML. В 2007 году завершилась разработка версии 2.0, которая теперь является составной частью языка XQuery 1.0. В декабре 2009 года началась разработка версии 2.1, которая использует XQuery 1.1.

На данный момент самой популярной версией является XPath 1.0. Это связано с отсутствием поддержки XPath 2.0 со стороны открытых библиотек. В частности, речь идёт о LibXML, от которой зависит поддержка языка в браузерах, с одной стороны, и поддержка со стороны серверного интерпретатора, с другой.

Основы[править | править вики-текст]

XML имеет древовидную структуру. В документе всегда имеется корневой элемент (инструкция <?xml version="1.0"?> к дереву отношения не имеет). У элемента дерева всегда существуют потомки и предки, кроме корневого элемента, у которого предков нет, а также тупиковых элементов (листьев дерева), у которых нет потомков. Каждый элемент дерева находится на определенном уровне вложенности (далее — «уровень»). У элементов на одном уровне бывают предыдущие и следующие элементы.

Это очень похоже на организацию каталогов в файловой системе, и строки XPath, фактически, — пути к «файлам» — элементам.

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

Например, рассмотрим XHTML документ:

 1 <html>
 2  <body>
 3     <div>Первый слой
 4       <span>блок текста в первом слое</span>
 5     </div>
 6     <div>Второй слой</div>
 7     <div>Третий слой
 8       <span class="text">первый блок в третьем слое</span>
 9       <span class="text">второй блок в третьем слое</span>
10       <span>третий блок в третьем слое</span>
11     </div>
12     <span>четвёртый слой</span>
13     <img />
14   </body>
15 </html>

XPath-путь /html/body/*/span[@class] (полный синтаксис имеет вид /child::html/child::body/child::*/child::span[attribute::class]) будет соответствовать в нём двум элементам исходного документа — <span class="text">первый блок в третьем слое</span> и <span class="text">второй блок в третьем слое</span>.

Путь делится на шаги адресации, которые разделяются символом «косая черта» /. Каждый шаг адресации состоит из трех частей:

  • ось (в данном примере child::), это обязательная часть;
  • условие проверки узлов (в данном примере это проверки на соответствие элементов документа именам html, body, span, и символ *, который пропустит элемент с любым именем), также обязательная часть;
  • предикат (в данном примере attribute::class), необязательная часть, заключаемая в квадратные скобки, в которой могут содержаться дополнительные условия проверки элементов по другим осям, функции, операторы (+, -, <, > и пр.).

Анализ ведется слева направо. В текущем контексте выбираются элементы указанной в шаге оси, подходящие под указанные условия, и они образуют результат данного шага, который берётся как контекст для следующего шага. Контекст — это некая точка отсчета для осей, относительно которой рассчитывается результат шага адресации.

Если в начале пути не указан символ /, то корневой элемент документа уже на первом шаге будет назначен текущим контекстом, и ось child:: в этом контексте будет содержать его дочерние элементы. В данном примере ось child:: содержала бы один элемент body. Если первый символ пути — /, то путь адресации считается абсолютным (то есть от корня документа), и на первом шаге ось child:: содержит лишь сам корневой элемент. В данном примере child:: на первом шаге содержит элемент html.

Таким образом, первый шаг адресации /child::html явным образом делает текущим контекстом для следующего шага элемент html, что было бы и так сделано неявно, если этот шаг не был обозначен.

На втором шаге адресации (child::body) контекстом является элемент html. Ось child:: говорит о том, что необходимо найти всех непосредственных потомков элемента html, а условие проверки body говорит о том, что в формируемый набор элементов нужно включить все узлы с именем body. В ходе второго шага адресации получаем набор узлов, состоящий всего из одного элемента body, который и становится контекстом для третьего шага.

Третий шаг адресации: child::* . Ось child:: собирает всех непосредственных потомков элемента body, а условие проверки * говорит о том, что в формируемый набор нужно включить элементы основного типа с любым именем. В ходе этого шага получаем набор узлов, состоящий из трех элементов div, одного span и одного элемента img — итого, пять элементов.

Четвёртый шаг адресации: child::span[@class]. Его контекстом является набор из пяти элементов, поэтому следующий набор узлов создается в пять проходов (за пять итераций). При первой итерации узлом контекста становится первый div. Согласно заданной оси child:: и правилу проверки span, в набор должны включаться непосредственные потомки этого div-а, имя которых равно span. Там такой один. При второй итерации в набор ничего добавляться не будет, так как у второго div нет потомков. Третья итерация увидит сразу три элемента span. Четвёртая ничего не увидит, так как у элемента span нет потомков span, а то что он сам span - не важно, ведь просматриваются именно потомки. Пятая тоже ничего не увидит, у элемента img тоже нет потомков span. Итак, в ходе проверки мог бы быть получен набор узлов, состоящий из четырёх элементов span. Это и было бы контекстом для последующей обработки, не будь на этом шаге указано предиката.

Но так как предикат на четвёртом шаге есть, по мере выполнения каждого из пяти проходов будет производиться дополнительная фильтрация отбираемых элементов. В данном случае у предиката ось attribute:: говорит о необходимости проверить, есть ли у отбираемого узла атрибуты, а условие class требует оставить лишь те узлы, у которых задан атрибут с именем class. И поэтому на первой итерации единственный найденный span фильтрацию предикатом не пройдёт, на третьей итерации фильтрацию пройдут два элемента из трёх, и в итоге, не смотря на то, что фильтрация происходит за пять итераций, в окончательный набор попадают только два элемента span.

Оси[править | править вики-текст]

Оси — это база языка XPath. Для некоторых осей существуют сокращённые обозначения.

  • ancestor:: — Возвращает множество предков.
  • ancestor-or-self:: — Возвращает множество предков и текущий элемент.
  • attribute:: — Возвращает множество атрибутов текущего элемента. Это обращение можно заменить на «@»
  • child:: — Возвращает множество потомков на один уровень ниже. Это название сокращается полностью, то есть его можно вовсе опускать.
  • descendant:: — Возвращает полное множество потомков (то есть, как ближайших потомков, так и всех их потомков).
  • descendant-or-self:: — Возвращает полное множество потомков и текущий элемент. Выражение «/descendant-or-self::node()/» можно сокращать до «//». С помощью этой оси, например, можно вторым шагом организовать отбор элементов с любого узла, а не только с корневого: достаточно первым шагом взять всех потомков корневого. Например, путь «//span» отберёт все узлы span документа, независимо от их положения в иерархии, взглянув как на имя корневого, так и на имена всех его дочерних элементов, на всю глубину их вложенности.
  • following:: — Возвращает необработанное множество, ниже текущего элемента.
  • following-sibling:: — Возвращает множество элементов на том же уровне, следующих за текущим.
  • namespace:: — Возвращает множество, имеющее пространство имён (то есть присутствует атрибут xmlns).
  • parent:: — Возвращает предка на один уровень назад. Это обращение можно заменить на «..»
  • preceding:: — Возвращает множество обработанных элементов исключая множество предков.
  • preceding-sibling:: — Возвращает множество элементов на том же уровне, предшествующих текущему.
  • self:: — Возвращает текущий элемент. Это обращение можно заменить на «.»

Условие проверки[править | править вики-текст]

Дополнением к базе является условие проверки. Условием проверки может быть либо прямое равенство конкретному имени, либо *, что пропустит любое имя, либо обращение к одной из функций, которые делятся на 5 групп:

Системные функции[править | править вики-текст]

  • node-set document(object, node-set?)
Возвращает документ, указанный в параметре object.
  • string format-number(number, string, string?)
Форматирует число согласно образцу, указанному во втором параметре, третий параметр указывает именованный формат числа, который должен быть учтён.
  • string generate-id(node-set?)
Возвращает строку, являющуюся уникальным идентификатором.
  • node-set key(string, object)
Возвращает множество с указанным ключом (аналогично функции id для идентификаторов).
  • string unparsed-entity-uri(string)
Возвращает непроанализированный URI, если такового нет, возвращает пустую строку.
  • boolean element-available(string)
Проверяет, доступен ли элемент или множество, указанное в параметре. Параметр рассматривается как XPath.
  • boolean function-available(string)
Проверяет, доступна ли функция, указанная в параметре. Параметр рассматривается как XPath.
  • object system-property(string)
Параметры, возвращающие системные переменные, могут быть:
* xsl: version — возвращает версию XSLT процессора.
* xsl: vendor — возвращает производителя XSLT процессора.
* xsl: vendor-url — возвращает URL, идентифицирующий производителя.
Если используется неизвестный параметр, функция возвращает пустую строку.
  • boolean lang(string)
Возвращает истину, если у текущего тега имеется атрибут xml: lang, либо родитель тега имеет атрибут xml: lang и в нем указан совпадающий строке символ.

Функции над множествами узлов[править | править вики-текст]

  • * — обозначает любое имя или набор символов по указанной оси, например: * — любой дочерний узел; @* — любой атрибут.
  • $name — обращение к переменной, где name — имя переменной или параметра.
  • [] — дополнительные условия выборки или, что тоже самое, предикат шага адресации. Должен содержать логическое значение. Если содержит числовое, считает что это порядковый номер узла, что эквивалентно приписыванию перед этим числом выражения «position()=»
  • {} — если применяется внутри тега другого языка (например HTML), то XSLT процессор рассматривает содержимое фигурных скобок как XPath.
  • / — определяет уровень дерева, то есть разделяет шаги адресации
  • | — объединяет результат. То есть, можно написать несколько путей разбора через знак | и в результат такого выражения войдёт всё, что будет найдено любым из этих путей.
  • node-set node()
Возвращает все узлы. Вместо этой функции часто используют заменитель '*', но, в отличие от звездочки, функция node() возвращает и текстовые узлы.
  • string text()
Возвращает набор текстовых узлов;
  • node-set current()
Возвращает множество из одного элемента, который является текущим. Если мы делаем обработку множества с условиями, то единственным способом дотянуться из этого условия до текущего элемента будет данная функция.
  • number position()
Возвращает позицию элемента в множестве. Корректно работает только в цикле <xsl:for-each/>
  • number last()
Возвращает номер последнего элемента в множестве. Корректно работает только в цикле <xsl:for-each/>
  • number count(node-set)
Возвращает количество элементов в node-set.
  • string name(node-set?)
Возвращает полное имя первого тега в множестве.
  • string namespace-uri(node-set?)
Возвращает ссылку на url определяющий пространство имён.
  • string local-name(node-set?)
Возвращает имя первого тега в множестве, без пространства имён.
  • node-set id(object)
Находит элемент с уникальным идентификатором

Строковые функции[править | править вики-текст]

  • string string(object?)
Возвращает текстовое содержимое элемента. По сути возвращает объединенное множество текстовых элементов на один уровень ниже.
  • string concat(string, string, string*)
Объединяет две или более строк
  • number string-length(string?)
Возвращает длину строки.
  • boolean contains(string, string)
Возвращает истину, если первая строка содержит вторую, иначе возвращает ложь.
  • string substring(string, number, number?)
Возвращает строку вырезанную из строки начиная с указанного номера, и если указан второй номер — количество символов.
  • string substring-before(string, string)
Если найдена вторая строка в первой, возвращает строку до первого вхождения второй строки.
  • string substring-after(string, string)
Если найдена вторая строка в первой, возвращает строку после первого вхождения второй строки.
  • boolean starts-with(string, string)
Возвращает истину если вторая строка входит в начало первой, иначе возвращает ложь.
  • boolean ends-with(string, string)
Возвращает истину если вторая строка входит в конец первой, иначе возвращает ложь.
  • string normalize-space(string?)
Убирает лишние и повторные пробелы, а также управляющие символы, заменяя их пробелами.
  • string translate(string, string, string)
Заменяет символы первой строки, которые встречаются во второй строке, на соответствующие позиции символам из второй строки символы из третьей строки. translate(«bar», «abc», «ABC») вернет BAr.

Логические функции[править | править вики-текст]

Символ Значение
or логическое «или»
and логическое «и»
= логическое «равно»
< (&lt;) логическое «меньше»
> (&gt;) логическое «больше»
<= (&lt;=) логическое «меньше либо равно»
>= (&gt;=) логическое «больше либо равно»
  • boolean boolean(object)
Приводит объект к логическому типу;
  • boolean true()
Возвращает истину.
  • boolean false()
Возвращает ложь.
  • boolean not(boolean)
Отрицание, возвращает истину если аргумент ложь и наоборот.

Числовые функции[править | править вики-текст]

  • + — сложение
  • − — вычитание
  • * — умножение
  • div — обычное деление (не деление нацело!)
  • mod — остаток от деления
  • number number(object?)
Переводит объект в число.
  • number sum(node-set)
Вернёт сумму множества, каждый тег множества будет преобразован в строку и из него получено число.
  • number floor(number)
Возвращает наибольшее целое число, не большее, чем аргумент.
  • number ceiling(number)
Возвращает наименьшее целое число, не меньшее, чем аргумент.
  • number round(number)
Округляет число по математическим правилам.

Ссылки[править | править вики-текст]