<xsl:key> XSLT

Элемент xsl:key определяет в преобразовании именованный ключ.

Элемент верхнего уровня xsl:key определяет в преобразовании ключ именем, заданным в значении обязательного атрибута name, значением которого для каждого узла документа, соответствующего обязательному паттерну match, будет результат вычисления выражения, заданного в обязательном атрибуте use. Ни атрибут use, ни атрибут match не могут содержать переменных.

Элементы-родители:

Синтаксис

XSLT 1.0

<xsl:key
    name = "имя"
    match = "паттерн"
    use = "выражение" />

Атрибуты

  • nameобязательный атрибут, определяет имя ключа.
  • matchобязательный атрибут, выражение XPath, которое определяет узлы, индексируемые по данному ключу.
  • useобязательный атрибут, выражение XPath, которое определяет свойство индексируемых узлов, используемое для выборки узлов из индекса.

Спецификация

XSLT 2.0

<xsl:key
    name = "имя"
    match = "паттерн"
    use = "выражение"
    collation = "uri">
    <!-- Содержимое: sequence-constructor -->
</xsl:key>

Атрибуты

  • nameобязательный атрибут, определяет имя ключа.
  • matchобязательный атрибут, выражение XPath, которое определяет узлы, индексируемые по данному ключу.
  • useнеобязательный атрибут, выражение XPath, которое определяет свойство индексируемых узлов, используемое для выборки узлов из индекса. В XSLT 2.0 этот атрибут является необязательным. Элемент <xsl:key> может содержать конструктор последовательности, который создает или выбирает индексируемые узлы.
  • collationнеобязательный атрибут, определяет последовательность упорядочения, используемую для проверки равенства двух значений ключа.

XSLT 3.0

<xsl:key
    name = eqname
    match = pattern
    use? = expression
    composite? = boolean
    collation? = uri >
    <!-- Content: sequence-constructor -->
</xsl:key>

Описание и примеры

Прежде чем мы приступим к разбору ключей, которые являются одной из самых мощных концепций языка XSLT, попробуем решить одну несложную задачку.

Листинг 8.19. Входящий документ

<items>
    <item source="a" name="A"/>
    <item source="b" name="B"/>
    <item source="a" name="C"/>
    <item source="c" name="D"/>
    <item source="b" name="E"/>
    <item source="b" name="F"/>
    <item source="c" name="G"/>
    <item source="a" name="H"/>
</items>

Пусть входящий документ представляет собой список объектов (элементов item), каждый из которых имеет имя (атрибут name) и источник (атрибут source). Требуется сгруппировать объекты по своим источникам и получить документ приблизительно следующего вида.

Листинг 8.20. Требуемый результат

<sources>
    <source name="a">
        <item source="a" name="A"/>
        <item source="a" name="C"/>
        <item source="a" name="H"/>
    </source>
    <source name="b">
        <item source="b" name="B"/>
        <item source="b" name="E"/>
        <item source="b" name="F"/>
    </source>
    <source name="c">
        <item source="c" name="D"/>
        <item source="c" name="G"/>
    </source>
</sources>

Первым шагом на пути решения этой задачи является формулировка в терминах XSLT предложения “сгруппировать объекты по своим источникам”. Источник каждого объекта определяется его атрибутом source, значит множество объектов, принадлежащих одному источнику “а”, будет определяться путем выборки

/items/item[@source='a']

Тогда для каждого элемента item в его группу войдут элементы, которые будут выбраны выражением

/items/item[@source=current()/@source]

Попробуем использовать этот факт в следующем шаблоне:

<xsl:template match="item">
    <source name="{@source}">
        <xsl:copy-of select="/items/item[@source=current()/@source]"/>
    </source>
</xsl:template>

