Выбрать главу
Пример

В качестве примера приведем преобразование, которое добавляет в XHTML-файл перечень текстовых ссылок, обнаруженных в этом документе. Грубо говоря, XHTML — это XML-версия языка HTML, а значит XSLT вполне подходит для обработки XHTML-документов.

URI пространства имен языка XHTML — "http://www.w3.org/1999/xhtml"; этому языку мы назначим префикс "xhtml" и, кроме того, сделаем это пространство пространством имен по умолчанию:

<xsclass="underline" stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

 xmlns:xhtml="http://www.w3.org/1999/xhtml"

 xmlns="http://www.w3.org/1999/xhtml">

 ...

</xsclass="underline" stylesheet>

Начнем с шаблона, который будет выводить каждую из ссылок. В каждой ссылке мы будем выводить только ее атрибут href и текст, который она содержит. Для удобочитаемости мы также добавим элемент br и символ переноса строки &#xA;.

<xsclass="underline" template match="xhtmclass="underline" a">

 <xsclass="underline" copy>

  <xsclass="underline" copy-of select="@href|text()"/>

 </xsclass="underline" copy>

 <br/>

 <xsclass="underline" text>&#xA;</xsclass="underline" text>

</xsclass="underline" template>

Мы чуть позже познакомимся с элементами xsclass="underline" copy, xsclass="underline" copy-of и xsclass="underline" text, пока же скажем, что

<xsclass="underline" copy>

 <xsclass="underline" copy-of select="@href|text()"/>

</xsclass="underline" copy>

копирует в выходящий документ текущий узел, его атрибут href (@href) и дочерние текстовые узлы (text()).

Элемент <xsclass="underline" text>&#xA;</xsclass="underline" text> выводит символ переноса строки. Элемент <br/> является литеральным элементом результата — он никак не обрабатывается, а просто выводится в результирующий документ.

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

<xsclass="underline" template match="@*|node()">

 <xsclass="underline" copy>

  <xsclass="underline" apply-templates select="@*|node()"/>

 </xsclass="underline" copy>

</xsclass="underline" template>

И, наконец, нам понадобится преобразование для элемента body — в него мы включим копию содержимого, а также ссылки, отсортированные в алфавитном порядке:

<xsclass="underline" template match="xhtmclass="underline" body">

 <xsclass="underline" copy>

  <xsclass="underline" apply-templates select="@*|node()"/>

  <h1>Links found on this page:<h1>

  <xsclass="underline" apply-templates

   select=".//xhtmclass="underline" a[@href and not(xhtmclass="underline" *)]">

  <xsclass="underline" sort select="."/>

 </xsclass="underline" apply-templates>

 </xsclass="underline" copy>

</xsclass="underline" template>

Если мы попытаемся выполнить преобразование, состоящее из этих шаблонов, мы обнаружим, что в тексте самого документа ссылки испортились — там тоже добавились элементы br и переносы строк. Это произошло потому, что шаблон для обработки ссылок имеет больший приоритет, чем шаблон, копирующий содержимое документа.

Для исправления этой ошибки мы выделим шаблон обработки ссылок в отдельный режим links:

<xsclass="underline" template match="xhtmclass="underline" a" mode="links">

 ...

</xsclass="underline" template>

Теперь это правило не будет применяться к ссылкам во время копирования содержимого документа, потому что при выполнении инструкции

<xsclass="underline" apply-templates select="@*|node()"/>

режим будет пустым, значит шаблон для xhtmclass="underline" а вызываться не будет. Для того чтобы применить его при помощи xsclass="underline" apply-templates, мы добавим в этот элемент атрибут mode:

<xsclass="underline" apply-templates

 select=".//xhtmclass="underline" a[@href and not(xhtmclass="underline" *)]"

 mode="links">

 <xsclass="underline" sort select="."/>

</xsclass="underline" apply-templates>

Разберем более подробно это определение. Данная инструкция будет применять шаблоны с режимом links к узлам, возвращаемым выражением ".//xhtmclass="underline" a[@href and not (xhtmclass="underline" *)]", отсортированным в алфавитном порядке своих строковых значений. Выражение ".//xhtmclass="underline" a[@href and not(xhtmclass="underline" *)]" возвращает всех потомков текущего узла (путь выборки ".//"), которые принадлежат пространству имен xhtml, являются элементами с именами а, (тест имени "xhtmclass="underline" a"), при этом имеют атрибут href и не включают в себя другие элементы (предикат "[@href and not (xhtmclass="underline" *)]").

Преобразование целиком будет иметь следующий вид.

Листинг 5.4. Преобразование, добавляющее перечень ссылок

<xsclass="underline" stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

 xmlns:xhtml="http://www.w3.org/1999/xhtml"

 xmlns="http://www.w3.org/1999/xhtml">

 <xsclass="underline" template match="xhtmclass="underline" body">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()"/>

   <h1>Links found on this page:</h1>

   <xsclass="underline" apply-templates select=".//xhtmclass="underline" a[@href and not (xhtmclass="underline" *)]">

    <xsclass="underline" sort select="."/>

   </xsclass="underline" apply-templates>

  </xsclass="underline" copy>

 </xsclass="underline" template>

 <xsclass="underline" template match="@*|node()">

  <xsclass="underline" copy>

   <xsclass="underline" apply-templates select="@*|node()"/>

  </xsclass="underline" copy>

 </xsclass="underline" template>

 <xsclass="underline" template match="xhtmclass="underline" a">

  <xsclass="underline" copy>

   <xsclass="underline" copy-of select="@href|text()"/>

  </xsclass="underline" copy>

  <br/>

  <xsclass="underline" text>&#xA;</xsclass="underline" text>

 </xsclass="underline" template>

</xsclass="underline" stylesheet>

Применив это преобразование, например, к главной странице Консорциума W3 (http://www.w3.org), мы получим ее точный дубликат, в конце которого будет приведен перечень всех найденных текстовых ссылок. Выходящий документ будет заканчиваться фрагментом вида:

<h1>Links found on this page:</h1>

<a href="Consortium/">About W3C</a><br/>

<a href="WAI/">Accessibility</a><br/>

<a href="Consortium/Activities">Activities</a><br/>

и так далее.

Заметим, что того же эффекта можно было добиться другими способами, например, при помощи именованных шаблонов или элемента xsclass="underline" for-each, однако применение режимов, пожалуй, является наиболее гибкой техникой.

Досадным ограничением режимов является то, что режим нельзя выбирать динамически. Атрибут mode обязан иметь фиксированное значение, то есть вызов вида: