Xpath query примеры. Примеры XPath

(предок) содержит всех предков контекстного узла, включая родителей, дедушек, прадедушек и т.д. Эта ось всегда содержит корневой узел - если только контекстным узлом не является сам корневой узел.

Взгляните на листинг 7.3, в котором при помощи оси

осуществляется поиск имен (хранимых в элементе ) всех предков элементов . Листинг 7.3. Применение оси ancestor
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Вот результат применения этой таблицы стилей к

:

Применение оси ancestor-or-self

содержит всех предков контекстного узла, а также сам контекстный узел. Это означает, помимо прочего, что такая ось всегда содержит корневой узел.

В листинге 7.4 добавлены атрибуты

со значением «Steve» в весь документ. Листинг 7.4. planets.xml с атрибутами AUTHOR
.0553
58.65
1516
.983
43.4
.815
116.75
3716
.943
66.8
1
2107
1
128.4

Предположим теперь, что я хочу перечислить по имени всех предков элементов

, имеющих атрибут , а также текущий элемент , если у него есть атрибут . Это можно сделать при помощи оси и функции (листинг 7.5). Листинг 7.5. Применение оси ancestor-or-self
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Вот результат; показаны выбранные предки всех трех элементов

, включая сам элемент , при условии, что у него имеется атрибут :

Применение оси descendant

(потомок) содержит всех потомков контекстного узла. Заметьте, что сюда не входят атрибуты или узлы пространств имен, поскольку они не считаются дочерними узлами.

В следующем примере (листинг 7.6) демонстрируется работа с этой осью. На этот раз я хочу добавить примечание к элементу

Меркурия:
(Извините, но Меркурий взорвался и больше не доступен.). Чтобы найти Меркурий, мне достаточно только проверить, имеет ли какой-либо потомок элемента строковое значение «», что я сделаю при помощи выражения XPath внутри предиката выбора. Листинг 7.6. Применение оси descendant
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Sorry. Mercury has blown up and is no longer available.

Вот результирующий документ, дополненный новым элементом

только для Меркурия:
.0553
58.65
1516
.983
43.4
Sorry, Mercury has blown up and is no longer available.
.815
116.75
3716
.943
66.8

Применение оси descendant-or-self

содержит всех потомков контекстного узла и сам контекстный узел. Заметьте, однако, что она не содержит атрибутов и узлов пространств имен.

В следующем примере (листинг 7.7) демонстрируется работа с осью. В этом случае я создал упрощенную таблицу стилей (подробнее об упрощенных таблицах стилей см. главу 2), которая обрабатывает все элементы с использованием потомков, генерируя уже знакомую нам HTML-таблицу данных о планетах.

Листинг 7.7. Применение оси descendant-or-self

Вот и все. Я применил здесь упрощенную таблицу стилей, чтобы подчеркнуть, что при помощи таких осей потомков, как

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

Применение оси following

Ось following (следующий) содержит все узлы, расположенные после контекстного узла в соответствии с установленным в документе порядком (другими словами, в порядке, в котором они появляются в документе, начиная с его начала), исключая всех потомков контекстного узла, а также исключая узлы атрибутов и пространств имен.

В этом примере (листинг 7.8) я выбираю каждый элемент И копирую все последующие элементы в результирующий документ.

Листинг 7.8. Применение оси following
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Меркурия, он копирует все последующие элементы - то есть Венеру, затем всех потомков Венеры, далее Землю и затем всех потомков Земли. После этого он выбирает элемент Венеры и копирует все следующие элементы, то есть Землю и всех потомков Земли:
.815
116.75
3716
.943
66.8
.815
116.75
3716
.943
66.8
1
2107
1
128.4
1
2107
1
128.4
1
2107
1
128.4
1
2107
1
128.4

С другой стороны, при использовании оси

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

Применение оси following-sibling

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

Например, я могу выбрать каждый элемент

и скопировать в результирующий документ все узлы в оси следующим образом (листинг 7.9). Листинг 7.9. Применение оси following-sibling
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

При этом сначала копируются два узла-брата, следующие за Меркурием (Венера и Земля), затем копируется следующий узел-брат Венеры, Земля. У самой Земли нет следующих за ней братьев, поэтому результат выглядит так:

