Алексей Валиков - Технология XSLT
Вызов document(node-set, node-set)
Если функции document передаются два множества узлов, то вычисление результата можно описать примерно следующим образом:
□ каждый из узлов первого аргумента преобразуется в строковый вид;
□ для каждого из полученных значений выполняется вызов типа document(string, node-set);
□ результирующие множества объединяются.
Иными словами, document(node-set, node-set) работает через document(string, node-set) точно так же, как document(node-set) работает через document(string). Разница лишь в том, что в первом случае базовый URI будет изменен.
Другие дополнительные функции XSLT
Функция current
Выражение для этой функции имеет вид:
node-set current()
Функция current возвращает множество, состоящее из текущего узла преобразования.
Мы часто использовали термины текущий узел и узел контекста как синонимы: действительно, в большинстве случаев между ними нет никакой разницы, текущий узел преобразования совпадает с узлом контекста вычисления выражений. Однако бывают ситуации, когда они являются двумя различными узлами.
Представим себе, что нам нужно выбрать элементы item со значением атрибута source, равным значению этого атрибута текущего узла. Очевидно, путь выборки будет выглядеть как item[предикат], где предикат определяет условие равенства атрибутов текущего и выбираемого. Но как записать это условие? Предикат будет вычисляться в контексте проверяемого элемента item, значит, все относительные пути выборки типа @source или ./@source или self::item/@source будут отсчитываться именно от проверяемого элемента. В этом случае узел контекста и текущий узел преобразования — не одно и то же.
Для того чтобы обратиться в предикате именно к текущему узлу, следует использовать функцию current:
item[@source=current()/@source]
Это выражение выберет все дочерние элементы item текущего узла, значение атрибута source которых будет таким же, как и у него.
Функция unparsed-entity-uri
Выражение для этой функции следующее:
string unparsed-entity-uri(string)
Функция unparsed-entity-uri возвращает уникальный идентификатор ресурса, который соответствует неразбираемой внешней сущности, имя которой передано как аргумент.
ПримерОписывая синтаксис XML, мы приводили пример документа, который использовал неразбираемые внешние сущности.
Листинг 8.67. Входящий документ использующий неразбираемые внешние сущности<!DOCTYPE menu [
<!ELEMENT menu (menuitem*)>
<!ELEMENT menuitem EMPTY>
<!ATTLIST menuitem
image ENTITY #REQUIRED
title CDATA #REQUIRED
href CDATA #REQUIRED>
<!NOTATION gif SYSTEM "gif-viewer.exe">
<!NOTATION jpg SYSTEM "jpg-viewer.exe">
<!ENTITY news SYSTEM "news.gif" NDATA gif>
<!ENTITY products SYSTEM "prod.jpg" NDATA jpg>
<!ENTITY support SYSTEM "support.gif" NDATA gif>
]>
<menu>
<menuitem image="news" title="News" href="news.htm"/>
<menuitem image="products" title="Products" href="prods.htm"/>
<menuitem image="support" title="Support" href="support.htm"/>
</menu>
Для того чтобы вычислить местоположение графических файлов, соответствующих пунктам этого меню, нужно будет использовать функцию unparsed- entity-uri. Аргументом этой функции в данном случае будет значение атрибута image, ведь именно этот атрибут задает имя неразбираемой сущности, которая соответствует изображению пункта меню. Преобразование такого документа в HTML будет иметь приблизительно следующий вид.
Листинг 8.68. Преобразование, использующее функцию unparsed-entity-uri<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method="html"
indent="yes"/>
<xsl:template match="menu">
<table>
<xsl:apply-templates select="menuitem"/>
</table>
</xsl:template>
<xsl:template match="menuitem">
<tr>
<td>
<A alt="{@title}" href="{@href}">
<img src="{unparsed-entity-uri(@image)}"/>
</A>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Результат преобразования приведен на следующем листинге.
Листинг 8.69. Выходящий документ<table>
<tr>
<td>
<A alt="News" href="news.htm">
<img src="file:/C:/XML/news.gif"/>
</A>
</td>
</tr>
<tr>
<td>
<A alt="Products" href="prods.htm">
<img src="file:/C:/XML/prod.jpg"/>
</A>
</td>
</tr>
<tr>
<td>
<A alt="Support" href="support.htm">
<img src="file:/С:/XML/support.gif"/>
</A>
</td>
</tr>
</table>
Остается только добавить, что unparsed-entity-uri — это единственная функция, которая позволяет работать с неразбираемыми сущностями. Никаких средств для обработки нотаций и вспомогательных приложений, которые им соответствуют, в XSLT нет. Сказывается тот факт, что неразбираемые сущности и нотации очень редко используются в документах, поэтому их поддержка в XSLT минимальна.
Функция generate-id
Синтаксическая конструкция этой функции:
string generate-id(node-set?)
Функция generate-id возвращает уникальный строковый идентификатор первого в порядке просмотра документа узла, передаваемого ей в виде аргумента. Если аргумент опущен, функция возвращает уникальный идентификатор контекстного узла. Если аргументом является пустое множество, функция должна возвращать пустую строку.
Функция generate-id обладает следующими свойствами.
□ Функция generate-id возвращает для двух узлов один и тот же идентификатор тогда и только тогда, когда эти два узла совпадают. Это означает, что во время выполнения одного преобразования функция generate-id будет возвращать один идентификатор для одного и того же узла, а для разных узлов generate-id обязательно возвратит разные идентификаторы.
□ Возвращаемый идентификатор состоит только из цифр и букв ASCII и начинается буквой, то есть синтаксически является корректным XML-именем и может использоваться как имя элемента, атрибута, как значение ID-атрибута или в любом другом месте, где могут использоваться имена XML.
Кроме этого спецификация оговаривает следующие важные положения, которые мы приведем ниже.
□ Процессор не обязан генерировать один и тот же идентификатор при разных выполнениях преобразования одного и того же документа. Иными словами, если в понедельник процессор X при выполнении преобразования Y сгенерирует для узла Z документа D идентификатор I, то во вторник тот же процессор X при выполнении того же преобразования Y с тем же документом D может сгенерировать для того же самого узла Z совершенно другой, отличный от I идентификатор.
□ Форма возвращаемого идентификатора может быть произвольной, но при этом она должна удовлетворять описанному выше синтаксису. Это означает, что каждый процессор может по-своему генерировать идентификатор. Спецификация не определяет никакого стандартного метода реализации функции generate-id.
□ Генерируемый идентификатор может совпадать, а может и не совпадать со значениями уникальных атрибутов, то есть атрибутов, тип данных которых объявлен в блоке DTD как ID.
Помимо очевидного применения, например, для явного задания уникального идентификатора в выходящем документе, функция generate-id совершено неожиданным образом облегчает задачи группировки. Подробнее об этом мы расскажем в главе 11.
ПримерПредположим, что в наших XML-документах изменилась логическая схема: теперь каждый элемент item должен обладать уникальным атрибутом id.
Выполнить задачу конвертации может простое преобразование.
Листинг 8.70. Преобразование<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>