<content>Just a few words...</content>
</page>
то результат выполнения следующих двух шаблонов будет одинаков.
<xsclass="underline" template match="page">
<html>
<xsclass="underline" apply-templates select="head"/>
<body><xsclass="underline" copy-of select="content/node()/></body>
</html>
</xsclass="underline" template>
<xsclass="underline" template match="page">
<html>
<xsclass="underline" call-template name="head"/>
<body><xsclass="underline" copy-of select="content/node()/></body>
</html>
</xsclass="underline" template>
В чем же состоит разница вызова шаблона элементами xsclass="underline" apply-templates и xsclass="underline" call-template? Перечислим несколько отличий.
□ Элемент xsclass="underline" apply-templates применяет подходящие шаблоны к узлам определенного множества; xsclass="underline" call-template просто выполняет тело фиксированного именованного шаблона.
□ При вызове шаблона инструкцией xsclass="underline" apply-templates происходит изменение контекста — обрабатываемое множество узлов становится текущим списком узлов преобразования, а обрабатываемый узел — текущим узлом; xsclass="underline" call-template не изменяет контекст преобразования.
□ Инструкция xsclass="underline" apply-templates позволяет использовать различные режимы — применяются только те шаблоны, значение атрибута mode которых равно значению этого атрибута у вызывающей инструкции; xsclass="underline" call-template выполняет шаблон с заданным именем вне зависимости от того, в каком режиме происходит обработка и каково значение атрибута mode этого шаблона.
□ Если для обработки определенного узла подходит несколько шаблонов, то при выполнении xsclass="underline" apply-templates процессор будет выбирать наиболее подходящий из них; xsclass="underline" call-template всегда будет выполнять тот единственный шаблон преобразования, который имеет указанное имя.
□ Если в преобразовании не определен шаблон для обработки некоторого узла, но к нему элементом xsclass="underline" apply-templates все же применяются шаблоны, процессор будет использовать шаблон обработки по умолчанию; если элемент xsclass="underline" call-template вызывает отсутствующий шаблон, процессор выдаст сообщение об ошибке, потому что не сможет найти шаблон с заданным именем.
□ При использовании xsclass="underline" apply-templates процессор игнорирует значения атрибутов name элементов xsclass="underline" template; точно так же xsclass="underline" call-template принимает во внимание только значение атрибута name, игнорируя атрибуты match, mode и priority.
При желании можно найти еще с десяток отличий, но и этих положений вполне достаточно для того, чтобы понять разницу. Главным выводом из этого сравнения является то, что xsclass="underline" apply-templates демонстрирует декларативный, а xsclass="underline" call-template процедурный стиль программирования В первом случае мы используем объявленные (или задекларированные) правила преобразования, во втором — используем шаблон просто как процедуру.
Встроенные шаблоны
Для того чтобы обеспечить рекурсивную обработку документа при преобразовании, в XSLT существуют так называемые встроенные шаблоны. Несмотря на то, что они не описываются в преобразованиях явным образом, встроенные шаблоны применяются процессорами по умолчанию в случаях, когда более подходящих шаблонов нет.
Существуют пять основных шаблонных правил, которые применяются процессорами по умолчанию.
Первое из них обеспечивает рекурсивную обработку дочерних элементов документа, которые находятся как в корне, так и в других элементах. Это правило эквивалентно следующему шаблону:
<xsclass="underline" template match="*|/">
<xsclass="underline" apply-templates/>
</xsclass="underline" template>
Второе встроенное правило преобразования аналогично первому, с той лишь особенностью, что для каждого режима преобразования рекурсивная обработка происходит в том же самом режиме. В XSLT это правило выглядело бы следующим образом:
<xsclass="underline" template match="*|/" mode="режим">
<xsclass="underline" apply-templates mode="режим"/>
</xsclass="underline" template>
В XSLT также определяется встроенное правило для обработки текстовых узлов и атрибутов — это правило просто выводит их текстовые значения. Шаблон такого преобразования может быть записан в виде:
<xsclass="underline" template match="text()|@*">
<xsclass="underline" value-of select="."/>
</xsclass="underline" template>
Четвертое правило касается обработки инструкций по обработке и комментариев. Это правило не делает ничего, то есть инструкции и комментарии просто опускаются в выходящем документе. Шаблон такого преобразования будет иметь вид
<xsclass="underline" template match="processing-instruction()|comment()"/>
Последнее, пятое правило определяет обработку узлов пространств имен. Аналогично инструкциям и комментариям, с ними по умолчанию не следует делать ничего, то есть узлы пространств имен просто удаляются.
Встроенные шаблоны имеют наименьший приоритет импорта, а значит, будут использоваться лишь тогда, когда в преобразовании нет другого, более подходящего правила. Иными словами, любой шаблон, определенный в преобразовании, будет иметь больший приоритет, чем у встроенных правил.
Такое положение вещей позволяет переопределять преобразования, применяемые к узлам документа по умолчанию. Например, во многих случаях бывает весьма полезным идентичное преобразование, которое копирует узлы как есть. Мы уже встречались с ним, когда создавали шаблон для генерации таблицы ссылок XHTML-документа; теперь мы чуть более подробно разберем его работу.
Идентичное преобразование
Наличие в XSLT шаблонов, выполняемых по умолчанию, иногда приводит к тому, что процессоры ведут себя не совсем логично с человеческой точки зрения. Например, в простейшем случае может понадобиться переименовать все элементы с именами bold в элементы с именами b. Однако результатом обработки документа
<а>
text a
<bold>
text b
<bold/>
</bold>
<c>
text c
</c>
</a>
преобразованием
<xsclass="underline" stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsclass="underline" template match="bold">
<b><xsclass="underline" apply-templates/></b>
</xsclass="underline" template>
</xsclass="underline" stylesheet>
будет документ вида
text a
<b>
text b
<b/>
</b>
text c
Как можно заметить, в выходящем документе элементы а и с "пропали", но при этом их содержимое осталось нетронутым. Все дело во встроенных шаблонах, которые по умолчанию рекурсивно обрабатывают содержимое элементов и копируют текстовые узлы, если иного не определено.
Для того чтобы избежать подобного рода казусов, можно использовать идентичное преобразование, которое в случае отсутствия шаблонов для обработки тех или иных узлов копирует их в выходящий документ как есть. Идентичное преобразование записывается в следующем виде.