Как и ожидалось, при применении этого правила к элементам item для каждого из них будет создана группа, принадлежащая тому же источнику, — уже хороший результат, но в условии требуется создать по группе не для каждого объекта, а для каждого источника. Чтобы достичь этого, можно создавать группу только для первого объекта, принадлежащего ей. Провести такую проверку опять же несложно: объект будет первым в группе тогда и только тогда, когда ему не предшествуют другие, элементы item, принадлежащие тому же источнику. Иначе говоря, создаем группы только для тех элементов, для которых выражение

preceding-sibling::item[@source=current()/@source]

будет возвращать пустое множество.

С небольшими добавлениями искомое преобразование целиком будет иметь вид.

Листинг 8.21. Преобразование

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="items">
        <sources>
            <xsl:apply-templates/>
        </sources>
    </xsl:template>
    <xsl:template match="item">
        <xsl:choose>
            <xsl:when test="preceding-sibling::item[@source=current()/@source]"/>
            <xsl:otherwise>
                <source name="{@source}">
                    <xsl:copy-of select="self::node() | following-sibling::item[@source=current()/@source]"/>
                </source>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Бесспорно, решение было несложным, но довольно громоздким. Самым же узким местом в этом преобразовании является обращение к элементам item источника текущего элемента посредством сравнения атрибутов source.

Проблема совершенно стандартна для многих преобразований: нужно выбирать узлы по определенным признакам, причем делать это нужно как можно более эффективно. Хорошо, что в нашем документе было всего восемь элементов item, но представьте себе ситуацию, когда элементов действительно много.

Проблема, которую мы подняли, достаточно серьезна. Она состоит в оптимизации поиска узлов с определенными свойствами в древовидно организованной структуре.

Попробуем разобраться в смысле фразы “узел обладает определенными свойствами”. Очевидно, это означает, что для этого узла выполняется некое логическое условие, иначе говоря, некий предикат обращается в “истину”.

Однако какого именно типа условия мы чаще всего проверяем? Анализируя различные классы задач, можно придти к выводу, что в большинстве случаев предикаты являются равенствами — выражениями, которые обращаются в “истину” тогда и только тогда, когда некоторый параметр узла, не зависящий от текущего контекста, равен определенному значению. В нашем примере смысл предиката на самом деле состоит не в том, чтобы проверить на истинность выражение @source=current()/@source, а в том, чтобы проверить на равенство @source и current()/@source.

Если переформулировать это для общего случая, то нам нужно выбрать не те узлы, для которых истинно выражение A=B, скорее нужно выбрать те, для которых значение A равно значению B. Иначе говоря, узел будет идентифицироваться значением B своего свойства A. И если мы заранее вычислим значения свойств A, проблема поиска узлов в дереве сведется к классической проблеме поиска элементов множества (в нашем случае — узлов дерева) по определенным значениям ключей (в нашем случае — значениями свойств A).

Чтобы пояснить это, вернемся к нашему примеру: мы ищем элементы item со значением атрибута source, равным заданному. Свойством, идентифицирующим эти элементы, в данном случае будут значения их атрибутов source, которые мы можем заранее вычислить и включить в табл. 8.2.

Таблица 8.2. Значения атрибута source элементов item

Идентификатор (значение атрибута source) Элемент item
a <item source=”a” name=”A”/>
a <item source=”a” name=”C”/>
a <item source=”a” name=”H”/>
b <item source=”b” name=”B”/>
b <item source=”b” name=”E”/>
b <item source=”b” name=”F”/>
c <item source=”c” name=”D”/>
c <item source=”c” name=”G”/>

Таким образом, значение “c” идентифицирует объекты с именами D и G, а значение “a” — объекты с именами A, C и H, причем находить соответствующие элементы в таблице по их ключевому свойству не составляет никакого труда.

Несмотря на то, что произведенные нами манипуляции чрезвычайно просты (и настолько же эффективны), процессор вряд ли в общем случае сможет сделать что-либо подобное сам, и потому очень важной является возможность явным образом выделять в XSLT-преобразованиях ключевые свойства множеств узлов.

В этом разделе мы будем рассматривать две конструкции, позволяющие манипулировать множествами узлов посредством ключей — это элемент xsl:key, который определяет в преобразовании именованный ключ, и функция key, которая возвращает множество узлов, идентифицирующихся заданными значениями ключей.

Пример 1

В нашем примере элементы item идентифицируются значениями своих атрибутов source. Для их идентификации мы можем определить ключ с именем src следующим образом:

<xsl:key name="src" match="item" use="@source"/>

Следуя строгому определению, данному в спецификации языка, ключом называется тройка вида (node, name, value), где node — узел, name — имя и value — строковое значение ключа. Тогда элементы xsl:key, включенные в преобразование, определяют множество всевозможных ключей обрабатываемого документа. Если этому множеству принадлежит ключ, состоящий из узла x, имени y и значения z, говорят, что узел x имеет ключ с именем y и значением z или что ключ y узла x равен z.

Пример 2

Ключ 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 (второму аргументу функции).

Пример 3

Значением выражения key('src', 'a') будет множество элементов item таких, что значение их ключа “src” будет равно “a”. Попросту говоря, это будет множество объектов источника “a”.

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

Но не следует забывать, что язык XSLT — довольно нетрадиционный язык и с точки зрения синтаксиса, и с точки зрения модели данных. Как следствие, ключи в нем имеют довольно много скрытых нюансов, которые очень полезно знать и понимать. Мы попытаемся как можно более полно раскрыть все эти особенности.

Определение множества ключей

Не представляет особой сложности определение множества ключей в случае, если в определении они идентифицируются строковыми выражениями. Например, в следующем определении

<xsl:key name="src" match="item" use="string(@source)"/>

атрибут use показывает, что значением ключа src элемента item будет значение атрибута source. Но что можно сказать о следующем определении:

<xsl:key name="src" match="item" use="@*"/>

Очевидно, это уже гораздо более сложный, но, тем не менее, вполне реальный случай, не вписывающийся в определения, которые давались до сих пор. Мы говорили лишь о том, что множество ключей определяется элементами xsl:key преобразования, но как именно оно определяется — оставалось доселе загадкой. Восполним этот пробел, дав строгое определение множеству ключей.

Узел x обладает ключом с именем y и строковым значением z тогда и только тогда, когда в преобразовании существует элемент xsl:key такой, что одновременно выполняются все нижеперечисленные условия:

  • узел x соответствует паттерну, указанному в его атрибуте match;
  • значение его атрибута name равно имени y;
  • результат u вычисления выражения, указанного в значении атрибута use в контексте текущего множества, состоящего из единственного узла x, удовлетворяет одному из следующих условий:
    • u является множеством узлов и z равно одному из их строковых значений;
    • u не является множеством узлов и z равно его строковому значению.

Без сомнения, определение не из простых. Но как бы мы действовали, если бы физически создавали в памяти множество ключей? Ниже представлен один из возможных алгоритмов:

  • для каждого элемента xsl:key найти множество узлов документа, удовлетворяющих его паттерну match (множество X);
  • для каждого из найденных узлов (x ? X) вычислить значение выражения атрибута use (значение u(x));
  • если u(x) является множеством узлов (назовем его Ux), то для каждого uxi ? Ux создать ключ (x, n, string(uxi)), где n — имя ключа (значение атрибута name элемента xsl:key);
  • если u(x) является объектом другого типа (назовем его ux), создать ключ (x, n, string(ux)).

Пример 4

Найдем множество ключей, создаваемое определением

<xsl:key name="src" match="item" use="@*"/>

Имена всех ключей будут одинаковы и равны “src”. Множество x узлов, удовлетворяющих паттерну item, будет содержать все элементы item обрабатываемого документа. Значением выражения, заданного в атрибуте use, будет множество всех узлов атрибутов каждого из элементов item. Таким образом, множество узлов будет иметь следующий вид:

(<item name="А".../>, 'src', 'a')
(<item name="А".../>, 'src', 'A')
(<item name="В".../>, 'src', 'b')
(<item name="В".../>, 'src', 'В')
(<item name="С".../>, 'src', 'а')
(<item name="С".../>, 'src', 'С')
(<item name="D".../>, 'src', 'с')
(<item name="D".../>, 'src', 'D')
...
(<item name="H".../>, 'src', 'a')
(<item name="H".../>, 'src', 'H')

