Язык преобразований XSL

Ключи


Ключи дают возможность работать с документами, имеющими неявную структуру перекрестных ссылок. В XML атрибуты типа ID, IDREF и IDREFS создают механизм, позволяющий делать в документах XML перекрестные ссылки явными. В XSLT этот механизм реализуется с помощью функции из XPath. Однако этот механизм имеет ряд ограничений:

  • Атрибуты ID должны быть декларированы в качестве таковых в DTD. Если атрибут ID декларирован в качестве такового лишь во внешнем наборе DTD, то и распознаваться как ID атрибут он будет только тогда, когда процессор XML прочтет этот внешний набор DTD. Однако спецификация XML вовсе не обязует XML процессоры читать этот внешний DTD, а потому процессоры вполне могут этого не делать, особенно если для документа было декларировано standalone="yes".

    Документ может иметь только один набор уникальных ID. Не может быть несколько независимых наборов уникальных атрибутов ID.

    ID элемента может быть задано лишь в атрибуте. Он не может быть задан ни содержимым элемента, ни элементом, являющимся непосредственным потомком.

    ID должен быть именем XML. Например, он не может содержать пробелов.

    Элемент может содержать не более одного ID.

    Любой конкретный ID может принадлежать только одному элементу.

Из-за этих ограничений документы XML иногда имеют структуру перекрестных ссылок, которая не была явно декларирована атрибутами ID/IDREF/IDREFS.

Ключ определяется тремя параметрами:

узлом, которому принадлежит этот ключ

названием ключа ()

значением ключа (строка)

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



Таким образом, ключ - это такой тип обобщенного ID, на который не распространяются ограничения, принятые для ID в XML:

Ключи декларируются в стиле с помощью элементов xsl:key.

Ключи имеют как название, так и значение. Каждое название ключа можно рассматривать как отдельное, независимое пространство идентификаторов.


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

Значением ключа может быть произвольная строка и это не обязательно должно быть имя.

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

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

<!-- Category: top-level-element -->
<xsl:key
name = qname
  match = pattern
  use = expression />

Чтобы декларировать ключи, используется элемент xsl:key. Название создаваемого ключа задает атрибут name. Значением атрибута name является , которое приводится к расширенному имени как было описано в главе . Атрибут match является . Элемент xsl:key дает информацию о ключах во всех узлах, которые соответствуют шаблону, заданному атрибутом match. Атрибут use дает , определяющее значение ключа. Для каждого узла, соответствующего шаблону, это выражение вычисляется отдельно. Если результатом вычисления является набор узлов, то для каждого узла в этом наборе считается, что узлы, соответствующие представленному шаблону, имеют ключ с указанным именем, значением которого является строковое значение данного узла из набора. В противном случае, результат вычисления преобразуется в строку, и соответствующий шаблону узел получает ключ с указанным названием и значением, соответствующим этой строке. Таким образом, узел x имеет ключ с названием y и значением z тогда и только тогда, когда имеется элемент xsl:key, такой что:

x соответствует шаблону, указанному в атрибуте match данного элемента xsl:key,

атрибут name элемента xsl:key имеет значение, равное y, и

если выражение, заданное атрибутом use элемента xsl:key, обрабатывается с текущим узлом x, а в качестве текущего набора узлов используется список, состоящий из одного x, и при этом результатом является объект u, то либо z равно результату преобразования объекта u в строку (как при вызове функции ), либо u - это набор узлов, а z равно строковому значению одного или нескольких узлов из набора u.



Заметим также, что одному узлу может соответствовать несколько элементов xsl:key. В этом случае будут использованы все совпавшие элементы xsl:key, даже если они имеют разный .

Если значение атрибутов use или match содержит , фиксируется ошибка.

Функция: набор-узлов key(строка, объект)

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

Например, дана декларация

<xsl:key name="idkey" match="div" use="@id"/>

выражение key("idkey",@ref) возвратит тот же набор узлов, что и id(@ref), при условии, что в исходном XML-документе был декларирован единственный атрибут ID:

<!ATTLIST div id ID #IMPLIED>

а атрибут ref текущего узла не содержит пробельных символов.

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

<prototype name="key" return-type="node-set"> <arg type="string"/> <arg type="object"/> </prototype>

а чтобы обратиться к названию функции используется элемент function

<function>key</function>

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

<xsl:key name="func" match="prototype" use="@name"/> <xsl:template match="function"> <b> <a href="#{generate-id(key('func',.))}"> <xsl:apply-templates/> </a> </b> </xsl:template>



<xsl:template match="prototype"> <p><a name="{generate-id()}"> <b>Function: </b> ... </a></p> </xsl:template>

Функция может использоваться для извлечения ключа из других документов, нежели тот, в котором содержится текущий узел контекста. Предположим, к примеру, что документ содержит библиографические ссылки в формате <bibref>XSLT</bibref>, а также есть отдельный XML-документ bib.xml, содержащий библиографическую базу данных с записями в формате:

<entry name="XSLT">...</entry>

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

<xsl:key name="bib" match="entry" use="@name"/>

<xsl:template match="bibref"> <xsl:variable name="name" select="."/> <xsl:for-each select="document('bib.xml')"> <xsl:apply-templates select="key('bib',$name)"/> </xsl:for-each> </xsl:template>


Содержание раздела