Технология XSLT — страница 13 из 66

Многие простые преобразования состоят из единственного правила, которое обрабатывает корневой узел входящего документа. Общий вид такого рода преобразований показан в следующем листинге.

Листинг 4.2. Простое преобразование

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">



XSLT позволяет упрощать запись таких преобразований, опуская элементы

xsl:stylesheet
и
xsl:template
и оставляя только шаблон, создающий выходящий документ.

Корневой элемент упрощенной записи должен содержать атрибут

xsl:version
, указывающий версию языка XSLT, использованного в шаблоне. Как правило, этот элемент также содержит объявление пространства имен XSLT, хотя оно может быть определено и в другом месте.

Пример

Преобразование, приведенное в листинге 4.2, можно переписать в упрощенном виде следующим образом.

Листинг 4.3. Упрощённая запись преобразования

 xsl:version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Приведем еще один простой пример упрощенной записи преобразования, генерирующего простейшую HTML-страницу.

Листинг 4.4. Упрощённая запись преобразования XML-документа в HTML

</code></pre></p><p><pre><code><xsl:value-of select="page/name"/></code></pre></p><p><pre><code>

Следующий листинг приводит полную версию этого же преобразования.

Листинг 4.5. Полная запись преобразования XML-документа в HTML

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


</code></pre></p><p><pre><code><xsl:value-of select="page/name"/></code></pre></p><p><pre><code>

Модульная организация преобразования

Как и любой, достаточно развитый язык программирования, XSLT обладает средствами для организации модульной структуры преобразований. Существуют два основных способа использования в преобразованиях внешних модулей — включение и импорт. Кроме того, поскольку преобразования в XSLT также являются XML-документами, для разбиения их на модули можно применять сущности.

Включение преобразований

Подобно тому, как мы бы использовали в языке С директиву

#include
для включения внешних файлов, преобразования в XSLT могут использовать для той же самой цели элемент
xsl:include
. Правда, в отличие от языка С, условное включение в XSLT невозможно.

Элемент xsl:include

href = "URI"/>

Обязательный атрибут

href
элемента
xsl:include
содержит URI внешнего модуля, который должен быть включен в текущее преобразование. Внешний модуль обязан быть корректным XSLT-преобразованием.

Включение внешнего преобразования является включением в прямом смысле этого слова: преобразование, включающее внешний модуль, ведет себя так, как если бы на месте элемента

xsl:include
было содержимое этого внешнего модуля.

Пример

Рассмотрим простое преобразование

a.xsl
, которое определяет значение переменной
date
.

Листинг 4.6. Преобразование a.xsl

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Включим

a.xsl
в преобразование
b.xsl
.

Листинг 4.7. Преобразование b.xsl

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Today is 

.

Включение в преобразование

b.xsl
преобразования
a.xsl
эквивалентно замене в
b.xsl
соответствующего элемента
xsl:include
на содержимое преобразования
a.xsl
. В нашем случае будет включено только определение переменной
date
. Преобразование
b.xsl
можно переписать в следующем виде: .

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Today is 

.

При включении внешних преобразований при помощи

xsl:include
следует учитывать некоторые особенности использования этого элемента.

Все ссылки и относительные идентификаторы ресурсов (URI), используемые во включаемом преобразовании, вычисляются относительно его базового адреса.

Пример

Предположим, что URI нашего преобразования имеет вид:

http://www.xsltdev.ru/examples/a.xsl

В этом случае элемент

будет включать преобразование с URI

http://www.xsltdev.ru/examples/b.xsl

Нет никаких проблем и с включением преобразований по абсолютным идентификаторам. Например, если преобразование

identity.xsl
находится по адресу

http://www.xsltdev.ru/stylesheets/identity.xsl

то включить его можно элементом

Естественно, включаемые модули должны быть доступны процессору во время выполнения преобразования, поэтому если они находятся на других серверах, то всегда будет существовать возможность невыполнения преобразования.

В XSLT элементы

xsl:import
всегда должны быть первыми дочерними элементами головного элемента
xsl:stylesheet
. Поэтому элементы
xsl:import
внешнего преобразования включаются сразу после элементов
xsl:import
основного преобразования. Если в основном преобразовании элементов
xsl:import
нет, то включаемые элементы
xsl:import
становятся первыми дочерними элементами
xsl:stylesheet
основного преобразования.