В итоге функция key('src', 'a') будет возвращать объекты с именами A, C и H, а функция key('src', 'A') — единственный объект с именем A (поскольку ни у какого другого элемента item нет атрибута со значением “A”).

Необходимо сделать следующее замечание: совершенно необязательно, чтобы процессор действительно физически создавал в памяти множества ключей. Это множество определяется чисто логически — чтобы было ясно, что же все-таки будет возвращать функция key. Процессоры могут вычислять значения ключей и искать узлы в документе и во время выполнения, не генерируя ничего заранее. Но большинство процессоров, как правило, все же создают в памяти определенные структуры для манипуляций с ключами. Это могут быть хэш-таблицы, списки, простые массивы или более сложные нелинейные структуры, упрощающие поиск, — важно другое. Важно то, что имея явное определение ключа в xsl:key, процессор может производить такую оптимизацию.

Использование нескольких ключей в одном преобразовании

В случае, когда к узлам в преобразовании нужно обращаться по значениям различных свойств, можно определить несколько ключей — каждый со своим именем. Например, если мы хотим в одном случае обращаться к объектам, принадлежащим одному источнику, а во втором — к объектам с определенными именами, мы можем определить в документе два ключа — один с именем src, второй — с именем name:

<xsl:key name="src" match="item" use="@source"/>
<xsl:key name="name" match="item" use="@name"/>

Множество ключей, созданных этими двумя определениями, будет выглядеть следующим образом:

(<item name="А".../>, 'src', 'а')
(<item name="А".../>, 'name', 'А')
(<item name="В".../>, 'src', 'b')
(<item name="В".../>, 'name', 'В')
(<item name="C".../>, 'src', 'a')
(<item name="C".../>, 'name', 'С')
(<item name="D".../>, 'src', 'с')
(<item name="D".../>, 'name', 'D')
...
(<item name="H".../>, 'src', 'a')
(<item name="H".../>, 'name', 'H')

В этом случае функция key('src', 'a') возвратит объекты с именами A, C и H, а функция key('name', 'A') — объект с именем A.

Имя ключа является расширенным именем. Оно может иметь объявленный префикс пространства имен, например

<xsl:key name="data:src" match="item" use="@source" xmlns:data="urn:user-data"/>

В этом случае функция key(key-name, key-value) будет возвращать узлы, значение ключа с расширенным именем key-name которых равно key-value. Совпадение расширенных имен определяется как обычно — по совпадению локальных частей и URI пространств имен.

Использование нескольких определений одного ключа

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

Пример 5

Предположим, что в нашем документе имеется несколько элементов item, в которых не указано значение атрибута source, но по умолчанию мы будем причислять их к источнику a. Соответствующие ключи будут определяться следующим образом:

<xsl:key name="src" match="item[@source]" use="@source"/>
<xsl:key name="src" match="item[not(@source)]" use="'a'"/>

То есть для тех элементов item, у которых есть атрибут source, значением ключа будет значение этого атрибута, для тех же элементов, у которых атрибута source нет, его значением будет “a”.

Для входящего документа вида

<items>
    <item source="a" name="A"/>
    <item source="b" name="B"/>
    <item source="a" name="C"/>
    <item source="c" name="D"/>
    ...
    <item source="a" name="H"/>
    <item name="I"/>
    <item name="J"/>
    <item name="K"/>
</items>

соответствующее множество ключей будет определяться следующим образом:

(<item name="А".../>, 'src', 'а')
(<item name="В".../>, 'src', 'b')
(<item name="С".../>, 'src', 'а')
(<item name="D".../>, 'src', 'c')
...
(<item name="H".../>, 'src', 'a')
(<item name="I".../>, 'src', 'a')
(<item name="J".../>, 'src', 'a')
(<item name="K".../>, 'src', 'a')

