Выбрать главу

Фильтрация множества узлов выполняется следующим образом.

□ Фильтруемое множество сортируется в направлении просмотра оси навигации данного шага. Для осей ancestor, ancestor-or-self, preceding, preceding-sibling фильтруемое множество сортируется в обратном порядке просмотра документа, для остальных осей — в прямом порядке просмотра.

□ Выражение предиката вычисляется для каждого узла отсортированного множества в следующем контексте.

 • Фильтруемый узел (тот, для которого в данный момент вычисляется предикат) становится контекстным узлом.

 • Количество узлов фильтруемого множества становится размером контекста.

 • Позиция фильтруемого узла в отсортированном множестве становится позицией контекста.

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

 • Если результатом вычисления является число, равное позиции контекста, булевым значением предиката будет true, в противном случае — false. Например, предикат [2] равносилен предикату [position()=2] — он обратится в истину только для второго узла фильтруемого множества.

 • Все остальные типы данных приводятся к булевому типу в соответствии со стандартными правилами (см. также раздел "Типы данных" настоящей главы).

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

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

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

Примеры:

□ a[1] — выберет первый в порядке просмотра документа дочерний элемент а контекстного узла;

□ a[position() mod 2 = 0] — выберет все четные дочерние элементы а;

□ *[. = 'а'] — выберет все дочерние элементы, текстовое значение которых равно "а";

□ *[name() = 'a'] — выберет все дочерние элементы, имя которых равно "а";

□ *[starts-with(name(), 'a')] — выберет все дочерние элементы, имя которых начинается с "а";

□ *[. = 'а'][1] — выберет первый дочерний элемент, текстовое значение которого равно "а";

□ *[. = 'a'][position() mod 2 = 0] — выберет все дочерние элементы, текстовое значение которых равно "а", затем из них выберет четные элементы.

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

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

[XP10] AbbreviatedAbsoluteLocationPath

 :: = '//' RelativeLocationPath

[XP11] AbbreviatedRelativeLocationPath

 ::= RelativeLocationPath '//' Step

[XP12] AbbreviatedStep

 ::= '.'

     | '..'

[XP13] AbbreviatedAxisSpecifier

 ::= '@'?

Первое сокращение, '//' — это краткая версия для "/descendant-or-self::node()/". Шаг выборки descendant-or-self::node() возвращает всех потомков контекстного узла (не включая узлов атрибутов и пространств имен). Сокращенный путь вида '//' RelativeLocationPath раскрывается в путь вида

'/descendant-or-self::node()/' RelativeLocation

а путь вида RelativeLocationPath '//' Step — в путь

RelativeLocationPath '/descendant-or-self::node()/' Step

Сокращенный шаг вида '.' возвращает контекстный узел, его полная версия — self::node().

Сокращенный шаг '..' возвращает родительский узел контекстного узла. Это сокращение равносильно шагу выборки parent::node().

Заметим, что сокращения "." и ".." являются сокращенными шагами выборки. Это, в частности, означает, что к ним нельзя присовокуплять предикаты и так далее. Выражение ".[ancestor::body]" будет с точки зрения синтаксиса XPath некорректным. Вместо этого можно использовать выражение "self::node()[ancestor::body]", которое будет синтаксически правильным.

Наиболее часто используемой осью навигации является ось child, содержащая все дочерние узлы контекстного узла. Шаги выборки, которые обращаются к дочерним узлам, имеют вид 'child::' NodeTest Predicate*. Самым полезным сокращением является то, что в шагах такого вида дескриптор оси 'child::' может быть опущен, и тогда упрощенные шаги будут иметь вид NodeTest Predicate*.

Дескриптор оси навигации 'attribute::' также может быть сокращен до '@'. Шаг выборки 'attribute::' NodeTest Predicate* может быть переписан с использованием, сокращенного синтаксиса в виде '@'. NodeTest Predicate*.

Примеры:

□ .//* — выберет все элементы-потомки контекстного узла;

□ ..//* — выберет все дочерние элементы родителя контекстного узла;

□ @* — выберет все атрибуты контекстного узла;

□ .//@* — выберет все атрибуты всех потомков контекстного узла;

□ //* — выберет все элементы документа, содержащего контекстный узел;

□ //@* — выберет все атрибуты всех элементов документа, содержащего контекстный узел;

□ html/body — выберет элементы body, принадлежащие дочерним элементам html контекстного узла.

Примеры путей выборки

Простые шаги выборки:

□ child::* — выберет все дочерние элементы контекстного узла;

□ child::comment() — выберет все узлы комментариев контекстного узла;

□ child::node() — выберет все дочерние узлы контекстного узла вне зависимости от их типа;

□ child::query — выберет все дочерние элементы контекстного узла, имеющие имя query;

□ child::xsqclass="underline" * — выберет все дочерние элементы, которые находятся в пространстве имен, определяемом префиксом xsql;

□ child::xsqclass="underline" query — выберет все дочерние элементы query, которые находятся в пространстве имен, определяемом префиксом xsql;

□ attribute::* — выберет все атрибуты контекстного узла;

□ attribute::href — выберет атрибут href контекстного узла, если он существует;

□ parent::* — выберет родительский узел контекстного узла, если тот является элементом, и пустое множество, если родительский узел имеет другой тип, например является корнем дерева;

□ parent::node() — выберет родительский узел контекстного узла вне зависимости от его типа. Единственный случай, когда этот шаг выберет пустое множество — это когда контекстный узел является корневым узлом документа;

□ parent::xsclass="underline" template — выберет родительский узел, если тот является элементом с именем template и имеет пространство имен с префиксом xsl, иначе выберет пустое множество;