Определение шаблонного правила
Элемент xsl:template
Синтаксис этого элемента приведен ниже:
match="пaттерн"
name="имя"
priority="число"
mode="имя">
Элемент верхнего уровня
xsl:template
определяет в преобразовании шаблонное правило, или просто шаблон. Элемент xsl:template
имеет всего четыре атрибута, смысл которых мы кратко опишем ниже.Атрибут
match
задает паттерн — образец узлов дерева, для преобразования которых следует применять этот шаблон.Пример
В этом правиле атрибут
match
говорит о том, что оно должно использоваться для обработки элементов bold
— в данном случае они будут заменяться на элементы b
. Шаблоны, в которых определен атрибут match
, вызываются при помощи инструкции xsl:apply-templates
.Шаблон также может иметь имя, определяемое атрибутом
name
. Шаблон, в котором задано имя, называется именованным шаблоном. Именованные шаблоны могут вызываться вне зависимости от текущего контекста, и даже вести себя как функции — принимать на вход параметры и возвращать некоторые значения.Пример
В отличие от предыдущего примера, это правило не будет обрабатывать какие-либо определенные узлы. Вызвать его можно будет только по имени посредством элемента
xsl:call-template
.При определении шаблона нужно обязательно указать хотя бы один из атрибутов
match
или name
, причем эти атрибуты могут присутствовать в xsl:template
одновременно.Атрибут
mode
определяет режим данного шаблонного правила. Режимы позволяют задавать различные преобразования для одних и тех же частей документа (о них мы поговорим позже).Атрибут
priority
используется для определения значения, которое называется приоритетом шаблонного правила. Это значение используется для разрешения конфликтов шаблонов в случае, когда один узел может быть обработан различными правилами.Атрибуты шаблонного правила не влияют на выполнение его содержимого. Они используются элементами
xsl:apply-templates
и xsl:call-template
при выборе шаблонов. Правила, которые были импортированы в преобразование, вызываются элементом xsl:apply-imports
.Вызов шаблонных правил
Рассмотрим следующий простой пример.
Листинг 5.1. Входящий документtext
Попробуем написать пару шаблонов, которые будут изменять имена элементов
para
и bold
на p
и b
соответственно. Сначала напишем преобразование для bold
:
В этом правиле создается элемент
b
, в который включается текстовое значение текущего узла (то есть, обрабатываемого элемента bold
). Применив это преобразование к входящему документу, мы получим следующий результат:text
Как говорят математики, что и требовалось. Попробуем проделать тот же трюк с элементом
para
и создадим преобразование, включающее оба правила.Листинг 5.2. Преобразование с para и bold — версия 1
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
На этот раз вместо ожидаемого результата вида
text
мы получим
text
Попробуем ответить на три вопроса: кто виноват, что делать и куда делся элемент
b
.Для ответа на вопрос, куда делся элемент
b
, пожалуй, необходимо будет пояснить, что же именно происходит при преобразовании этого документа. Последовательно рассмотрим стадии этого процесса.□ Процессор начинает обработку с корневого узла дерева. Он выбирает шаблон, соответствующий этому узлу. В нашем преобразовании такого шаблона нет, значит, процессор применит к корню шаблонное правило, определенное по умолчанию (см. раздел "Встроенные шаблоны" данной главы).
□ По умолчанию шаблонное правило корневого узла обрабатывает все дочерние узлы. В нашем документе единственным дочерним узлом корня будет элемент
para
.□ Для элемента
para
в нашем преобразовании задан шаблон, который и будет применен к этому элементу.□ В соответствии с этим шаблоном, процессор создаст элемент
p
и включит в него текстовое значение выражения ".
". Как мы знаем, выражение ".
" является сокращенной формой выражения "self::node()
", которое возвратит текущий узел. Таким образом, элемент
вычислит и возвратит строковое значение текущего узла, то есть узла para
. Строковым значением элемента является конкатенация всех его текстовых потомков. Единственным текстовым потомком нашего para является текстовый узел со значением "text
" и вот он-то и выводится между открывающим и закрывающим тегами созданного элемента p
.Таким образом, элемент
b
"потерялся" потому, что шаблон для bold
просто не вызывался. Виноваты, естественно, мы сами, поскольку не включили его вызов. Осталось только разобраться, как можно вызвать шаблон для обработки элемента bold
.Ответ на этот вопрос предельно прост — для вызова неименованных шаблонных правил В XSLT используется элемент
xsl:apply-templates
.Элемент xsl:apply-templates
Синтаксис этого элемента выглядит следующим образом:
select="выражение"
mode="режим">
Элемент
xsl:apply-templates
применяет шаблонные правила к узлам, которые возвращаются выражением, указанным в атрибуте select
. Если атрибут select
опущен, то xsl:apply-templates
применяет шаблонные правила ко всем дочерним узлам текущего узла, то есть
равносильно
Атрибут
mode
используется для указания режима, в котором должны применяться шаблоны — мы поговорим о различных режимах чуть позже.Прежде чем двигаться дальше, опишем более подробно, что означает "применить шаблон" (англ. apply — применить, template — шаблон). Применение шаблонов — это составная часть обработки документа, которая может быть описана следующим порядком действий.
□ На первом шаге процессор вычисляет выражение, указанное в атрибуте
select
. Его значением должно быть множество узлов. Полученное множество узлов упорядочивается и становится текущим списком узлов контекста преобразования.□ Для каждого из узлов этого списка процессор находит наиболее подходящий шаблон для обработки. Процессор делает этот узел текущим и затем выполняет в измененном контексте выбранное шаблонное правило.
□ Дерево, которое является результатом выполнения шаблона, добавляется в выходящее дерево.
Применительно к нашему примеру с
para
и bold
, мы можем изменить преобразование так, что в создаваемый элемент p будет включаться не текстовое значение элемента para, а результат обработки его дочерних узлов.Листинг 5.3. Преобразование с para и bold — версия 2
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Проследим за процессом выполнения этого преобразования.
□ Обработка начинается с корневого узла дерева. Для него нет заданных шаблонных правил, значит, применено будет правило по умолчанию — обработать все дочерние узлы. Множество дочерних узлов корня содержит единственный элемент
para
, значит, текущий список узлов контекста будет состоять из одного узла. Для него в преобразовании определен шаблон, который и будет выполнен процессором.□ Шаблон, соответствующий элементу
para
, создает элемент p
, содержимым которого будет результат выполнения инструкции xsl:apply-templates
, то есть результат применения шаблонов к дочерним узлам текущего узла — элемента para
.□ Единственным дочерним узлом элемента
para
является элемент bold
. Процессор изменит контекст так, что текущий список узлов будет содержать только элемент bold
и выполнит соответствующее шаблонное правило, которое создаст элемент b
и включит в него узел, вычисленный инструкцией
, то есть текстовый узел со строковым значением текущего узла, элемента bold
.Три шага этого преобразования продемонстрированы на рис. 5.1.
Рис. 5.1. Процесс преобразования
Здесь слева показан текущий список узлов, посередине — дерево документа с выделенным пунктиром текущим узлом, справа — генерируемое выходящее дерево.
Результатом этого преобразования будет документ:
text
Рассмотрим чуть более сложное преобразование документа:
text1
text2
Порядок действий в этом случае будет приблизительно следующим.
□ Первым обрабатывается корневой узел. Процессор применяет шаблоны к дочерним узлам (вернее к одному дочернему узлу — элементу
para
).□ Шаблон, обрабатывающий элемент para, создает в выходящем документе элемент p и применяет шаблоны к своим дочерним узлам — на этот раз их два,
bold
и para
.□ Шаблон, обрабатывающий элемент
bold
, создает в выходящем документе элемент b
и текстовый узел со значением "text1
".□ Шаблон, обрабатывающий элемент
para
, создает в выходящем дереве узел p
и применяет шаблоны к дочерним узлам.□ Единственным дочерним узлом элемента
para
является элемент bold
.□ Шаблон, обрабатывающий этот элемент
bold
, создает в выходящем документе элемент b
и текстовый узел со значением "text2
".Процесс преобразования показан на рис. 5.2.
Рис. 5.2. Процесс преобразования
Результатом этого преобразования будет документ:
text1
text2
Атрибут
select
элемента xsl:apply-templates
позволяет выбирать, к каким именно узлам будет применяться этот шаблон. Значение select
— это XPath-выражение, которое должно возвращать множество узлов. В случае, если атрибут select
указан, шаблоны будут поочередно применяться к каждому из узлов выбранного множества.ПримерЕсли при обработке элементов para мы хотим обрабатывать только дочерние элементы
bold
и никакие другие, шаблон обработки элементов para
будет записан следующим образом:
Результатом обработки документа
text1
text2
будет теперь
text1
Элемент
para
, который во входящем документе включен в другой элемент para
, не будет обработан по той простой причине, что он не вошел во множество, выбранное XPath-выражением "bold
". В то же время, если мы запишем
то результат будет таким же, как и прежде:
text1
text2
Следует хорошо понимать разницу между атрибутом
select
элемента xsl:apply-templates
и атрибутом match
элемента xsl:template
. Атрибут match
содержит не XPath-выражение, а паттерн XSLT; в отличие от атрибута select в xsl:apply-templates
он не выбирает никакого множества узлов, он используется только для того, чтобы проверить, может ли данный узел обрабатываться этим шаблоном или нет.Атрибут
select
элемента xsl:apply-templates
наоборот, содержит не паттерн, а выражение, единственным требованием к которому является то, что оно должно возвращать множество узлов. Например, некорректным будет определение вида
поскольку выражение
para+1
не может возвратить множество узлов.Кроме этого требования, никаких других ограничений на выражения в этом атрибуте нет. В нем можно использовать переменные, содержащие множества узлов, функции, возвращающие множества узлов (например, такие, как
id
или key
), выражения с операциями над множествами (именно таким выражением — выражением объединения было выражение bold|para
), пути выборки, фильтрующие выражения, в общем, любые выражения, которые только могут возвращать множества. Например, для того, чтобы обработать содержимое произвольного внешнего XML-документа, в атрибуте select
элемента xsl:apply-template
следует использовать функцию document
.ПримерОбъявление вида
применит шаблоны ко всем элементам
para
документа a.xml
.Режимы