Алексей Валиков - Технология XSLT
• Фильтруемый узел (тот, для которого в данный момент вычисляется предикат) становится контекстным узлом.
• Количество узлов фильтруемого множества становится размером контекста.
• Позиция фильтруемого узла в отсортированном множестве становится позицией контекста.
□ Результат вычисления предиката преобразуется в булевый тип согласно следующим правилам.
• Если результатом вычисления является число, равное позиции контекста, булевым значением предиката будет 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::xsql:* — выберет все дочерние элементы, которые находятся в пространстве имен, определяемом префиксом xsql;
□ child::xsql:query — выберет все дочерние элементы query, которые находятся в пространстве имен, определяемом префиксом xsql;
□ attribute::* — выберет все атрибуты контекстного узла;
□ attribute::href — выберет атрибут href контекстного узла, если он существует;
□ parent::* — выберет родительский узел контекстного узла, если тот является элементом, и пустое множество, если родительский узел имеет другой тип, например является корнем дерева;
□ parent::node() — выберет родительский узел контекстного узла вне зависимости от его типа. Единственный случай, когда этот шаг выберет пустое множество — это когда контекстный узел является корневым узлом документа;
□ parent::xsl:template — выберет родительский узел, если тот является элементом с именем template и имеет пространство имен с префиксом xsl, иначе выберет пустое множество;
□ self::* — выберет контекстный узел, если он является элементом и пустое множество узлов, если контекстный узел имеет другой тип;
□ self:* — выберет все дочерние элементы контекстного узла, принадлежащие пространству имен с префиксом self;
□ self::text() — выберет контекстный узел, если он является текстовым узлом;
□ self::node() — выберет контекстный узел вне зависимости от его типа;
□ self::query — выберет контекстный узел, если он является элементом с именем query, и пустое множество, если контекстный узел имеет другое имя или не является элементом;
□ preceding::para — выберет все элементы para, которые предшествуют контекстному узлу в порядке просмотра документа;
□ preceding::comment() — выберет все узлы комментариев, которые предшествуют контекстному узлу в порядке просмотра документа;
□ preceding-sibling::* — выберет все братские (принадлежащие тому же родителю) элементы контекстного узла, которые предшествуют ему в порядке просмотра документа;
□ following::processing-instruction('fop') — выберет все узлы инструкций по обработке, которые имеют имя (целевое приложение) "fop" и следуют за контекстным узлом в порядке просмотра документа;
□ following-sibling::text() — выберет все текстовые узлы, которые являются братьями контекстного узла и следуют за ним в порядке просмотра документа;
□ descendant::* — выберет все элементы-потомки контекстного узла;
□ descendant::node() — выберет все узлы-потомки контекстного узла;
□ descendant::b — выберет все элементы b, являющиеся потомками контекстного узла;
□ descendant-or-self::* — выберет все элементы-потомки контекстного узла, а также сам контекстный узел, если он также является элементом;
□ ancestor::* — выберет все элементы, которые являются предками контекстного узла; выбранное множество не будет включать корневой узел, поскольку он не является элементом;
□ ancestor::node() — выберет все узлы, являющиеся предками контекстного узла; выбранное множество будет включать корневой узел (за исключением того случая, когда контекстный узел сам является корневым);
□ ancestor::p — выберет все элементы p, являющиеся предками контекстного узла;
□ ancestor-or-self::node() — выберет контекстный узел, а также все узлы, являющиеся его предками. Выбранное этим шагом множество будет всегда включать корневой узел;