<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:*)]
').
Преобразование целиком будет иметь следующий вид.
<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 они появятся.
Именованные шаблоны
Вместо того чтобы при помощи атрибута match
указывать, какая часть входящего документа должна преобразовываться данным шаблоном, ему можно присвоить имя и вызывать в любой момент вне зависимости от контекста преобразования. Такие шаблоны очень схожи по принципу с процедурами в императивных языках программирования — они позволяют выносить часто используемые части преобразований, передавать им параметры и вызывать вне зависимости от того, что именно обрабатывается в данный момент.
Имя шаблонному правилу присваивается атрибутом name элемента xsl:template
. После этого шаблону более необязательно иметь атрибут match
, теперь он может быть вызван просто по имени. Два шаблона с одним порядком импорта не могут иметь одинаковых имен. Если же одинаковые имена имеют шаблоны различного порядка импорта, шаблоны старшего порядка