Книга: Технология XSLT
Режимы
Разделы на этой странице:
Режимы
Очень часто в преобразованиях требуется обрабатывать одни и те же узлы, но разными способами. Типичным примером такого рода задачи является генерация оглавления документа вместе с преобразованием его содержимого. Очевидно, что просто шаблонами здесь не обойтись, и чтобы не получить другой результат, нужно каким-то образом указывать, что по-другому должна вестись и обработка.
Эта проблема решается в XSLT просто и элегантно. Атрибут mode
элемента xsl:template задает режим этого шаблона. Точно такой же атрибут есть у элемента xsl:apply-templates
: в этом элементе он устанавливает режим обработки. При выполнении xsl:apply-templates
процессор будет применять только те шаблоны преобразования, режим которых совпадает с выбранным режимом обработки.
Пример
В качестве примера приведем преобразование, которое добавляет в XHTML-файл перечень текстовых ссылок, обнаруженных в этом документе. Грубо говоря, XHTML — это XML-версия языка HTML, а значит XSLT вполне подходит для обработки XHTML-документов.
URI пространства имен языка XHTML — "http://www.w3.org/1999/xhtml"
; этому языку мы назначим префикс "xhtml
" и, кроме того, сделаем это пространство пространством имен по умолчанию:
<xsl: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">
...
</xsl:stylesheet>
Начнем с шаблона, который будет выводить каждую из ссылок. В каждой ссылке мы будем выводить только ее атрибут href
и текст, который она содержит. Для удобочитаемости мы также добавим элемент br
и символ переноса строки 

.
<xsl:template match="xhtml:a">
<xsl:copy>
<xsl:copy-of select="@href|text()"/>
</xsl:copy>
<br/>
<xsl:text>
</xsl:text>
</xsl:template>
Мы чуть позже познакомимся с элементами xsl:copy
, xsl:copy-of
и xsl:text
, пока же скажем, что
<xsl:copy>
<xsl:copy-of select="@href|text()"/>
</xsl:copy>
копирует в выходящий документ текущий узел, его атрибут href(@href
) и дочерние текстовые узлы (text()
).
Элемент <xsl:text>
</xsl:text>
выводит символ переноса строки. Элемент <br/>
является литеральным элементом результата — он никак не обрабатывается, а просто выводится в результирующий документ.
Следующее преобразование называется идентичным преобразованием — оно просто копирует все узлы один в один:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
И, наконец, нам понадобится преобразование для элемента body
— в него мы включим копию содержимого, а также ссылки, отсортированные в алфавитном порядке:
<xsl:template match="xhtml:body">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<h1>Links found on this page:<h1>
<xsl:apply-templates
select=".//xhtml:a[@href and not(xhtml:*)]">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
Если мы попытаемся выполнить преобразование, состоящее из этих шаблонов, мы обнаружим, что в тексте самого документа ссылки испортились — там тоже добавились элементы br
и переносы строк. Это произошло потому, что шаблон для обработки ссылок имеет больший приоритет, чем шаблон, копирующий содержимое документа.
Для исправления этой ошибки мы выделим шаблон обработки ссылок в отдельный режим links
:
<xsl:template match="xhtml:a" mode="links">
...
</xsl:template>
Теперь это правило не будет применяться к ссылкам во время копирования содержимого документа, потому что при выполнении инструкции
<xsl:apply-templates select="@*|node()"/>
режим будет пустым, значит шаблон для xhtml:а
вызываться не будет. Для того чтобы применить его при помощи xsl:apply-templates
, мы добавим в этот элемент атрибут mode
:
<xsl:apply-templates
select=".//xhtml:a[@href and not(xhtml:*)]"
mode="links">
<xsl:sort select="."/>
</xsl:apply-templates>
Разберем более подробно это определение. Данная инструкция будет применять шаблоны с режимом links
к узлам, возвращаемым выражением ".//xhtml:a[@href and not (xhtml:*)]"
, отсортированным в алфавитном порядке своих строковых значений. Выражение ".//xhtml:a[@href and not(xhtml:*)]"
возвращает всех потомков текущего узла (путь выборки ".//
"), которые принадлежат пространству имен xhtml
, являются элементами с именами а
, (тест имени "xhtml:a
"), при этом имеют атрибут href
и не включают в себя другие элементы (предикат "[@href and not (xhtml:*)]
").
Преобразование целиком будет иметь следующий вид.
Листинг 5.4. Преобразование, добавляющее перечень ссылок
<xsl: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">
<xsl:template match="xhtml:body">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<h1>Links found on this page:</h1>
<xsl:apply-templates select=".//xhtml:a[@href and not (xhtml:*)]">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xhtml:a">
<xsl:copy>
<xsl:copy-of select="@href|text()"/>
</xsl:copy>
<br/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl: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/>
и так далее.
Заметим, что того же эффекта можно было добиться другими способами, например, при помощи именованных шаблонов или элемента xsl:for-each
, однако применение режимов, пожалуй, является наиболее гибкой техникой.
Досадным ограничением режимов является то, что режим нельзя выбирать динамически. Атрибут mode
обязан иметь фиксированное значение, то есть вызов вида:
<xsl:apply-templates mode="{$mode}"/>
будет некорректным. Особо серьезных практических противопоказаний для динамических режимов нет, будем надеяться, что в следующих версиях XSLT они появятся.
- 8.5.3. Режимы энергосбережения
- 4. Режимы работы экспертных систем
- 1.1 Режимы ядра и пользователя Windows
- Режимы работы проигрывателя
- Режимы работы с документами
- Режимы работы с таблицами
- Режимы: форматирование в зависимости от контекста
- Режимы протяжки
- Режимы энергосбережения
- Режимы работы жестких дисков
- 4.3. Режимы работы МК семейства 68HC12
- 7.6. Режимы просмотра презентации