.815
116.75
3716
.943
66.8
1
2107
1
128.4
1
2107
1
128.4

Применение оси namespace

содержит узлы пространств имен контекстного узла. Заметьте, что эта ось пуста, если контекстным узлом не является элемент. У элемента присутствует узел пространства имен для:

Каждого атрибута элемента, чье имя начинается с «xmlns:»;

Каждого атрибута элемента-предка, чье имя начинается с «xmlns:» (конечно, если сам элемент или ближайший предок не объявит пространство имен заново);

Атрибута

, если элемент или предок имеет атрибут .

В следующем примере (листинг 7.10) я хочу отобразить пространство имен элемента

в результирующем документе, и в исходном документе я присвоил пространству имен значение «http://www.starpowder.com». Листинг 7.10. planets.xml с объявлением пространства имен
.0553
58.65
1516
.983
43.4

Вот таблица стилей (листинг 7.11), в которой я проверяю пространства имен, используемые в элементе

. Листинг 7.11. Применение оси namespace в planets.xml
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

А вот результирующий документ (заметьте, что вид документа может меняться в зависимости от процессора XSLT):

Применение оси parent

Ось parent (родитель) содержит родителя (и только родителя) контекстного узла, если таковой имеется.

Предположим, что я хочу изменить содержимое элемента Земли

на «>> (Масса Земли принимается за 1). В следующем шаблоне (листинг 7.12) для этого проверяется, содержит ли родитель элемента элемент со строковым значением «Earth». Листинг 7.12. Применение оси parent
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

The mass of Earth is set to 1.

И вот результат:

.0553
58.65
1516
.983
43.4
.815
116.75
3716
.943
66.8
The mass of Earth is set to 1.
2107
1
128.4

Применение оси preceding

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

Пусть, например, мне нужно задать для содержимого элемента

текст «» (Эта планета расположена дальше от Солнца, чем Меркурий.), если рассматриваемая планета действительно дальше от Солнца, чем Меркурий. Один из способов сделать это - проверить, расположен ли Меркурий перед рассматриваемой планетой в соответствии с установленным в документе порядком, при помощи оси (листинг 7.13). Листинг 7.13. Применение оси preceding
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
This planet is farther from the Sun than Mercury.

Если текущая планета расположена после Меркурия, я могу вставить сообщение в ее элемент

. Результат следующий:
.0553
58.65
1516
.983
43.4
.815
116.75
3716
.943
This planet is farther from the Sun than Mercury.
1
2107
1
This planet is farther from the Sun than Mercury.

Применение оси preceding-sibling

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

Что, если, например, вам нужно создать шаблон, который будет выбирать только элементы

в элементе Меркурия? Для этого можно проверить, существуют ли братья, предшествующие элементу , которые являются элементами со строковым значением «». Если применить ось (листинг 7.14), поиск будет ограничен текущим элементом , что означает, что Меркурий не будет выбран, если вы только не находитесь в нужном элементе . Листинг 7.14. Применение оси preceding-sibling
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

А вот результат:

.0553
58.65
1516
.983
This is the planet Mercury, closest to the Sun.
.815
116.75
3716
.943
66.8
1
2107
1
128.4

Применение оси self

содержит только контекстный узел. В соответствии с одним из сокращений XPath, как мы увидим дальше, вместо «» можно использовать «.».

Эту ось полезно иметь в виду, поскольку, как вы помните из главы 4, если не задать ось, осью по умолчанию будет

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

В следующем примере я объединяю шаблоны для элементов

и в один шаблон. Поскольку у этих элементов разный формат, я должен обращаться с ними по-разному внутри одного и того же шаблона (что можно сделать проверкой значений оси , которая возвращает непустой набор узлов, если контекстным, узлом является элемент , и , возвращающей непустой набор узлов, если контекстным узлом является элемент ):

На этом мы завершаем рассмотрение новых осей XPath. Давайте перейдем к примерам.

Примеры путей расположения

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

