Создание уникальных идентификаторов средствами XSLT

confguru

ExAdmin
Команда форума
Создание уникальных идентификаторов средствами XSLT

Автор: Боб Дишам, 3 октября 2001
Оригинал статьи: http://www.xml.com/pub/a/2001/10/03/unique-ids.html
Перевод: В.Ярошевич, 16 ноября 2001

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

Функция XSLT generate-id() генерирует уникальный идентификатор для узла, указанного в аргументе. Этот идентификатор начинается с латинской буквы, так что вы можете использовать его как значение атрибута XML ID. Например, следующая таблица стилей копирует XML-документ и добавляет атрибут uid ("unique ID") к каждому элементу chapter, sect1, и sect2. Здесь инструкция xsl:value-of в первом шаблоне таблицы стилей использует функцию generate-id(), чтобы сгенерировать значение этих атрибутов.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:eek:utput method="xml" omit-xml-declaration="yes"/>

<xsl:template match="chapter | sect1 | sect2">
<xsl:copy>
<xsl:attribute name="uid">
<xsl:value-of select="generate-id(.)"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

При помощи этой таблицы стилей из такого XML-документа

<chapter>
<para>Then with expanded wings he steers his flight</para>
<figure><title>"Incumbent on the Dusky Air"</title>
<graphic fileref="pic1.jpg"/></figure>
<para>Aloft, incumbent on the dusky Air</para>
<sect1>
<para>That felt unusual weight, till on dry Land</para>
<figure><title>"He Lights"</title>
<graphic fileref="pic2.jpg"/></figure>
<para>He lights, if it were Land that ever burned</para>
<sect2>
<para>With solid, as the Lake with liquid fire</para>
<figure><title>"The Lake with Liquid Fire"</title>
<graphic fileref="pic3.jpg"/></figure>
</sect2>
</sect1>
</chapter>

можно получить такой:

<chapter uid="N134711680">
<para>Then with expanded wings he steers his flight</para>
<figure><title>"Incumbent on the Dusky Air"</title>
<graphic fileref="pic1.jpg"/></figure>
<para>Aloft, incumbent on the dusky Air</para>
<sect1 uid="N134683456">
<para>That felt unusual weight, till on dry Land</para>
<figure><title>"He Lights"</title>
<graphic fileref="pic2.jpg"/></figure>
<para>He lights, if it were Land that ever burned</para>
<sect2 uid="N134684064">
<para>With solid, as the Lake with liquid fire</para>
<figure><title>"The Lake with Liquid Fire"</title>
<graphic fileref="pic3.jpg"/></figure>
</sect2>
</sect1>
</chapter>

Ваш XSLT-процессор может генерировать различные значения с функцией generate-id() . Фактически, если вы запускаете такую же таблицу стилей с таким же документов на входе несколько раз, XSLT-процессор может каждый раз создавать значения идентификаторов, отличные от тех, что были сгенерированы во время первого прохода. Однако, если вы вызываете generate-id() более, чем один раз внутри одной таблицы стилей с одинаковым узлом в качестве аргумента, она каждый раз для этого узла сгенерирует одинаковые значения идентификатора. Так как уникальный идентификатор является популярным способом для организации гиперссылок, эта устойчивость функции generate-id() делает ее замечательным инструментом для решения подобных задач.

Например, мы можем копировать документ подобно тому, как это мы сделали выше, но при этом в начало результирующего документа добавить список всех иллюстраций (см. колонку "Transforming XML" на XML.com). Если же при этом предполагется, что конечный документ будет HTML-файлом, то мы можем использовать функцию generate-id для того, чтобы превратить каждую запись в таком списке иллюстраций в гиперссылку на элемент img в теле документа, непосредственно содержащим эту иллюстрацию:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:eek:utput method="html"/>

<xsl:template match="chapter">
<html><body>

<!-- Формирование списка названий изображений,
в котором каждое название является ссылкой
на изображение в теле документа. -->
<b>Pictures:</b><br/>
<xsl:for-each select="descendant::figure">
<a href="#{generate-id(graphic)}">
<xsl:value-of select="title"/></a><br/>
</xsl:for-each>