Пример

Предположим, что в основное преобразование мы импортируем файл

a.xsl
и включаем файл
b.xsl
.

Листинг 4.8. Основное преобразование

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Листинг 4.9. Преобразование b.xsl

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Тогда основное преобразование может быть переписано следующим образом.

Листинг 4.10. Основное преобразование после включения b.xsl

Элемент

xsl:include
можно использовать и для включения преобразований с упрощенным синтаксисом. Преобразования такого рода будут включаться как эквивалентные им преобразования стандартного синтаксиса — то есть с корневым элементом
xsl:stylesheet
и единственным шаблоном, соответствующим корневому узлу.

Пример

Предположим, что мы используем преобразование упрощенного синтаксиса

simple.xsl
.

Листинг 4.11. Преобразование simple.xsl

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Включим

simple.xsl
в основное преобразование.

Листинг 4.12. Основное преобразование

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">



Тогда основное преобразование может быть переписано в следующем виде.

Листинг 4.13. Основное преобразование после включения simple.xsl

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">



Полужирным шрифтом на листинге 4.13 выделен шаблон, который соответствует преобразованию

simple.xsl
.

Следует отметить, что разные процессоры по-разному обрабатывают включение упрощенных преобразований. К сожалению, большинство из них не поддерживают эту особенность, хотя она четко определена в спецификации, поэтому, если требуется высокая надежность и переносимость, таких включений лучше избегать.

Включаемые модули являются полноценными и самостоятельными преобразованиями. К примеру, они также могут включать другие преобразования при помощи тех же элементов

xsl:include
. При этом преобразование не должно прямо или косвенно включать само себя — такая ситуация породит бесконечный цикл включений.

Импорт преобразований

Другим способом использования внешних модулей в XSLT является импорт преобразований, который обеспечивается элементом

xsl:import
. Импорт преобразований более сложен, чем их простое включение — последовательность импорта модулей может влиять на то, как будет выполняться преобразование. Равно как и в случае с
xsl:include
, условное импортирование преобразований не разрешено.

Элемент xsl:import

href =" URI"/>

Синтаксис импорта преобразования практически полностью аналогичен включению: обязательный атрибут

href
содержит URI внешнего модуля, который должен быть импортирован в текущее преобразование. Так же, как и в случае с
xsl:include
, элемент
xsl:import
логически заменяется содержимым внешнего модуля, и относительные идентификаторы ресурсов (URI), используемые во внешнем преобразовании, отсчитываются от его базового адреса. Преобразование не может прямо или косвенно импортировать само себя.

Совет

Не следует импортировать или включать в преобразование больше кода, чем необходимо. Если в одном импортируемом модуле находится много разнородных шаблонов, определений и так далее, лучше разбить этот модуль на несколько более мелких. Половина модуля загружается быстрее, чем модуль целиком. При этом целый модуль загружается быстрее, чем две его половины по отдельности.

Главным отличием импорта преобразований является то, что последовательность импортирования внешних модулей, называемая порядком импорта оказывает влияние на приоритет исполнения шаблонов, определения и многое другое.

Порядок импорта

Как уже было сказано выше, элементы

xsl:import
должны всегда быть первыми дочерними элементами
xsl:stylesheet
. Порядок, в котором они находятся в преобразовании, определяет порядок импорта внешних модулей следующим образом.

□ Порядок импорта основного преобразования всегда старше порядка импорта внешнего преобразования.

□ В случае, если преобразование импортирует несколько внешних модулей, порядок импорта преобразований, которые импортируются раньше, младше порядка импорта последующих модулей.

□ Порядок импорта преобразования, включенного в основное при помощи элемента

xsl:include
, равен порядку импорта основного преобразования.

Эти правила могут быть проиллюстрированы следующими примерами.

Рассмотрим преобразование

alpha.xsl
, которое импортирует преобразования
bravo.xsl
и
сharlie.xsl
и включает преобразование
delta.xsl
.

Листинг 4.14. Фрагмент преобразования alpha.xsl

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

В соответствии с первым правилом, порядок импорта основного преобразования старше порядка импорта внешних модулей, значит

