XSLT позволяет использовать уникальные атрибуты элементов при помощи функции id, которая возвращает множество, состоящее из узла, уникальный атрибут которого равен переданному ей значению, или пустое множество, если такого элемента нет.
Кроме того, XSLT предоставляет похожий механизм, механизм ключей, который выбирает узлы не по уникальным атрибутам, а по значениям именованных ключей, определенных в преобразовании. Для этого служит функция key.
Поскольку два этих механизма схожи по семантике, они определяются в XSLT в едином паттерне:
[PT3] IdKeyPattern ::= 'id' '(' Literal ')'
| 'key' '(' Literal ',' Literal ')'
Этому паттерну соответствуют только узлы, принадлежащие результату одной из двух функций — id или key.
Оставим детали использования ключей и ID-атрибутов на потом и вернемся к разбору вариантов синтаксиса паттернов.
□ Паттерну IdKeyPattern '/' RelativePathPattern соответствуют узлы, которые соответствуют образцу пути RelativePathPattern отсчитанного относительного узла, соответствующего IdKeyPattern. Например, узел соответствует паттерну id ('index5')/a/b, если он является элементом с именем b, его родителем является элемент а, а его родитель в свою очередь имеет уникальный атрибут со значением 'index5'.
□ Паттерн IdKeyPattern '//' RelativePathPattern аналогичен предыдущему: ему соответствуют узлы, которые соответствуют паттерну RelativePathPattern, отсчитанному от любого потомка или самого узла, входящего в IdKeyPattern. Например, паттерну id ('index5')//a/b будет соответствовать любой дочерний элемент b элемента a, являющегося потомком элемента, уникальный атрибут которого имеет значение index5, или если он сам имеет такой атрибут.
Мы более подробно остановимся на ключевых паттернах, когда будем разбирать функции id и key, а пока обратимся к главной детали всех вышеперечисленных продукций — к образцу относительного пути, RelativePathPattern. Его продукция записывается в следующем виде:
[PT4] RelativePathPattern
::= StepPattern
| RelativePathPattern '/' StepPattern
| RelativePathPattern '//' StepPattern
Если сравнить это правило с упрощенной продукцией RelativeLocationPath, можно заметить совпадение с точностью до имен продукций. Образец относительного пути строится точно так же, как и обычный путь выборки — перечислением через разделяющие символы '/' и '//' шагов, в данном случае — шагов образца относительного пути.
Эти шаги соответствуют продукции StepPattern, которая отличается от продукции Step только тем, что разрешает использовать только оси child и attribute.
[PT5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest
Predicate*
Продукция ChildOrAxisSpecifier описывает дескрипторы осей child и attribute в полном или сокращенном виде:
[P6] ChildOrAttributeAxisSpecifier
::= AbbreviatedAxisSpecifier
| ('child' | 'attribute') '::'
Для простоты мы можем раскрыть эту продукцию, получив ее в следующем виде:
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//а, вычисленное в его контексте, будет содержать проверяемый узел. На практике первые два элемента а приведенного ниже документа соответствуют этому паттерну, потому что существует элемент html, содержащий элемент body, потомками которого эти элементы а являются.
<html>
<body>
<a>