Функция key('src', 'a') возвратит объекты с именами A, C, H, I, J и K.

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

 <xsl:key name="src" match="item[not(@source)]" use="'#default'"/>

Это определение позволит по значению “#default” обращаться к объектам, принадлежащим источнику по умолчанию.

Использование множеств узлов в функции key

Функция key принимает на вход два аргумента: первым аргументом является строка, задающая имя ключа, в то время как вторым аргументом может быть объект любого типа. В том случае, если аргумент key-value в функции key(key-name, key-value) является множеством узлов, функция key возвратит все узлы, имеющие ключ key-name со значением, равным хотя бы одному из строковых значений узла множества key-value.

Пример 6

Предположим, что источники объектов будут сгруппированы следующим образом:

<sources>
    <source name="a"/>
    <source name="c"/>
</sources>

Для того чтобы вычислить множество элементов item, принадлежащих любому из источников данной группы, достаточно будет воспользоваться выражением вида

key('src', sources/source/@name)

Множество узлов, выбираемое путем sources/source/@name, будет содержать атрибуты name элементов source. Их строковые значения будут равны a и c, значит, наше выражение возвратит множество элементов item, значение атрибута source которых равно либо a либо c.

Использование ключей в нескольких документах

Ключи, определенные в преобразовании, могут использоваться для выбора узлов в различных обрабатываемых документах. Функция key возвращает узлы, которые принадлежат текущему документу, то есть документу, содержащему текущий узел. Значит, для того, чтобы выбирать узлы из внешнего документа, необходимо сделать текущим узлом один из узлов этого внешнего документа. Контекстный документ может быть легко изменен элементом xsl:for-each, например, для того, чтобы текущим документом стал документ a.xml, достаточно написать

<xsl:for-each select="document('а.xml')">
    <!-- Теперь текущим документом стал документ а.xml -->
</xsl:for-each>

Пример 7

Предположим, что нам нужно выбрать объекты, принадлежащие источнику a, причем принадлежность объектов определена в двух внешних документах, a.xml и b.xml.

Листинг 8.22. Входящий документ

<source name="a"/>

Листинг 8.23. Документ a.xml

<items>
    <item source="a" name="A"/>
    <item source="b" name="B"/>
    <item source="a" name="C"/>
    <item source="c" name="D"/>
</items>

Листинг 8.24. Документ b.xml

<items>
    <item source="b" name="E"/>
    <item source="b" name="F"/>
    <item source="c" name="G"/>
    <item source="a" name="H"/>
</items>

Листинг 8.25. Преобразование

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="src" match="item" use="@source"/>
    <xsl:template match="source">
        <xsl:variable name="name" select="@name"/>
        <xsl:copy>
            <xsl:for-each select="document('a.xml')|document('b.xml')">
                <xsl:copy-of select="key('src', $name)"/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.26. Выходящий документ

<source>
    <item source="a" name="A"/>
    <item source="a" name="C"/>
    <item source="a" name="H"/>
</source>

Составные ключи

В теории реляционных баз данных существует такое понятие, как составной ключ. Согласно определению К. Дж. Дейта [Дейт 1999], составной ключ — это “потенциальный ключ; состоящий из более чем одного атрибута”.

Хотя концепция ключей в XSLT сильно отличается от того, что называется ключом в реляционных БД, идея весьма и весьма интересна: использовать при обращении к множествам узлов не одно свойство, а некоторую их комбинацию.

Главная проблема состоит в том, что значение ключа в XSLT всегда является строкой, одним из самых примитивных типов. И выбирать множества узлов можно только по одному строковому значению за один раз. Ничего похожего на key(key-name, key-value-1, key-value-2, ...) для выбора узлов, первое свойство которых равно key-value-1, второе — key-value-2 и так далее, XSLT не предоставляет.

Выход достаточно очевиден: если значение ключа не может быть сложной структурой, оно должно выражать сложную структуру. Иными словами, раз значением составного ключа может быть только строка, то эта строка должна состоять из нескольких частей.