alpha.xsl
старше
bravo.xsl
и
charlie.xsl
. Далее, согласно второму правилу порядок импорта преобразования
bravo.xsl
младше порядка
charlie.xsl
, поскольку оно импортируется первым. Преобразование
delta.xsl
будет иметь порядок импорта такой же, как и у основного преобразования
alpha.xsl
. Таким образом, порядок импорта в этом примере будет иметь следующий вид:

bravo.xsl

charlie.xsl

alpha.xsl delta.xsl

Преобразование

bravo.xsl
будет самым младшим, а преобразования
alpha.xsl
и
delta.xsl
— самыми старшими.

Заметим, что импортируемые преобразования могут и сами импортировать другие модули. В этих случаях вычисление порядка импорта несколько усложняется.

Техническая рекомендация XSLT предлагает решать эту проблему построением логического дерева импорта.

Пример

Рассмотрим следующую схему включений и импорта (табл 4.1).


Таблица 4.1. Включение и импорт преобразований

ПреобразованиеИмпортируетВключает
alpha.xsl
bravo.xsl charlie.xsl
bravo.xsl
delta.xsl echo.xsl
foxtrot.xsl
charlie.xsl
golf.xsl hotel.xsl
hotel.xsl
india.xsl

Этой схеме будет соответствовать логическое дерево импорта на рис. 4.1.

Рис. 4.1. Обход дерева импорта преобразований

В соответствии с правилами, левые ветки дерева будут младше правых, вершины, находящиеся ближе к корню, будут старше тех, которые дальше от него, включенные преобразования имеют тот же приоритет, что и у родителей.

Таким образом, порядок импорта преобразований от младших к старшим будет выглядеть следующим образом:

delta.xsl

echo.xsl

bravo.xsl foxtrot.xsl

golf.xsl

hotel.xsl india.xsl

charlie.xsl

alpha.xsl

Порядок, в котором импортируются модули, непосредственным образом влияет на различные аспекты преобразования. Эффект, который оказывает порядок импорта на те или иные элементы, будет подробно описан при их рассмотрении — сейчас же мы их просто коротко перечислим.

xsl:attribute-set
— порядок импорта используется для определения главенства элементов
xsl:attribute
, включенных в разные именованные списки атрибутов, но создающих атрибуты с одинаковыми именами.

xsl:namespace-alias
— в случае, если в преобразовании определяются несколько псевдонимов префиксов пространств имен, процессор использует самый старший в порядке импорта псевдоним.

xsl:output
— эти элементы объединяются процессором. В случае конфликтов, например, когда в разных элементах
xsl:output
атрибуты определены по-разному, процессор должен использовать старшее в порядке импорта определение.

xsl:strip-space
и
xsl:preserve-space
— в этих элементах порядок импорта также используется для разрешения конфликтов: выигрывают определения со старшим порядком импорта.

xsl:template
— порядок импорта используется для разрешения конфликтов, которые возникают в случаях, когда один узел может быть обработан несколькими шаблонами. Шаблон, содержащийся в преобразовании с младшим порядком импорта, будет просто исключен из рассмотрения.

xsl:variable
и
xsl:param
— порядок импорта используется при обращении к глобальным переменным в случае, если в разных преобразованиях существуют разные определения переменной с одним именем. В подобной ситуации будет использована переменная со старшим порядком импорта.

Использование сущностей для разбивки на модули

Поскольку XSLT-преобразования являются XML-документами, мы можем воспользоваться средствами XML для модульной организации данных. Части преобразований можно просто вынести во внешние документы и включать в документ в виде сущности.

Пример
Листинг 4.15. Входящий документ:

]>

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">



&ab;


Листинг 4.17. Файл ab.xsl


Листинг 4.18. Результат преобразования

В этом примере в DTD-блоке мы определяем сущность с именем

ab
, которая содержит два шаблонных правила для обработки элементов
a
и
b
. Файл
ab.xsl
, в котором содержится текст внешней сущности, заменяет в документе ссылку
&ab;
. После раскрытия процессором сущности (замены ссылки на ее содержимое) наше преобразование будет выглядеть следующим образом.

Листинг 4.19. Основное преобразование после раскрытия сущности &ab;

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">





Совместное использование преобразований и XML-документов