Кроме того, XSLT предоставляет похожий механизм, механизм ключей, который выбирает узлы не по уникальным атрибутам, а по значениям именованных ключей, определенных в преобразовании. Для этого служит функция
key
.
Поскольку два этих механизма схожи по семантике, они определяются в XSLT в едином паттерне:
[PT3] IdKeyPattern ::= 'id' '(' Literal ')'
| 'key' '(' Literal ',' Literal ')'
Этому паттерну соответствуют только узлы, принадлежащие результату одной из двух функций —
id
или
key
.
Оставим
детали использования ключей и
ID
– атрибутов на потом и вернемся к разбору вариантов синтаксиса паттернов.
□ Паттерну
IdKeyPattern '/' RelativePathPattern
соответствуют узлы, которые соответствуют образцу пути
, а его родитель в свою очередь имеет уникальный атрибут со значением
"index5"
.
□ Паттерн
IdKeyPattern '//' RelativePathPattern
аналогичен предыдущему: ему соответствуют узлы, которые соответствуют паттерну
RelativePathPattern
, отсчитанному от любого потомка или самого узла, входящего в
IdKeyPattern
. Например, паттерну
id('index5')//a/b
будет соответствовать любой дочерний элемент
b
элемента
a
, являющегося потомком элемента, уникальный атрибут которого имеет значение
index5
, или если он сам имеет такой атрибут.
Мы более подробно остановимся на ключевых паттернах, когда будем разбирать функции
id
и
key
, а пока обратимся к главной детали всех вышеперечисленных продукций — к образцу относительного пути,
RelativePathPattern
. Его продукция записывается в следующем виде:
[PT4] RelativePathPattern
::= StepPattern
| RelativePathPattern '/' StepPattern
| RelativePathPattern '//' StepPattern
Если сравнить это правило с упрощенной продукцией
RelativeLocationPath
, можно заметить совпадение с точностью до имен продукций. Образец относительного пути строится точно так же, как и обычный путь выборки — перечислением через разделяющие символы
"/"
и
"//"
шагов, в данном случае — шагов образца относительного пути.
простоты мы можем раскрыть эту продукцию, получив ее в следующем виде:
ChildOrAttributeAxisSpecifier
::= '@' ?
| 'child::'
| 'attribute::'
Тогда продукцию
StepPattern
тоже можно переписать:
StepPattern ::= NodeTest Predicate*
| '@' NodeTest Predicate*
| 'child::' NodeTest Predicate*
| 'attribute::' NodeTest Predicate*
Теперь стало совершенно очевидно, что шаг паттерна это не что иное, как подмножество шагов выборки, в которых ограничено множество осей навигации.
Таким образом, синтаксически паттерны отличаются от путей выборки тем, что в них можно использовать только две оси навигации (не считая
descendant-or-self
в виде оператора), но зато можно в качестве узла отсчета использовать узел, выбранный по своему уникальному атрибуту или по значению ключа.
Паттерны могут использоваться в XSLT в следующих атрибутах:
□ атрибуты
count
и
from
элемента
xsl:number
;
□ атрибут
match
элемента
xsl:key
;
□ атрибут
match
элемента
xsl:template
.
Последние два случая паттернов отличаются от первого тем, что в них нельзя использовать переменные. Определение вида
<xsl:template match="*[name = $name]">
...
</xsl:template>
будет некорректным.
Семантика паттернов
Остановимся подробнее на вопросе — что же означает "соответствие узла некоторому паттерну".
Прежде всего, заметим, что любой паттерн является также и XPath-выражением. Тогда строгое определение соответствия узла паттерну можно дать следующим образом.
Узел
X
соответствует паттерну
P
тогда и только тогда, когда существует такой узел
Y
, принадлежащий оси
ancestor-or-self
узла
X
, что множество, получаемое в результате вычисления выражения
P
в контексте узла
Y
будет содержать узел
X
.
Пример
Рассмотрим это определение на примере паттерна
body//а
. Строго говоря, узел будет соответствовать этому паттерну, если во множестве его предков (плюс сам узел) найдется такой узел, что множество
body//а
, вычисленное в его контексте, будет содержать проверяемый узел. На практике первые два элемента
а
приведенного ниже документа соответствуют этому паттерну, потому что существует элемент