Пример 8

Предположим, что объекты с одинаковыми именами могут принадлежать различным источникам. Покажем, как с помощью ключей можно решить следующие задачи:

  • найти объект с определенным именем и источником;
  • найти объекты с определенным именем;
  • найти объекты с определенным источником.

Листинг 8.27. Входящий документ

<items>
    <item source="a" name="A"/>
    <item source="b" name="B"/>
    <item source="b" name="E"/>
    <item source="b" name="F"/>
    <item source="a" name="C"/>
    <item source="c" name="G"/>
    <item source="a" name="H"/>
    <item source="a" name="B"/>
    <item source="b" name="G"/>
    <item source="c" name="H"/>
    <item source="c" name="C"/>
    <item source="c" name="D"/>
    <item source="b" name="A"/>
    <item source="a" name="B"/>
    <item source="c" name="D"/>
    <item source="c" name="E"/>
    <item source="a" name="F"/>
</items>

Для элементов item мы будем генерировать ключи, значения которых будут состоять из двух частей — источника и имени, разделенных символом “-”. Для того чтобы решить одним ключом все три поставленные задачи, мы будем использовать для его определения три элемента xsl:key.

Листинг 8.28. Входящий документ

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="src" match="item" use="concat(@source,'-')"/>
    <xsl:key name="src" match="item" use="concat('-', @name)"/>
    <xsl:key name="src" match="item" use="concat(@source, '-', @name)"/>
    <xsl:template match="/">
        <result>
            <items source="a" name="B">
                <xsl:copy-of select="key('src', 'a-B')"/>
            </items>
            <items name="B">
                <xsl:copy-of select="key('src', '-B')"/>
            </items>
            <items source="a">
                <xsl:copy-of select="key('src', 'a-')"/>
            </items>
        </result>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.29. Выходящий документ

<result>
    <items source="a" name="B">
        <item source="a" name="B"/>
        <item source="a" name="B"/>
    </items>
    <items name="B">
        <item source="b" name="B"/>
        <item source="a" name="B"/>
        <item source="a" name="B"/>
    </items>
    <items source="a">
        <item source="a" name="A"/>
        <item source="a" name="C"/>
        <item source="a" name="H"/>
        <item source="a" name="B"/>
        <item source="a" name="B"/>
        <item source="a" name="F"/>
    </items>
</result>

У приведенного здесь способа формирования ключа есть определенные ограничения: необходимо иметь априорную информацию о строковых значениях каждого из свойств, составляющих наш композитный ключ для того, чтобы корректно формировать его строковые представления. Например, если бы в приведенном выше документе имена объектов и источников могли бы содержать символ “-”, было бы непонятно, к какому объекту относится составной ключ “a-b-c”: к объекту с источником a-b и именем c или к объекту с источником a и именем b-c. К счастью, в большинстве случаев такая информация имеется, и генерировать составные ключи не очень сложно.

Функция key в паттернах

Разбирая синтаксические правила построения паттернов, мы встретились с особой формой паттерна, в котором могла использоваться функция key. Приведем еще раз эту продукцию:

[PT3] IdKeyPattern ::= 'id' '(' Literal ')'
                   | 'key' '(' Literal ',' Literal ')'

Функция key(key-name, key-value) в паттерне будет соответствовать узлам, значение ключа key-name которых равняется или принадлежит объекту key-value. Это позволяет использовать возможности ключей при проверке узлов на соответствие образцу.

Пример 9

Предположим, что нам нужно по-особому обработать объекты, принадлежащие источнику a. Для этого мы можем создать шаблон следующего вида.

Листинг 8.30. Шаблон, использующий функцию key в паттерне

<xsl:template match="key('src', 'a')">
    <!-- Содержимое шаблона -->
</xsl:template>

Этот шаблон будет применяться к любым узлам, имеющим ключ src со значением a.

См. также

Ссылки

MDN xsl:key на MDN
MSDN xsl:key на MSDN