12 Дополнительные функции

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

12.1 Множественные исходные документы

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

Функция document позволяет получить доступ к иным XML-документам помимо основного исходного документа.

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

Если первый аргумент функции document не был набором узлов, он преобразуется в строку как при вызове функции string. Полученная строка обрабатывается как ссылка URI, то есть, извлекается ресурс, идентифицируемый этим URI. Полученные таким образом данные обрабатываются как XML документ и в соответствии с моделью данных (см. [3 Модель данных]) строится дерево. Если при извлечении ресурса произошла ошибка, XSLT процессор может сигнализировать о ней. Если он этого не делает, то должен обработать ошибку сам, возвратив пустой набор узлов. Один из возможных типов ошибки извлечения ресурса связан с тем, что XSLT процессор не поддерживает схему, используемую данным URI. XSLT процессор не обязан поддерживать все возможные схемы URI. В документации для XSLT процессора должно быть указано, какие схемы URI поддерживаются этим процессором.

Если ссылка URI не содержит идентификатор фрагмента, возвращается набор узлов, содержащий только корневой узел документа. Если же ссылка URI содержит идентификатор фрагмента, то данная функция возвращает набор узлов из дерева, на которые указывает идентификатор фрагмента из этой ссылки URI. Семантика идентификатора фрагмента зависит от типа среды, полученного при извлечении URI. Если во время обработки идентификатора фрагмента возникла ошибка, XSLT процессор может сигнализировать об ошибке. Если он этого не делает, то должен обработать ошибку сам, вернув пустой набор узлов. Некоторые из возможных ошибок:

Данные, полученные в результате извлечения, обрабатываются как XML документ независимо от типа среды у результата извлечения. Если типом среды верхнего уровня является text, то он обрабатывается точно так же, как если бы тип среды был text/xml. В противном случае обработка производится так, как если бы тип среды был application/xml.

Замечание: Поскольку для верхнего уровня нет типа среды xml, данные с иным типом среды, чем text/xml или application/xml действительно могут быть XML.

Ссылка URI может быть относительной. Из набора узлов, представленного во втором аргументе, берется узел, который первым встретится в документе, и его базовый URI (см. [3.2 Базовый URI]) используется для преобразования относительных URI в абсолютные. Если второй аргумент опущен, то по умолчанию используется тот узел из стиля, который содержит выражение, включающее рассматриваемый вызов функции document. Заметим, что ссылка URI нулевой длины является ссылкой на документ, относительно которого эта ссылка URI разрешается. Таким образом, document("") ссылается на корневой узел данного стиля, а представление стиля в виде дерева в точности такое же как если бы в качестве исходного документа был взят XML документ, изначально содержащий этот стиль.

Если два документа идентифицируются одним и тем же URI, то они обрабатываются как один и тот же документ. Для сравнения используется абсолютный URI, к каковому приводится любой относительный URI, не содержащий каких-либо идентификаторов фрагментов. Два корневых узла обрабатываются как один и тот же узел, если оба взяты из одного и того же документа. Таким образом, следующее выражение всегда будет давать true:

generate-id(document("foo.xml"))=generate-id(document("foo.xml"))

Функция document дает возможность держать в одном наборе узлов узлы сразу из нескольких документов. Для такого набора узлов относительный порядок следования двух узлов, взятых из одного и того же документа - это обычный порядок следования в документе, заданный в XPath [XPath]. Относительный порядок следования двух узлов из различных документов определяется тем, как реализовано упорядочение документов, содержащих эти узлы. Помимо согласованности (для одного и того же набора документов реализация всегда должна давать один и тот же порядок следования) каких-либо иных ограничений на реализацию упорядочения документов нет.

12.2 Ключи

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

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

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

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

  2. названием ключа (расширенное имя)

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

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

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

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

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

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

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

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

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

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

<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>

Функция key может использоваться для извлечения ключа из других документов, нежели тот, в котором содержится текущий узел контекста. Предположим, к примеру, что документ содержит библиографические ссылки в формате <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>

12.3 Форматирование чисел

Функция: строка format-number(число, строка, строка?)