. Возвращает дочерние элементы контекстного узла; . Возвращает все дочерние текстовые узлы контекстного узла; . Возвращает всех детей контекстного узла; . Возвращает атрибут контекстного узла; . Возвращает все элементы-потомки контекстного узла; . Возвращает всех предков контекстного узла; . Возвращает предков контекстного узла. Если контекстным узлом тоже является , возвращает также контекстный узел; . Возвращает элементы-потомки контекстного узла. Если контекстным узлом тоже является , возвращает также контекстный узел; . Возвращает контекстный узел, если им является элемент ;
child::PLANET/descendant::NAME
. Возвращает элементы-потомки дочерних элементов контекстного узла; . Возвращает всех внуков контекстного узла; . Возвращает корневой узел; . Возвращает все элементы в документе;
/descendant::PLANET/child::NAME
. Возвращает все элементы с родителем в документе; . Возвращает третьего ребенка контекстного узла;
child::PLANET
. Возвращает последнего ребенка контекстного узла;
/descendant::PLANET
. Возвращает третий элемент в документе;
child::PLANETS/child::PLANET/child::NAME
. Возвращает третий элемент четвертого элемента элемента ; . Возвращает всех детей контекстного узла после первых трех;
preceding-sibling::NAME
. Возвращает второй предыдущий элемент-брат контекстного узла;
child::*
. Возвращает детей и контекстного узла.
child::*
. Возвращает последнего ребенка или контекстного узла.

Как видите, синтаксис некоторых выражений достаточно запутан, и набирать их также довольно долго. Но, как и для образцов, существует сокращенная форма синтаксиса XPath.

Сокращенный синтаксис XPath

Сокращения синтаксиса XPath могут быть весьма удобными. Ниже приведены правила:

может быть сокращено как ; может быть сокращено как ; может быть сокращено как ; может быть сокращено как ; может быть сокращено как .

Например, путь расположения

- сокращение для
self::node()/descendant-or-self::node()/child::PLANET
. Можно также сократить выражение предиката как , как и т.д. Работать с путями расположения XPath при помощи сокращенного синтаксиса значительно проще. В следующем списке перечислен ряд примеров путей расположения с использованием сокращенного синтаксиса: возвращает дочерние элементы контекстного узла; возвращает все дочерние элементы контекстного узла; возвращает все дочерние текстовые узлы контекстного узла; возвращает атрибут контекстного узла; возвращает все атрибуты контекстного узла; возвращает третьего ребенка контекстного узла; возвращает последнего ребенка контекстного узла; возвращает всех внуков контекстного узла; возвращает второй элемент третьего элемента элемента ; возвращает всех потомков корня документа; возвращает элементы-потомки дочерних элементов контекстного узла; возвращает все элементы , у которых есть родитель ; возвращает сам контекстный узел; возвращает элементы-потомки контекстного узла; возвращает родителя контекстного узла; возвращает атрибут родителя контекстного узла; возвращает всех родителей потомка контекстного узла и родителя контекстного узла; возвращает детей контекстного узла, у которых есть дети ; возвращает детей контекстного узла, у которых есть дети с текстом, равным «Venus»; возвращает всех детей контекстного узла, у которых есть атрибут со значением «»; возвращает шестого ребенка контекстного узла, только если у этого ребенка есть атрибут со значением «days». Можно также написать ; возвращает всех детей контекстного узла, у которых есть атрибут и атрибут ;
//PLANET
" выбирает все элементы , значение которых отлично от значения любого предшествующего элемента ; выбирает любой элемент , который является первым ребенком своего родителя; выбирает первых пятерых детей контекстного узла, у которых есть атрибут .

Проверка выражений XPath

В пакет Xalan входит удобная программа-пример, ApplyXPath.java, позволяющая применить выражение XPath к документу и посмотреть на результат, что очень помогает при тестировании. Для запуска этого примера вам нужно будет скомпилировать

в при помощи утилиты java.exe, входящей в поставку Java.

В качестве примера я применю выражение XPath «

» к при помощи . Ниже показан результат, отображающий все элементы , дочерние по отношению к элементам (теги добавлены программой ApplyXPath):
%java ApplyXPath planets.xml PLANET/NAME
MercuryVenusEarth

XPath 2.0

XPath находится в стадии обновления, и в него включаются средства поддержки XSLT 2.0 (см. www.w3.org/TR/xpath20req). Задачи XPath 2.0 следующие:

Упрощение операций с содержимым типов, поддерживаемых схемой XML;

Упрощение операций со строковым содержимым;

