В этом разделе мы будем рассматривать две конструкции, позволяющие манипулировать множествами узлов посредством ключей — это элемент
xsl:key
, который определяет в преобразовании именованный ключ, и функция
key
, которая возвращает множество узлов, идентифицирующихся заданными значениями ключей.
Элемент xsl:key
Синтаксис элемента несложен:
<xsl:key
name="имя"
match="паттерн"
use="выражение"/>
Элемент
верхнего уровня
xsl:key
определяет в преобразовании ключ именем, заданным в значении атрибута
name
, значением которого для каждого узла документа, соответствующего паттерну
match
, будет результат вычисления выражения, заданного в атрибуте
use
. Ни атрибут
use
, ни атрибут
match
не могут содержать переменных.
Пример
В нашем примере элементы
item
идентифицируются значениями своих атрибутов
source
. Для их идентификации мы можем определить ключ с именем
src
следующим образом:
<xsl:key name="src" match="item" use="@source"/>
Следуя строгому определению, данному в спецификации языка, ключом называется тройка вида
(node, name, value)
, где
node
— узел,
name
— имя и
value
— строковое значение ключа. Тогда элементы
xsl:key
, включенные в преобразование, определяют множество всевозможных ключей обрабатываемого документа. Если этому множеству принадлежит ключ, состоящий из узла
x
, имени
у
и значения
z
, говорят, что узел
x
имеет ключ с именем
у
и значением
z
или что ключ
у
узла
x
равен
z
.
Пример
Ключ
src
из предыдущего примера определяет множество, которое состоит из следующих троек:
(<item name="A".../>, 'src', 'a')
(<item name="B".../>, 'src', 'b')
(<item name="C".../>, 'src', 'a')
(<item name="D".../>, 'src', 'c')
...
(<item name="H".../>, 'src', 'a')
В соответствии с нашими определениями мы можем сказать, что элемент
<item source="b" name="B"/>
имеет ключ с именем
"src"
и значением
"b"
или что ключ
"src"
элемента
<item source="a" name="H"/>
равен
"a"
.
Для того чтобы обращаться к множествам узлов по значениям их ключей, в XSLT существует функция
key
, о которой мы сейчас и поговорим.
Функция key
Ниже приведена синтаксическая конструкция данной функции:
node-set key(string, object)
Итак, элементы
xsl:key
нашего преобразования
определили множество троек
(node, name, value)
. Функция
key(key-name, key-value)
выбирает все узлы x такие, что значение их ключа с именем
key-name
(первым аргументом функции) равно
key-value
(второму аргументу функции).
Пример
Значением выражения
key('src', 'a')
будет множество элементов
item
таких, что значение их ключа
"src"
будет равно
"а"
. Попросту говоря, это будет множество объектов источника
"а"
.
Концепция ключей довольно проста, и существует великое множество аналогий в других языках программирования: от хэш-функций до ключей в реляционных таблицах баз данных. По всей вероятности, читателю уже встречалось что-либо подобное.
Но не следует забывать, что язык XSLT — довольно нетрадиционный язык и с точки зрения синтаксиса, и с точки зрения модели данных. Как следствие, ключи в нем имеют довольно много скрытых нюансов, которые очень полезно знать и понимать. Мы попытаемся как можно более полно раскрыть все эти особенности.
Определение множества ключей
Не представляет особой сложности определение множества ключей в случае, если в определении они идентифицируются строковыми выражениями. Например, в следующем определении
Очевидно, это уже гораздо более сложный, но, тем не менее, вполне реальный случай, не вписывающийся в определения, которые давались до сих пор. Мы говорили лишь о том, что множество ключей определяется элементами
xsl:key
преобразования, но как именно оно определяется — оставалось доселе загадкой. Восполним этот пробел, дав строгое определение множеству ключей.
Узел
x
обладает ключом с именем
у
и строковым значением
z
тогда и только тогда, когда в преобразовании существует элемент
xsl:key
такой, что одновременно выполняются все нижеперечисленные условия:
□ узел
x
соответствует паттерну, указанному в его атрибуте
match
;
□ значение его атрибута
name
равно имени
y
;
□ результат
u
вычисления выражения, указанного в значении атрибута
use
в контексте текущего множества, состоящего из единственного узла
x
, удовлетворяет одному из следующих условий:
•
u
является множеством узлов и
z
равно одному из их строковых значений;
•
u
не является множеством узлов и
z
равно его строковому значению.
Без сомнения, определение не из простых. Но как бы мы действовали, если бы физически создавали в памяти множество ключей? Ниже представлен один из возможных алгоритмов:
□ для каждого элемента
xsl:key
найти множество узлов документа, удовлетворяющих его паттерну