<xsl:apply-templates/>
</body></html>
</xsl:template>

<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>

<xsl:template match="graphic">
<!-- Изображение и название в виде подписи, по центру. -->
<center><a name="{generate-id(.)}"><img src="{@fileref}"/></a>
<b><xsl:value-of select="../title"/></b></center>
</xsl:template>

<!-- Запрещение названия изображения, так как
оно уже добавлено в результирующее дерево
в шаблоне, соответствующем "graphic". -->
<xsl:template match="figure/title"/>

</xsl:stylesheet>

С исходным документом, приведеным выше, и этой таблицей стилей XSLT-процессор может создать следующий HTML-документ:

<html>
<body>
<b>Pictures:</b>
<br>
<a href="#N134691840">"Incumbent on the Dusky Air"</a>
<br>
<a href="#N134692416">"He Lights"</a>
<br>
<a href="#N134757920">"The Lake with Liquid Fire"</a>
<br>
<p>Then with expanded wings he steers his flight</p>

<center>
<a name="N134691840"><img src="pic1.jpg"></a>
<b>"Incumbent on the Dusky Air"</b>
</center>
<p>Aloft, incumbent on the dusky Air</p>

<p>That felt unusual weight, till on dry Land</p>

<center>
<a name="N134692416"><img src="pic2.jpg"></a>
<b>"He Lights"</b>
</center>
<p>He lights, if it were Land that ever burned</p>

<p>With solid, as the Lake with liquid fire</p>

<center>
<a name="N134757920"><img src="pic3.jpg"></a>
<b>"The Lake with Liquid Fire"</b>
</center>


</body>
</html>

(Для просмотра HTML-документа, вы должны использовать свои собственные файлы pic1.jpg, pic2.jpg и pic3.jpg.) В таблице стилей используется generate-id() дважды:

*

Инструкция xsl:for-each в шаблоне, соответствующем "chapter", добавляет значение title каждого элемента figure в результирующее дерево для формирования списка "Pictures:" в верхней части конечного документа. При этом содержание каждого из таких элементов title для создания ссылки на соответствующее изображение в теле документа размещается внутри HTML-элемента a. Непосредственно адрес ссылки указывается в атрибуте href каждого из таких элементов a. В нашем случае значение атрибута href начинается со знака "#" для обозначения того, что ссылка ведет на другой элемент a в самом документе, в котором значение атрибута name равно части строки после знака "#" в ссылке-источнике. Например, <a href="#a123"> указывает на элемент <a name="a123"> где-либо внутри документа.

Вместо строки "a123", определяющей каждый адрес ссылки, эта таблица стилей использует функцию generate-id() для создания идентификатора. Так как узел элемента graphic подается ей в качестве аргумента, функция создает идентифицирующую строку для каждого из трех элементов graphic: "N134691840", "N134692416" и "N134757920".
*

Для создания ссылки-адресата шаблон, соответствующий "graphic", размещает каждый HTML-элемент img в результирующем дереве внутри элемента a. Значение атрибутов src элементов img устанавливается значением атрибутов fileref элементов graphic исходного дерева, а элементы a используют функцию generate-id() для создания значений их атрибутов name. Указание в качестве аргумента к функции "." экивавалентно указанию self::node(), то есть текущего узла. В нашем случае это эквивалентно непосредственному указанию элементу узла graphic. Таким образом XSLT-процессор генерирует значение идентификатора для каждого узла graphic. Это те же самые три узла, что ранее использовали созданные generate-id() идентификаторы для ссылок, поэтому будут созданы такие же три значения: "N134691840", "N134692416" и "N134757920". Когда этот HTML-файл будет отображен в браузере, каждая ссылка в списке "Pictures:" теперь будет соответствовать изображению в документе.

Подведем итог. Устойчивость в данном контексте функции generate-id() при обработке конкретного узла, даже если функция генерирует идентификатор для этого узла более чем один раз, является ключевой. Элементы graphic не имели идентификаторов в исходном документе; с помощью это функции, их эквивалент в результирующем документе имеет их, и другие элементы в этом документе используют эти идентификаторы для связи с ними.
 
Сверху