Поддержка соответствующих стандартов XML;

Улучшение удобства использования;

Улучшение функциональной совместимости;

Улучшение поддержки международных языковых средств;

Сохранение обратной совместимости;

Повышенная эффективность процессора.

Следующий список дает обзор требований XPath. Главные пункты - поддержка схемы XML и регулярных выражений, что дает средства работы со строками и поиска в строках. (Дополнительную информацию о регулярных выражениях можно почерпнуть по адресу http://www.perldoc.com/perl5.6/pod/perlre.html.) В соответствии с W3C, XPath 2.0:

Должен поддерживать архитектуру XML W3C, хорошо взаимодействуя с другими стандартами в семействе XML;

Должен выражать свою модель данных в терминах информационного множества (infoset) XML;

Должен предоставлять общий ключевой синтаксис для XSLT 2.0 и XML Query language 1.0;

Должен поддерживать явное сравнение «

» или «» и синтаксис равенства;

Должен расширять множество функций агрегации (например, пользователи XSLT часто требовали добавить функции

и );

Должен сохранять обратную совместимость с XPath 1.0;

Должен предоставлять функции пересечения и разности то есть - XPath 1.0 поддерживает объединение двух наборов узлов, и к этому должны быть добавлены функции пересечения и разности;

Должен поддерживать операцию унарного плюса (поскольку в схеме XML у десятичных чисел может присутствовать лидирующий плюс);

Должен улучшать удобство использования;

Должен снизить ограничения на шаги расположения;

Должен реализовывать условную операцию, оперирующую тремя выражениями - выражением 1 (логическая операция), выражением 2 и выражением 3. Если выражение 1 принимает значение «истина», должно вычисляться выражение 2, а если выражение 1 принимает значение «ложь», должно вычисляться выражение 3;

Должен определять последовательный синтаксис для подвыражений, обрабатывающих коллекции элементов;

Должен поддерживать дополнительные строковые функции. Например, W3C рассматривает вопрос добавления средств для замены в строках, заполнения символами и преобразований регистра;

Должен поддерживать функции агрегации при применении к коллекциям. Например, некоторым пользователям XPath 1.0 требовалось применить такую функцию агрегации, как

, к значениям выражений, примененных к наборам узлов;

Должен поддерживать регулярные выражения для поиска в строках с использованием нотации регулярных выражений, установленной в схеме XML;

Должен поддерживать элементарные типы данных схемы XML. То есть в дополнение к типам, поддерживаемым моделью данных XPath 1.0, - строке, числу, логическому значению и набору узлов - модель данных XPath 2.0 должна поддерживать элементарные типы данных схемы XML;

Должен поддерживать представления чисел с плавающей точкой одинарной и двойной точности, поддерживаемые схемой XML, которая использует научную нотацию;

Должен определять подходящий набор функций для работы пользователя с элементарными типами данных схемы XML;

Должен добавлять в XPath тип данных «список» (поскольку схема XML позволяет определять простые типы, унаследованные от списка);

Должен поддерживать доступ к значениям простых типов элементов и атрибутов. Поскольку схемы XML представляют много новых типов, XPath 2.0 должен поддерживать доступ к собственному, простого типа, значению элемента или атрибута;

Должен определять поведение операторов для нулевых аргументов;

Должен иметь средства для выбора элементов или атрибутов на основе явного типа схемы XML;

Должен иметь средства для выбора элементов или атрибутов на основе иерархии типов схемы XML;

Должен иметь средства для выбора элементов на основе групп подстановки схемы XML;

Должен поддерживать средства поиска, основанные на уникальных ограничениях и ключах схемы.

Хотя мы подошли к концу главы, о XPath сказано еще не все. Тема будет продолжена в следующей главе, в которой мы более внимательно рассмотрим доступные в XPath функции и функции, уже встроенные в XSLT.

XPath – это язык для записи выражений. Он имеет фундаментальное значе­ние для обработки XML-документов. Нельзя овладеть XSLT, не зная XPath, точ­но так же, как нельзя выучить английский язык, не зная алфавита. Некоторые читатели первого издания этой книги пеняли мне за то, что я не включил в нее основ XPath. Эта глава добавлена отчасти, чтобы удовлетворить их, но главным образом потому, что в спецификации XPath 2.0 выразительная мощь этого языка была значительно усилена. Впрочем, многие рецепты будут рабо­тать и с XPath 1.0.

В XSLT 1.0 язык XPath используется тремя способами. Во-первых, в шабло­нах он служит для адресации частей преобразуемого документа. Во-вторых, он применяется для задания образцов в правилах сопоставления. В-третьих, с помо­щью встроенных в XPath операторов и функций выполняются простые математи­ческие операции и манипуляции со строками.

В XSLT 2.0 связь с XPath 2.0 сохранена и даже стала прочнее. В нем широ­ко используются новые вычислительные средства, появившиеся в XPath 2.0. Можно даже сказать, что дополнительные возможности XSLT 2.0 – во многом результат нововведений в XPath 2.0, к числу которых относятся последова­тельности, регулярные выражения, условные и итеративные выражения, сис­тема типов, совместимая со спецификацией XML Schema, а также множество новых встроенных функций.

Каждый рецепт в этой главе – это подборка мини-рецептов для решения опре­деленного класса задач, возникающих в XPath в контексте XSLT. Все XPath-выра- жения прокомментированы в соответствии с принятым в XPath 2.0 соглашением (: комментарий:), но пользователям XPath 1.0 следует иметь в виду, что это недопустимая синтаксическая конструкция. Пустой результат вычисления XPath-выражения мы будем обозначать (), именно так в XPath 2.0 записывается пустая последовательность.

Требуется отобрать узлы XML-дерева с учетом сложных взаимосвязей в иерар­хической структуре.

Во всех приведенных ниже примерах используются оси. В каждой группе для демонстрации берется некий XML-документ, в котором контекстный узел выделен полужирным шрифтом. Поясняется, что является результатом вы­числения пути, при этом показано, какие элементы отбираются относительно выделенного контекста. В некоторых случаях для иллюстрации тонкостей вычис­ления конкретного выражения рассматриваются и другие узлы, помимо кон­текстного.

Дочерняя ось и ось потомков

Дочерняя ось принимается в XPath по умолчанию. Иными словами, явно ука­зывать ось child:: необязательно, но, если вы хотите быть педантом, то можете и указать. Спуститься по XML-дереву глубже, чем на один уровень, позволяют

оси descendant:: и descendant-or-self::. Первая не включает сам кон­текстный узел, вторая – включает.

(: Отобрать все дочерние элементы с именем X

X (: то же, что child::X)

Результат:

(: Отобрать первый дочерний элемент с именем X X

Результат:

(: Отобрать последний дочерний элемент с именем X X

Результат:

(: Отобрать первый дочерний элемент при условии, что его имя X. Иначе пусто *

Результат:

(: Отобрать последний дочерний элемент при условии, что его имя X. Иначе пусто

*

Результат: ()

(: Отобрать последний дочерний элемент при условии, что его имя Y. Иначе пусто

*

Результат:

(: Отобрать всех потомков с именем X descendant::X

Результат:

(: Отобрать контекстный узел, если его имя X, а также всех потомков с именем X descendant-or-self::X

Результат:

(: Отобрать контекстный узел и всех его потомков descendant-or-self::*

Результат:

Оси братьев

Оси братьев называются preceding-sibling:: и following-sibling::. Ось preceding-sibling содержит братьев, предшествующих контекстному узлу, а ось following-sibling – следующих за ним. Братьями, естественно, называются дети одного родителя. Почти во всех примерах ниже используется ось preceding-sibling::, но вам не составит труда вычислить результат и для оси following-sibling::.

Имейте в виду, что в позиционном выражении вида preceding- sibling::* вы ссылаетесь на непосредственно предшествующего брата в порядке обратного отсчета от контекстного узла, а не первого брата в порядке доку­мента. Некоторых смущает тот факт, что результирующая последовательность воз­вращается в порядке документа вне зависимости от того, используется ось preceding-sibling:: или following-sibling::. В выражении../X, строго говоря, никакая ось не указана; это просто способ отобрать предшествующего и пос­ледующего брата с именем X, а также сам контекстный узел, если он называется X. Формально это сокращенная запись выражения parent::node()/X. Отметим, что выражения(preceding-sibling::*) и(following-sibling::*) от­бирают первого предшествующего или последующего брата в порядке документа.

(: Отобрать всех братьев с именем A, предшествующих контекстному узлу preceding-sibling::A

Результат:

(: Отобрать всех братьев с именем A, следующих за контекстным узлом following-sibling::A

Результат:

(: Отобрать всех братьев, предшествующих контекстному узлу preceding-sibling::*

Результат:

(: Отобрать первого предшествующего брата с именем A в обратном порядке документа preceding-sibling::A

Результат:

(: Отобрать первого предшествующего брата в обратном порядке документа при условии, что его имя A preceding-sibling::*

Результат: ()

(: Если бы контекстным был узел , то в результате мы получили бы

(: Отобрать всех предшествующих братьев, кроме элементов с именем A preceding-sibling::*

Результат:

(: В следующих примерах используется такой тестовый документ

(: Элемент, непосредственно предшествующий контекстному узлу при усло­вии, что у того есть дочерний элемент с именем A

preceding-sibling::*[A]

Результат: ()

(: Первый из предшествующих контекстному узлу элементов, у которого есть дочерний элемент с именем A

preceding-sibling::*[A]

Результат:

(: XPath 2.0 позволяет более гибко выбирать элементы с учетом про­странств имен. В следующих примерах используется такой XML-документ

(: Отобрать всех предшествующих братьев контекстного узла, для которых пространство имен ассоциировано с префиксом NS preceding-sibling::NS:*

Результат:

(: Отобрать всех предшествующих братьев контекстного узла, для которых локальное имя равно A preceding-sibling::*:A

Результат:

Родительская ось и ось предков

Родительская ось (parent::) относится к родителю контекстного узла. Не путайте выражение parent::X с../X. Первое порождает последовательность, ко­торая содержит в точности один элемент, если имя родителя контекстного узла – X, и пуста в противном случае. Второе – это сокращенная запись выражения parent::node()/X, которое отбирает всех братьев контекстного узла с именем X, в том числе и сам этот узел, если он называется X.

С помощью осей ancestor:: и ancestor-or-self:: можно перемещать­ся вверх по XML-дереву (переходя к родителю, деду, прадеду и т.д.). В первом случае сам контекстный узел исключается, во втором – включается.

(: Возвращает родителя контекстного узла, при условии, что он называется X, в противном случае - пустую последовательность. parent::X

(: Возвращает родителя контекстного узла. Результат может быть пустым, только если контекстный узел является элементом верхнего уровня. parent::*

(: Возвращает родителя, если его пространство имен ассоциировано с префиксом X. Префикс должен быть определен, иначе произойдет ошибка.

(: Возвращает родителя независимо от его пространства имен при условии, что локальное имя равно X.:) parent::*:X

(: Возвращает всех предков (включая родителя) с именем X. ancestor::X

(: Возвращает контекстный узел, если он называется X, а также всех предков с именем X. ancestor-or-self::X

Оси предшественников и последователей

Оси preceding:: и following:: могут отбирать очень много узлов, по­скольку учитываются все узлы, предшествующие контекстному (или следующие за ним) в порядке документа, исключая предков в случае оси following:: или потомков для оси preceding::. Не забывайте также, что обе оси не включают узлы, соответствующие пространствам имен и атрибутам.

(: Все предшествующие узлы с именем X. preceding::X

(: Ближайший предшественник с именем X. preceding::X

(: Самый дальний последователь с именем X. following::X

Обсуждение

В языке XPath понятие оси служит для того, чтобы выделить в дереве доку­мента различные подмножества узлов относительно некоторого узла, называемо­го контекстным. В общем случае эти подмножества пересекаются, но оси ancestor, descendant, following, preceding и self разбивают документ на непересекающиеся части, в совокупности содержащие все узлы (за исключением тех, что соответ­ствуют пространствам имен и атрибутам). Контекстный узел устанавливается языком, в который погружен XPath. В случае XSLT контекстный узел устанавли­вают следующие конструкции:

Сопоставление с шаблоном ();

Xsl:apply-templates.

Свободное владение языком написания путевых выражений – необходимое условие для выполнения как простых, так и сложных преобразований. Опыт про­граммирования на традиционных языках часто служит причиной путаницы и ошибок при работе с XPath. Например, я часто ловил себя на том, что писал что- то типа , имея в виду . Возможно, это объясняется тем, что последнее выражение – интуитивно менее понятный способ выразить такое условие: «если имя непосредственно предше­ствующего брата равно X».

Конечно, нет никакой возможности показать все полезные комбинации осей в путевых выражениях. Но, если вы поймете приведенные выше примеры, то смо­жете разобраться, что означает выражение preceding-sibling::X/ descendant::Z и еще более сложные.

Мангано Сэл XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

В данной главе на основе некоторых примеров демонстрируется базовый синтаксис XPath.

Пример XML документа

В качестве примера будет использоваться следующий XML документ:

Напоминание Отправить письмо! 4 Re: Напоминание Письмо отправлено 7

Загрузка XML документа

Для загрузки XML документа используется объект XMLHttpRequest, который поддерживается всеми основными браузерами.

Var xmlhttp = new XMLHttpRequest();

В старых браузерах Microsoft (IE 5 и 6) используется код:

Var xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

Выбор узлов

К сожалению разные браузеры поддерживают разные способы для работы с XPath.

Chrome, Firefox, Edge, Opera и Safari для выбора узлов используют метод evaluate():

XmlDoc.evaluate(xpath, xmlDoc, null, XpathResult.ANY_TYPE, null);

Internet Explorer использует метод selectNodes():

XmlDoc.selectNodes(xpath);

Выбор всех заголовков

В следующем примере выбираются все узлы heading:

/messages/note/heading

Выбор заголовка первой заметки

В следующем примере выбирается заголовок heading первого узла note элемента messages:

/messages/note/heading

Выбор всех отделов

В следующем примере выбирается текст из всех узлов desk:

/messages/note/desk

Выбираем отделы с номером больше 4

В следующем примере выбираются все узлы desk, значение которых больше 4:

/messages/note/desk

Выбираем заголовки заметок для отделов с номерами больше 4

В следующем примере выбираются все узлы heading тех узлов note, у элемент desk которых значение больше 4:

/messages/note/heading

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 имеет древовидную структуру. В документе всегда имеется корневой элемент (инструкция к дереву отношения не имеет). У элемента дерева всегда существуют потомки и предки, кроме корневого элемента, у которого предков нет, а также тупиковых элементов (листьев дерева), у которых нет потомков. Каждый элемент дерева находится на определенном уровне вложенности (далее - «уровень»). У элементов на одном уровне бывают предыдущие и следующие элементы.

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

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

<html > <body > <div > Первый слой <span > блок текста в первом слое</ span > </ div > <div > Второй слой</ div > <div > Третий слой <span class = "text" > первый блок в третьем слое</ span > <span class = "text" > второй блок в третьем слое</ span > <span > третий блок в третьем слое</ span > </ div > <img / > </ body > </ html >

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

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

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

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

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

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

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

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

Оси

Оси - это база языка XPath.

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

Существуют сокращения для некоторых осей, например:

  • attribute:: - можно заменить на «@»
  • child:: - часто просто опускают
  • descendant:: - можно заменить на «.//»
  • parent:: - можно заменить на «..»
  • 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 - имя переменной или параметра.
  • - дополнительные условия выборки
  • {} - если применяется внутри тега другого языка (например HTML), то XSLT процессор рассматривает содержимое фигурных скобок как XPath.
  • / - определяет уровень дерева
node-set node () Возвращает все узлы. Для этой функции часто используют заменитель "*", но в отличие от звездочки - node() возвращает и текстовые узлы. string text () Возвращает набор текстовых узлов; node-set current () Возвращает множество из одного элемента, который является текущим. Если мы делаем обработку множества с условиями, то единственным способом дотянуться из этого условия до текущего элемента будет данная функция. number position () Возвращает позицию элемента в множестве. Корректно работает только в цикле number last () Возвращает номер последнего элемента в множестве. Корректно работает только в цикле 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 - логическое «и»
  • = - логическое «равно»
  • < (<) - логическое «меньше»
  • > (>) - логическое «больше»
  • <= (<=) - логическое «меньше либо равно»
  • >= (>=) - логическое «больше либо равно»
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) Округляет число по математическим правилам.