Основные элементы XSLT
Основные и дополнительные элементы
Все элементы XSLT можно разделить на две группы: элементы основные и элементы дополнительные. Это разделение очень условно, ничего подобного в спецификации языка XSLT нет, однако, мы будем им пользоваться, считая основными элементами те элементы XSLT, которые непосредственно отвечают за создание узлов выходящего дерева или обеспечивают контроль над этим процессом. К дополнительным элементам мы будем относить все остальные элементы XSLT.
Таким образом, множество основных элементов будет включать в себя следующее:
□
xsl:element
— создание в выходящем дереве узла элемента;□
xsl:attribute
— создание в выходящем дереве узла атрибута;□
xsl:attribute-set
— определение именованного набора атрибутов;□
xsl:text
— создание текстового узла;□
xsl:value-of
— создание текстового узла по результатам вычисления выражения;□
xsl:comment
— создание узла комментария;□
xsl:processing-instruction
— создание узла инструкции по обработке;□
xsl:copy
— копирование текущего узла вместе с его узлами пространств имен;□ x
sl:copy-of
— копирование результата вычисления выражения;□
xsl:if
— условная обработка;□
xsl:choose
, xsl:when
и xsl:otherwise
— выбор одной из нескольких альтернатив согласно некоторым условиям;□
xsl:for-each
— итеративная обработка множества узлов.Создание узлов элементов
В четвертой главе мы уже разобрали один из способов создания в выходящем документе узлов элементов, а именно — использование литеральных элементов результата, которые в неизменном виде копируются процессором в выходящее дерево. Этот способ прост, понятен и удобен, однако есть две основные проблемы, которые он не может решить.
□ Что, если в выходящем документе требуется создать элемент с заранее неизвестным (например, вычисляемым во время выполнения) именем?
□ Как создать элемент, принадлежащий пространству имен, известному обрабатывающему процессору?
Поясним на примерах суть и той и другой проблемы.
Представим себе входящий документ вида
который нужно преобразовать во что-нибудь наподобие
<а>
а>
Совершенно очевидно, что литеральными элементами тут не обойдешься — мы не знаем заранее имена элементов выходящего документа, ибо они определяются значениями атрибутов входящего.
Представим теперь, что нам в XSLT-преобразовании необходимо сгенерировать другое XSLT-преобразование. Скажем из элемента вида
нужно получить шаблон
Беда в том, что литеральные элементы не могут быть использованы для создания, скажем, элемента
xsl:template
по той причине, что любой элемент с локальной частью имени template
, принадлежащий пространству имен XSLT будет рассматриваться процессором, как элемент самого преобразования. Очевидно, что
будет некорректным определением. He поможет и смена префикса, ведь принадлежность пространству имен определяется не им.
Для того чтобы решить эти проблемы (главным образом, первую), XSLT предоставляет возможность создавать узлы элементов при помощи элемента
xsl:element
.Элемент xsl:element
Синтаксическая конструкция этого элемента задается следующим образом:
name="{имя}"
namespace="{пространство имен}
"use-attribute-sets="имена">
Здесь обязательный атрибут
name
указывает имя создаваемого элемента. Этот атрибут может содержать шаблон значения, а значит, имя элемента может быть вычислено во время выполнения.Атрибут
namespace
указывает URI пространства имен создаваемого элемента. Точно так же, как и name, этот атрибут может содержать шаблон значения, что позволяет вычислять пространство имен создаваемого элемента при помощи выражений.Атрибут
use-attribute-sets
перечисляет имена наборов атрибутов, которые должны быть включены в создаваемый элемент.Содержимым
xsl:element
является шаблон, который выполняется процессором и затем включается в создаваемый элемент.ПримерПредположим, мы хотим поменять имя каждого элемента на значение его первого атрибута и наоборот.
Листинг 7.1. Входящий документ
Листинг 7.2. Шаблон, заменяющий имя элемента значением атрибута
Листинг 7.3. Выходящий документ
В этом примере код
...
создает элемент, именем которого становится значение выражения @*
, указанного в виде шаблона значения атрибута name
. Это выражение выбирает множество, состоящее из узлов атрибутов текущего элемента, а если привести его к строке, в результате получится текстовое значение первого атрибута элемента.Подобным образом выбирается имя атрибута создаваемого элемента и его значение.
Вычисленное значение атрибута
name
может задавать и расширенное имя элемента, то есть иметь форму префикс:имя
. В этом случае элемент будет создаваться в том пространстве имен, которое соответствует указанному префиксу, например
создаст элемент вида
Заметим, что элемент вида
даст тот же результат.
Другим способом указания пространства имен при использовании элемента
xsl:element
является использование атрибута namespace
. Например, для предыдущего случая мы могли бы записать
name="template"
namespace="http://www.w3.org/1999/XSL/Transform"/>
и получить в итоге
что эквивалентно результату предыдущего примера, хоть и различается внешне.
Атрибут
namespace
тоже может быть сконструирован на этапе выполнения, например:
name="template"
namespace="{concat('http://www.w3.org/', 2001 - 2, '/XSL/Transform')}"/>
что также даст элемент
template
, принадлежащий пространству имен XSLT.Для того чтобы разобраться в приоритетах атрибутов
name
и namespace
на определение пространства имен, приведем несколько правил, которые пояснят этот процесс.□ Если в элементе
xsl:element
определен атрибут namespace
, то создаваемый элемент будет принадлежать пространству имен с URI, который будет значением этого атрибута. Если значением атрибута namespace
будет пустая строка, создаваемый элемент будет принадлежать нулевому пространству имен. Как правило, процессоры используют префикс, указанный в имени атрибутом name
, но, вместе с тем, они не обязаны так делать. Поэтому в общем случае следует ожидать, что префикс может быть любым.□ Если в элементе
xsl:element
не определен атрибут namespace
, но имя, заданное в атрибуте name имеет префикс, то создаваемый элемент будет принадлежать соответствующему этому префиксу пространству имен. Однако и в этом случае не гарантируется, что префикс создаваемого элемента будет таким, каким он был задан в атрибуте name
.□ В случае, если в элементе
xsl:element
не определен атрибут namespace
и имя, заданное в атрибуте name не имеет префикса, создаваемый элемент будет принадлежать пространству имен, которое действует для создающего элемента xsl:element
по умолчанию.Повторим еще раз, что во всех трех случаях сказать что-либо достоверно о префиксе создаваемого элемента нельзя — префикс с точки зрения пространств имен не является значащей частью имени элемента. Вместе с тем, на практике процессоры, как правило, используют префикс, указанный в атрибуте
name
, или не используют префикс вообще, если префикс в name
указан не был.Приведем несколько примеров.
Для начала покажем, что, согласно первому правилу, атрибут
namespace
имеет наивысший приоритет при определении пространства имен выходящего элемента. Рассмотрим следующее преобразование.Листинг 7.4.
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
name="xsl:html"
namespace="http://www.w3.org/1999/xhtml"/>
В выделенном элементе
xsl:element
пространство имен создаваемого элемента указано вроде бы два раза: в виде значения атрибута namespace
и в виде префикса имени ("xsl
"). Результат будет выглядеть следующим образом:
Процессор использовал пространство имен, указанное в атрибуте
namespace
, локальную часть имени, заданного атрибутом name ("html
"), а также префикс (только префикс, но не связанное с ним пространство имен) этого имени ("xsl
").В свою очередь конструкция вида
создаст элемент
что на самом деле эквивалентно просто
.Таким образом, атрибут
namespace
наиболее приоритетен для определения пространства имен создаваемого элемента. Обратимся теперь к случаю, когда этот атрибут опущен в xsl:element
. Объявление вида
создаст элемент
Как видим, отсутствие
namespace
и namespace=""
— не одно и то же.Рассмотрим теперь случай, когда нет ни атрибута
namespace
, ни префикса в name
:
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Результатом этого преобразования будет документ, состоящий из одного пустого элемента
html
:
Мы специально привели все преобразование целиком, чтобы показать, что выходящий элемент будет принадлежать нулевому пространству имен тогда и только тогда, когда для него не было объявлено пространства имен по умолчанию. Попробуем посмотреть, что получится, если пространство имен по умолчанию будет объявлено:
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
Результатом в этот раз будет элемент с локальной частью имени "
html
", принадлежащий пространству имен с URI "http://www.w3.org/1999/xhtml
":
Создание узлов атрибутов