</xsclass="underline" template>
</xsclass="underline" stylesheet>
Проследим за процессом выполнения этого преобразования.
□ Обработка начинается с корневого узла дерева. Для него нет заданных шаблонных правил, значит, применено будет правило по умолчанию — обработать все дочерние узлы. Множество дочерних узлов корня содержит единственный элемент para, значит, текущий список узлов контекста будет состоять из одного узла. Для него в преобразовании определен шаблон, который и будет выполнен процессором.
□ Шаблон, соответствующий элементу para, создает элемент p, содержимым которого будет результат выполнения инструкции xsclass="underline" apply-templates, то есть результат применения шаблонов к дочерним узлам текущего узла — элемента para.
□ Единственным дочерним узлом элемента para является элемент bold. Процессор изменит контекст так, что текущий список узлов будет содержать только элемент bold и выполнит соответствующее шаблонное правило, которое создаст элемент b и включит в него узел, вычисленный инструкцией <xsclass="underline" value-of select="."/>, то есть текстовый узел со строковым значением текущего узла, элемента bold.
Три шага этого преобразования продемонстрированы на рис. 5.1.
Рис. 5.1. Процесс преобразования
Здесь слева показан текущий список узлов, посередине — дерево документа с выделенным пунктиром текущим узлом, справа — генерируемое выходящее дерево.
Результатом этого преобразования будет документ:
<p><b>text</b></p>
Рассмотрим чуть более сложное преобразование документа:
<para>
<bold>text1</bold>
<para>
<bold>text2</bold>
</para>
</para>
Порядок действий в этом случае будет приблизительно следующим.
□ Первым обрабатывается корневой узел. Процессор применяет шаблоны к дочерним узлам (вернее к одному дочернему узлу — элементу para).
□ Шаблон, обрабатывающий элемент para, создает в выходящем документе элемент p и применяет шаблоны к своим дочерним узлам — на этот раз их два, bold и para.
□ Шаблон, обрабатывающий элемент bold, создает в выходящем документе элемент b и текстовый узел со значением "text1".
□ Шаблон, обрабатывающий элемент para, создает в выходящем дереве узел p и применяет шаблоны к дочерним узлам.
□ Единственным дочерним узлом элемента para является элемент bold.
□ Шаблон, обрабатывающий этот элемент bold, создает в выходящем документе элемент b и текстовый узел со значением "text2".
Процесс преобразования показан на рис. 5.2.
Рис. 5.2. Процесс преобразования
Результатом этого преобразования будет документ:
<p>
<b>text1</b>
<p>
<b>text2</b>
</p>
</p>
Атрибут select элемента xsclass="underline" apply-templates позволяет выбирать, к каким именно узлам будет применяться этот шаблон. Значение select — это XPath-выражение, которое должно возвращать множество узлов. В случае, если атрибут select указан, шаблоны будут поочередно применяться к каждому из узлов выбранного множества.
Если при обработке элементов para мы хотим обрабатывать только дочерние элементы bold и никакие другие, шаблон обработки элементов para будет записан следующим образом:
<xsclass="underline" template match="para">
<p><xsclass="underline" apply-templates select="bold"/></p>
</xsclass="underline" template>
Результатом обработки документа
<para>
<bold>text1</bold>
<para>
<bold>text2</bold>
</para>
</para>
будет теперь
<p>
<b>text1</b>
</p>
Элемент para, который во входящем документе включен в другой элемент para, не будет обработан по той простой причине, что он не вошел во множество, выбранное XPath-выражением "bold". В то же время, если мы запишем
<xsclass="underline" template match="para">
<p><xsclass="underline" apply-templates select="bold|para"/></p>
</xsclass="underline" template>
то результат будет таким же, как и прежде:
<p>
<b>text1</b>
<p>
<b>text2</b>
</p>
</p>
Следует хорошо понимать разницу между атрибутом select элемента xsclass="underline" apply-templates и атрибутом match элемента xsclass="underline" template. Атрибут match содержит не XPath-выражение, а паттерн XSLT; в отличие от атрибута select в xsclass="underline" apply-templates он не выбирает никакого множества узлов, он используется только для того, чтобы проверить, может ли данный узел обрабатываться этим шаблоном или нет.
Атрибут select элемента xsclass="underline" apply-templates наоборот, содержит не паттерн, а выражение, единственным требованием к которому является то, что оно должно возвращать множество узлов. Например, некорректным будет определение вида
<xsclass="underline" apply-templates select="para+1"/>
поскольку выражение para+1 не может возвратить множество узлов.
Кроме этого требования, никаких других ограничений на выражения в этом атрибуте нет. В нем можно использовать переменные, содержащие множества узлов, функции, возвращающие множества узлов (например, такие, как id или key), выражения с операциями над множествами (именно таким выражением — выражением объединения было выражение bold|para), пути выборки, фильтрующие выражения, в общем, любые выражения, которые только могут возвращать множества. Например, для того, чтобы обработать содержимое произвольного внешнего XML-документа, в атрибуте select элемента xsclass="underline" apply-template следует использовать функцию document.
Объявление вида
<xsclass="underline" apply-templates select="document('a.xml')//para"/>
применит шаблоны ко всем элементам para документа a.xml.
Режимы
Очень часто в преобразованиях требуется обрабатывать одни и те же узлы, но разными способами. Типичным примером такого рода задачи является генерация оглавления документа вместе с преобразованием его содержимого. Очевидно, что просто шаблонами здесь не обойтись, и чтобы не получить другой результат, нужно каким-то образом указывать, что по-другому должна вестись и обработка.
Эта проблема решается в XSLT просто и элегантно. Атрибут mode элемента xsclass="underline" template задает режим этого шаблона. Точно такой же атрибут есть у элемента xsclass="underline" apply-templates: в этом элементе он устанавливает режим обработки. При выполнении xsclass="underline" apply-templates процессор будет применять только те шаблоны преобразования, режим которых совпадает с выбранным режимом обработки.