Функция format-number преобразует свой первый аргумент в строку, используя строку шаблона форматирования, представленную во втором аргументе, и десятичный формат, поименованый в третьем аргументе, либо десятичный формат по умолчанию, если третий аргумент отсутствует. Строка с шаблоном форматирования имеет синтаксис, определенный в JDK 1.1 для класса DecimalFormat. Строка шаблона форматирования представлена в локализованной нотации: десятичный формат определяет, какие именно символы в шаблоне имеют специальное значение (за исключением символа кавычки, который не подлежит локализации). Шаблон формата не должен содержать символ денежной единицы (#x00A4), такая возможность была добавлена уже после первой реализации JDK 1.1. Названием десятичного формата должно быть QName, которое приводится к расширенному имени как описано в главе [2.4 Полные имена]. Если в стиле отсутствует декларация десятичного формата с заданным расширенным именем, фиксируется ошибка.

Замечание: Разработчики не обязаны использовать именно реализацию JDK 1.1, а сам анализатор не обязательно реализовывать на Java.
Замечание: Чтобы контролировать округление чисел, в стилях могут использоваться другие функции из XPath.

<!-- Category: top-level-element -->
<xsl:decimal-format
  name = qname
  decimal-separator = char
  grouping-separator = char
  infinity = string
  minus-sign = char
  NaN = string
  percent = char
  per-mille = char
  zero-digit = char
  digit = char
  pattern-separator = char />

Элемент xsl:decimal-format декларирует десятичный формат, который управляет интерпретацией шаблона формата, используемого в функции format-number. Если присутствует атрибут name, данный элемент декларирует именованный десятичный формат. В остальных случаях декларируется десятичный формат по умолчанию. Значением атрибута name является QName, которое приводится к расширенному имени как было описано в главе [2.4 Полные имена]. Если десятичный формат по умолчанию или десятичный формат с данным именем, декларируется несколько раз, фиксируется ошибка (даже при различном приоритете импорта). Это можно делать только если каждый раз для всех атрибутов декларированы одни и те же значения (принимая во внимание все значения по умолчанию).

Остальные атрибуты xsl:decimal-format соответствуют методам класса DecimalFormatSymbols из JDK 1.1. Для каждой пары методов get/set в элементе xsl:decimal-format определен соответствующий атрибут.

Следующие атрибуты задают интерпретацию символов в шаблоне формата, а также указывают символы, которые могут появиться в результате форматирования числа:

Следующие атрибуты задают интерпретацию символов в шаблоне формата:

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

12.4 Различные дополнительные функции

Функция: набор-узлов current()

Функция current возвращает набор узлов, состоящий из единственного члена - текущего узла. Для внешнего выражения (выражения, которое не является частью другого выражения), текущий узел всегда тот же самый, что и узел контекста. Таким образом,

<xsl:value-of select="current()"/>

означает то же самое, что и

<xsl:value-of select="."/>

Однако внутри квадратных скобок текущий узел обычно отличается от узла контекста. Например,

<xsl:apply-templates select="//glossary/item[@name=current()/@ref]"/>

будет обрабатывать все элементы item, которые имеют родителем элемент glossary, а также имеют атрибут name, значение которого равно значению атрибута ref текущего узла. Этот вариант отличается от

<xsl:apply-templates select="//glossary/item[@name=./@ref]"/>

который означает то же самое, что

<xsl:apply-templates select="//glossary/item[@name=@ref]"/>

а потому будет обрабатывать все элементы item, которые имеют родителем элемент glossary, а также имеют атрибуты name и ref с одинаковыми значениями.

Если в шаблоне использовать функцию current, фиксируется ошибка.

Функция: строка unparsed-entity-uri(строка)

unparsed-entity-uri возвращает URI неразобранной сущности с заданным именем, находящейся в том же документе, что и узел контекста (см. [3.3 Неразобранные сущности]). Если такой сущности нет, функция возвращает пустую строку.

Функция: строка generate-id(список-узлов?)

Функция generate-id возвращает строку, уникальным образом идентифицирующую тот узел из набора узлов, представленного в аргументе, который первым встретится в документе. Уникальный идентификатор должен состоять из алфавитно-цифровых символов ASCII и должен начинаться с буквы. Таким образом, данная строка синтаксическим соответствует имени XML. Разработчик волен генерировать идентификатор любым удобным ему способом при условии, что для одного и того же узла всегда генерируется один и тот же идентификатор, а для разных узлов всегда генерируются разные идентификаторы. Процессор не обязан генерировать одни и те же идентификаторы при каждом преобразовании документа. Нет гарантий, что сгенерированный уникальный идентификатор не совпадет с каким-либо уникальным ID, указанным у исходном документе. Если в аргументе был дан пустой набор узлов, функция возвращает пустую строку. Если аргумент отсутствует, то по умолчанию используется узел контекста.

Функция: object system-property(строка)

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

Реализации процессора должны представлять следующие системные свойства, относящиеся к пространству имен XSLT:

Назад | Содержание | Вперед