Алексей Валиков - Технология XSLT
Что касается псевдоатрибута type, то на самом деле нет стандарта, который заставлял бы использовать значение "text/xsl". Рабочая группа XSL Консорциума W3 до сих пор обсуждает, какой именно тип должен быть присвоен XSLT. Поскольку XSLT есть XML-язык, формально следовало бы использовать "application/xml", однако с легкой подачи Microsoft все используют "text/xsl".
Инструкция xml-stylesheet может быть включена только в пролог документа, то есть она должна предшествовать корневому элементу. Не рекомендуется включать эту инструкцию в блоки DOCTYPE, поскольку некоторые парсеры и процессоры будут ее в этом случае игнорировать.
ПримерыСтандартный механизм использования xml-stylesheet может быть продемонстрирован следующим документом:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="mytransform.xsl"?>
<body>
<!-- ... -->
</body>
В этом документе инструкция xml-stylesheet указывает на то, что этот документ должен быть обработан XSLT-преобразованием mytransform.xsl.
Псевдоатрибут title может содержать краткое описание применяемого преобразования:
<?xml-stylesheet
title="Generate menu"
type="text/xsl"
href="menu.xsl"?>
Псевдоатрибуты media и alternate могут использоваться совместно для того, чтобы описать альтернативное представление документа, к примеру, на небольших мобильных устройствах:
<?xml-stylesheet
type="text/xsl"
href="pda.xsl"
alternate="yes"
media="handheld"?>
Теоретически, если документ с такой инструкцией будет показываться на мобильном устройстве (например, на Palm Pilot), он должен быть преобразован при помощи pda.xsl. На практике не следует полагаться на подобные возможности, поскольку они сильно зависят от поддержки серверов и процессоров, которая в этом отношении все еще сильно ограничена.
В заключение описания инструкции xml-stylesheet приведем правила, которые определяют ее синтаксис.
[XMS1] StyleSheetPI ::= '<?xml-stylesheet' (S PseudoAtt)* S? '?>'
[XMS2] PseudoAtt ::= Name S? '=' S? PseudoAttValue
[XMS3] PseudoAttValue ::= ( '"' ([^"<&]|CharRef|PredefEntityRef)* '"'
| "'" ([^'<&]|CharRef|PredefEntityRef)* "'")
- (Char* '?>' Char*)
[XMS4] PredefEntityRef ::= '"' | '<'
| '>' | '&' | '''
Объединение документа и преобразования
XSLT-преобразование является, как правило, самостоятельным XML-документом, корневым элементом которого является xsl:stylesheet или xsl:transform. Вместе с тем, иногда бывает необходимо объединять преобразуемый документ и само преобразование так, чтобы они находились в одном файле.
Мы опишем два способа объединения документов и преобразований. Первый основывается на использовании инструкции xml-stylesheet для того, чтобы закрепить за документом преобразование, находящееся внутри него самого. Во втором способе обрабатываемый документ включается в преобразование как пользовательский элемент верхнего уровня и обрабатывается при помощи функции document('') с пустым строковым параметром.
Включение преобразования в документ
Корневой элемент преобразования xsl:stylesheet может быть включен в преобразуемый документ со всеми дочерними элементами верхнего уровня и так далее. Для того чтобы использовать это преобразование, псевдоатрибут href инструкции по обработке xml-stylesheet должен указывать на идентификатор элемента xsl:stylesheet, определенный в его атрибуте id.
Пример Листинг 4.20. Входящий документ<?xml version="1.0"?>
<?xml-stylesheet type="text/xml" href="#transform"?>
<page>
<title>Main page</title>
<content>Main content</content>
<xsl:stylesheet
id="transform"
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<body title="{page/title}">
<xsl:text><xsl:value-of select="page/content"/></xsl:text>
</body>
</xsl:template>
<xsl:template match="xsl:stylesheet"/>
</xsl:stylesheet>
</page>
Листинг 4.21. Выходящий документ<body title="Main page">
Main content
</body>
Поскольку элемент xsl:stylesheet включен в преобразуемый документ, он также подвергнется преобразованию. Для того чтобы избежать этого, в преобразование включается шаблонное правило, которое указывает, что элементы xsl:stylesheet следует игнорировать:
<xsl:template match="xsl:stylesheet"/>
К сожалению, приходится констатировать тот факт, что описанную возможность (хотя она и включена в спецификацию языка XSLT) поддерживают очень немногие процессоры и поэтому пока что на нее не следует полагаться.
Включение документа в преобразование
Другой возможностью объединения документов и преобразований является включение элемента документа в преобразование в виде элемента верхнего уровня.
Поскольку преобразование также является XML-документом, доступ к данным, которые оно содержит можно получить при помощи функции document, так же, как если бы документ преобразования был внешним документом. Функция document, которой в качестве параметра была передана пустая строка, возвращает множество, состоящее из корневого узла самого преобразования. То есть, если документ был включен в преобразование в качестве элемента верхнего уровня с именем, к примеру, user:input, получить доступ к нему можно при помощи выражения
document('')/xsl:stylesheet/user:input
Пример Листинг 4.22. Входящий документ<whatever/>
Листинг 4.23. Преобразование<xsl:stylesheet
version="1.0"
xmlns:user="urn:user"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="user">
<input xmlns="urn:user">
<a/>
<b/>
</input>
<xsl:template match="/">
<xsl:apply-templates
select="document('')/xsl:stylesheet/user:input"/>
</xsl:template>
<xsl:template match="user:a">
<A/>
</xsl:template>
<xsl:template match="user:b">
<B/>
</xsl:template>
<xsl:template match="user:input">
<output>
<xsl:apply-templates/>
</output>
</xsl:template>
</xsl:stylesheet>
Листинг 4.24. Выходящий документ<output>
<A/>
<B/>
</output>
Следует обратить внимание на следующие особенности этого примера.
□ Элементы верхнего уровня в обязательном порядке должны иметь ненулевое пространство имен. Поэтому мы включили элемент input и все его дочерние узлы в пространство имен urn:user. В листинге 4.23 эти элементы выделены полужирным шрифтом.
□ В шаблонах, которые обрабатывают элементы включенного документа, должны указываться паттерны, соответствующие расширенным именам этих элементов, то есть не input, a user:input.
□ Чтобы не выводить объявления пространств имен в выходящем документе, мы включили префикс user в атрибут exclude-result-prefixes элемента xsl:stylesheet.
Как можно видеть, включение элемента input как элемента верхнего уровня породило определенные проблемы. Для того чтобы избежать их, можно воспользоваться маленьким фокусом — включать документ не как элемент верхнего уровня, а в элемент верхнего уровня.
ПримерРезультат следующего преобразования в точности совпадает с результатом преобразования в предыдущем примере.
Листинг 4.25. Пользовательские данные в элементе верхнего уровня<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="input">
<input>
<a/>
<b/>
</input>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates
select="document('')/
xsl:stylesheet/xsl:template[@name='input']/input"/>
</xsl:template>
<xsl:template match="a">
<A/>
</xsl:template>
<xsl:template match="b">
<B/>
</xsl:template>
<xsl:template match="input">