Алексей Валиков - Технология XSLT
Выполнение преобразования
Несмотря на полную свободу в порядке выполнения шаблонов, правила изменения контекста и компоновки результирующего дерева, спецификация XSLT оговаривает очень четко — это делает XSLT весьма гибким языком, программы на котором при этом выполняются совершенно детерминированным образом.
Типовой процесс выполнения преобразования согласно спецификации включает следующие стадии:
□ дерево выходящего документа создается путем обработки множества, состоящего из единственного узла — текущего узла дерева;
□ результатом применения шаблонов к обрабатываемому множеству узлов является объединение фрагментов деревьев, которые являются результатами обработки каждого из узлов множества;
□ каждый из узлов обрабатываемого множества преобразуется следующим образом:
• из всех шаблонов, определенных в данном преобразовании, выбираются шаблоны, соответствующие данному узлу (соответствие определяется паттерном, указанным в атрибуте match элемента xsl:template);
• из этих шаблонов выбирается наиболее подходящий;
• выбранный шаблон выполняется в контексте обрабатываемого множества как текущего множества узлов и обрабатываемого узла как текущего узла;
□ если шаблон содержит инструкции xsl:apply-templates или xsl:foreach, которые дополнительно выбирают узлы для обработки, процесс рекурсивно продолжается до тех пор, пока обрабатываемое множество будет содержать хотя бы один узел.
В общих чертах этот процесс был продемонстрирован на примере, приведенном в описании контекста преобразования. Сейчас мы завершим картину, показав, как в каждом из шаблонов будут создаваться результирующие фрагменты деревьев и как они затем будут "сращиваться" в дерево выходящего документа.
На сей раз, мы начнем с самых "глубоких" шаблонов — шаблонов, обрабатывающих элементы month.
<xsl:template match="month">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
Каждый из них создает результирующий фрагмент дерева следующего вида (рис. 3.23).
Рис. 3.23. Результат обработки элемента month
Шаблоны к элементам month применяются элементом xsl:apply-templates при обработке элемента summer соответствующим шаблоном:
<xsl:template match="summer">
<table>
<tr>
<xsl:apply-templates select="month"/>
</tr>
</table>
</xsl:template>
Результатом выполнения xsl:apply-templates будет объединение результирующих фрагментов деревьев, которые получатся при обработке элементов month. Таким образом, результирующий фрагмент этого шаблона будет "собран" в следующем виде (рис. 3.24):
Рис. 3.24. Результат обработки элемента summer
Пунктиром выделены результирующие фрагменты деревьев, сгенерированные при обработке элементов month; эти фрагменты объединяются и используются при создании фрагмента дерева, являющегося результатом обработки элемента summer.
Этот результат, в свою очередь, используется в главном шаблоне — шаблоне, который обрабатывает корневой элемент:
<xsl:template match="/">
<html>
<head>
<title>Summer</title>
</head>
<body>
<xsl:apply-templates select="summer"/>
</body>
</html>
</xsl:template>
Сгенерированный при обработке элемента summer результирующий фрагмент дерева включается в корневом шаблоне в элемент body (рис.3.25).
Рис. 3.25. Результат обработки корневого узла
Пунктиром выделен результирующий фрагмент дерева, который был получен при обработке элемента summer.
Результирующий фрагмент дерева, полученный в результате обработки корневого узла, является деревом выходящего документа. В чистом XSLT это и есть результат выполнения преобразования. Для того чтобы получить физическую интерпретацию — в данном случае HTML-документ, дерево сериализуется, обращаясь в следующий выходящий документ.
Листинг 3.31. Выходящий документ проведённого преобразования<html>
<head>
<title>Summer</title>
</head>
<body>
<table>
<tr>
<td>June</td>
<td>July</td>
<td>August</td>
</tr>
</table>
</body>
</html>
Надо сказать, что спецификация языка XSLT не оговаривает, в каком именно порядке процессоры должны выполнять шаблонные правила — главное, чтобы результат преобразования совпадал с результатом, полученным при обработке приведенным выше способом. На практике это означает, что разработчикам совершенно необязательно знать, как именно конкретный процессор применяет правила — достаточно понимать принципы шаблонной обработки. В этом одно из главных достоинств XSLT как языка, не имеющего побочных эффектов.
Глава 4
Структура преобразования
Пространство имен XSLT
Для того чтобы выделить элементы и атрибуты, которые принадлежат логической схеме XSLT, в этом языке применяется механизм пространств имен. Это означает, что в документе преобразования элементы, относящиеся к XSLT, должны принадлежать его пространству имен.
Уникальный идентификатор ресурса пространства имен XSLT имеет вид
http://www.w3.org/1999/XSL/Transform
Как отмечалось ранее, по адресу, указанному в URI пространства имен, совершенно необязательно будет находиться что-либо осмысленное. Однако в нашем случае по адресу http://www.w3.org/1999/XSL/Transform находится текстовый документ, содержащий единственную строчку:
This is the XSLT namespace.
Символ 1999 в URI пространства имен XSLT никак не соотносится с версией языка преобразования. Это просто год, который был назначен Консорциумом W3 данной спецификации и не более. Версия использованного языка определяется атрибутом version элемента xsl:stylesheet.
Общепринятым префиксом пространства имен языка XSLT является префикс xsl. Естественно, он может быть любым другим, но в этой книге мы будем использовать именно такое обозначение. Таким образом, объявление пространства имен XSLT в общем случае будет выглядеть следующим образом: xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
ПримерПриведем пример простого преобразования, в котором объявлено пространство имен XSLT.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:element name="root"/>
</xsl:template>
</xsl:stylesheet>
В некоторых случаях исходный текст намного упрощается, если пространство имен XSLT объявляется по умолчанию:
<stylesheet
version="1.0"
xmlns="http://www.w3.org/1999/XSL/Transform">
<template match="/">
<element name="root"/>
</template>
</stylesheet>
Кроме этого, пространство имен по умолчанию можно снова обнулить:
<stylesheet
version="1.0"
xmlns="http://www.w3.org/1999/XSL/Transform">
<template match="root">
<root xmlns=""/>
</template>
</stylesheet>
В последнем случае элемент root будет принадлежать нулевому пространству имен. Результат всех трех преобразований одинаков:
<root/>
Элементы XSLT могут содержать атрибуты, принадлежащие другим, но обязательно ненулевым, пространствам имен. Такие атрибуты могут содержать дополнительную информацию, но поскольку они не относятся к XSLT, обрабатываться процессором в общем случае они не будут.
ПримерЕсли мы определим в преобразовании элемент вида
<xsl:template match="a" xsldoc:text="Processes all a elements"
xmlns:xsldoc="http://www.a.com/XSL/doc">
...
</xsl:template>
то в общем случае атрибут xsldoc:text будет проигнорирован. Однако процессор, которому знакомо пространство имен с URI http://www.a.com/XSL/doc сможет понять, что этот атрибут применен для документирования преобразования и будет использовать его в своих целях.
Корневые элементы преобразования
За исключением случаев упрощенных преобразований, корневым элементом XSLT-документа всегда является элемент xsl:stylesheet или его синоним xsl:transform. Эти элементы полностью идентичны и различаются только именами, поэтому мы будем описывать семантику и пользоваться только элементом xsl:stylesheet.