<xsl:output> XSLT

Элемент верхнего уровня xsl:output позволяет указывать, каким образом должно быть выведено результирующее дерево.

Элементы-родители:

Синтаксис

XSLT 1.0

<xsl:output
    method = "xml | html | text | нестандартный_метод"
    version = "версия"
    encoding = "строка"
    omit-xml-declaration = "yes | no"
    standalone = "yes | no"
    doctype-public = "строка"
    doctype-system = "строка"
    cdata-section-elements = "строка"
    indent = "yes | no"
    media-type = "строка" />

Атрибуты

  • methodнеобязательный атрибут, который определяет, какой метод должен использоваться для вывода документа. Значением этого атрибута может быть любое имя, но при этом техническая рекомендация XSLT определяет только три стандартных метода вывода — “xml”, “html” и “text”. В том случае, если процессор поддерживает нестандартный метод вывода, его реализация полностью зависит от производителя. Если в преобразовании не определен элемент xsl:output или в нем не указан атрибут method, метод преобразования выбирается по умолчанию исходя из следующих условий.
    • Если корень выходящего документа имеет дочерний элемент с локальным именем “html” (в любом регистре символов), которому предшествуют только пробельные символы, методом вывода по умолчанию становится “html”.
    • Во всех остальных случаях методом вывода по умолчанию является “xml”.
  • versionнеобязательный атрибут, определяет версию языка выходящего документа;
  • indentнеобязательный атрибут, определяет, должен ли процессор добавлять пробельные символы для более наглядного форматирования документа;
  • encodingнеобязательный атрибут, определяет, в какой кодировке должен быть выведен документ. Значение этого атрибута не зависит от регистра символов, то есть значения encoding="utf-8" и encoding="UtF-8" будут эквивалентны. В атрибуте encoding можно использовать только печатаемые символы ASCII, то есть символы интервала от #x21 до #x7e. Значением encoding должно быть название набора символов, определенное в стандартах IANA (Internet Assigned Numbers Authority) или RFC2278. В противном случае, атрибут должен начинаться символами “x-”;
  • media-typeнеобязательный атрибут, определяет тип содержимого MIME выходящего документа;
  • doctype-systemнеобязательный атрибут, определяет системный идентификатор, который должен быть использован в декларации типа документа (DTD);
  • doctype-publicнеобязательный атрибут, определяет публичный идентификатор, который должен быть использован в декларации типа документа (DTD);
  • omit-xml-declarationнеобязательный атрибут, определяет, нужно ли включать декларацию XML в выходящий документ или нет. Значением этого атрибута должно быть либо “yes” (пропустить декларацию), либо “no” (включить декларацию в выходящий документ);
  • standaloneнеобязательный атрибут, определяет, должен ли процессор выводить указание на самостоятельность документа (standalone declaration). Значением этого атрибута может быть либо “yes” (выводить указание), либо “no” (не выводить указание на самостоятельность);
  • cdata-section-elementsнеобязательный атрибут, определяет список элементов, текстовое содержимое которых должно быть выведено с использованием секций CDATA.

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

Спецификация

XSLT 2.0

<xsl:output
    name? = qname
    method? = "xml" | "html" | "xhtml" | "text" | qname-but-not-ncname
    byte-order-mark? = "yes" | "no"
    cdata-section-elements? = qnames
    doctype-public? = string
    doctype-system? = string
    encoding? = string
    escape-uri-attributes? = "yes" | "no"
    include-content-type? = "yes" | "no"
    indent? = "yes" | "no"
    media-type? = string
    normalization-form? = "NFC" | "NFD" | "NFKC" | "NFKD" | "fully-normalized" | "none" | nmtoken
    omit-xml-declaration? = "yes" | "no"
    standalone? = "yes" | "no" | "omit"
    undeclare-prefixes? = "yes" | "no"
    use-character-maps? = qnames
    version? = nmtoken />

Атрибуты

  • methodнеобязательный атрибут, обычно принимает одно из четырех значений: xml, html, xhtml или text. Значение определяет тип генерируемого документа. Процессор XSLT может дополнить список другими значениями; влияние этих значений на генерируемый документ определяется процессором XSLT. По умолчанию используется значение xml, если только корневым элементом выходного документа не является <html>. В стандарте XSLT 1.0 определяются только три метода вывода: xml, html и text. В XSLT 2.0 добавлен метод xhtml, который должен поддерживаться процессором XSLT. Процессорам разрешается добавлять другие значения.
  • versionнеобязательный атрибут, определяет версию выходного документа XML, HTML или XHTML. Игнорируется при наличии атрибута method="text". Атрибут version элемента <xsl:output> своим поведением отличается от атрибута version, поддерживаемого всеми элементами XSLT в XSLT 2.0. За подробностями обращайтесь к статье атрибуты, общие для всех элементов XSLT.
  • encodingнеобязательный атрибут, определяет значение encoding, задаваемое в объявлении XML выходного документа. Игнорируется при наличии атрибута method="text".
  • omit-xml-declarationнеобязательный атрибут, определяет, должно ли объявление XML быть опущено в выходном документе. Допустимые значения: yes и no; по умолчанию используется no. Атрибут используется только в режимах method="xml" и method="xhtml".
  • standaloneнеобязательный атрибут, определяет значение атрибута standalone в объявлении XML выходного документа. Допустимые значения: yes и no. Атрибут используется только в режимах method="xml" и method="xhtml". В XSLT 2.0 поддерживается также значение omit. Атрибут standalone="omit" означает, что в выходном документе значение standalone не задано.
  • doctype-publicнеобязательный атрибут, определяет значение атрибута PUBLIC в объявлении DOCTYPE выходного документа. Атрибут определяет открытый идентификатор DTD выходного документа. Игнорируется при наличии атрибута method="text".
  • doctype-systemнеобязательный атрибут, определяет значение атрибута SYSTEM в объявлении DOCTYPE в выходном документе. Атрибут определяет системный идентификатор DTD выходного документа. Игнорируется при наличии атрибута method="text".
  • cdata-section-elementsнеобязательный атрибут, перечисляет элементы, содержимое которых записывается в выходной документ в виде секций CDATA. Соблюдение всех ограничений и правил экранирования для секций CDATA обеспечивается процессором XSLT. Если потребуется перечислить более одного элемента, разделите их имена одним или несколькими символами-пропусками. Атрибут используется только в режимах method="xml" и method="xhtml".
  • indentнеобязательный атрибут, определяет наличие отступов в тегах выходного документа. Допустимые значения: yes и no. Атрибут используется только в режимах method="xml", method="html" и method="xhtml", причем процессор XSLT не обязан обеспечивать его реализацию. По умолчанию используются значение yes для method="html" и method="xhtml" и значение no для method="xml".
  • media-typeнеобязательный атрибут, определяет тип MIME для выходного документа. По умолчанию используются значения text/xml для method="xml", text/html для method="html" и method="xhtml" и text/plain для method="text".
  • nameнеобязательный атрибут, определяет имя спецификации выходного документа. Новый элемент <xsl:result-document> может использовать ссылки на это имя в атрибуте format. Если таблица стилей использует элемент <xsl:result-document> для создания нескольких выходных документов, определите спецификацию выходного документа с атрибутом name и используйте его там, где потребуется.
  • byte-order-markнеобязательный атрибут, определяет, должна ли метка порядка байтов записываться в выходной документ. Допустимые значения: yes и no. По умолчанию значение yes используется для кодировки UTF-16, тогда как значение по умолчанию для UTF-8 зависит от процессора XSLT. Для всех остальных кодировок по умолчанию используется значение no.
  • escape-uri-attributesнеобязательный атрибут, определяет, должны ли специальные символы в атрибутах HTML и XHTML с URI-значениями заменяться своими шестнадцатеричными кодами. Например, если URI-адрес содержит пробелы, в преобразованном значении каждый пробел заменяется обозначением %20.
  • include-content-typeнеобязательный атрибут, определяет, должен ли тип содержимого записываться в выходной документ. Допустимые значения: yes и no; по умолчанию используется значение yes. Например, при использовании атрибута include-content-type для method="html" в элемент <head> документа HTML включается элемент <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">.
  • normalization-formнеобязательный атрибут, определяет способ нормализации символов Юникода. Допустимые значения: NFC, NFD, NFKC, NFKD, fully-normalized и none. Процессоры XSLT также могут поддерживать другие значения; за информацией о поддержке других форм нормализации обращайтесь к документации своего процессора.
  • undeclare-prefixesнеобязательный атрибут, определяет, должен ли выходной документ включать отменяющие объявления пространств имен (такие объявления связывают префикс пространства имен с пустой строкой, например xmlns:doug=""). Допустимые значения: yes и no; этот атрибут имеет смысл только с method="xml" и в том случае, если атрибут version равен 1.1 или выше. За полной информацией об этом малопонятном атрибуте обращайтесь к разделу 20 спецификации XSLT 2.0.
  • use-character-mapsнеобязательный атрибут, определяет список именованных карт символов, разделенных пробелами (карты создаются элементом <xsl:character-map>, используемым при создании выходного документа).

XSLT 3.0

<xsl:output
    name? = eqname
    method? = "xml" | "html" | "xhtml" | "text" | eqname
    byte-order-mark? = boolean
    cdata-section-elements? = eqnames
    doctype-public? = string
    doctype-system? = string
    encoding? = string
    escape-uri-attributes? = boolean
    html-version? = decimal
    include-content-type? = boolean
    indent? = boolean
    item-separator? = string
    media-type? = string
    normalization-form? = "NFC" | "NFD" | "NFKC" | "NFKD" | "fully-normalized" | "none" | nmtoken
    omit-xml-declaration? = boolean
    parameter-document? = uri
    standalone? = boolean | "omit"
    suppress-indentation? = eqnames
    undeclare-prefixes? = boolean
    use-character-maps? = eqnames
    version? = nmtoken />

Описание и примеры

Пример

Для документа

<HTML>
    <HEAD>
        <TITLE>XSL Transformations (XSLT)</TITLE>
    </HEAD>
    <BODY>
        <H1>XSL Transformations (XSLT)<BR/>Version 1.0</H1>
    </BODY>
</HTML>

Методом вывода по умолчанию будет “html”, а для документа

<BODY>
    <H1>XSL Transformations (XSLT)<BR/>Version 1.0</H1>
</BODY>

будет выбран метод вывода “xml”.

Метод вывода “xml”

Для того чтобы вывести результирующее дерево в виде XML-документа, следует использовать в элементе xsl:output метод “xml”. Ниже мы подробно опишем, каким образом на выход должны влиять другие атрибуты этого элемента.

Атрибут version

Этот атрибут определяет версию языка XML, которая должна использоваться для вывода результирующего документа. В случае если процессор не поддерживает указанную версию, он может либо выдать ошибку, либо использовать одну из поддерживаемых версий. На данный момент единственной действующей версией языка является версия 1.0 и потому, если в атрибуте в version будет указано другое значение, единственным эффектом от этого будет измененный параметр version в декларации XML.

Пример

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

<xsl:output method="xml" version="1.2"/>

Тогда процессор может вывести декларацию XML в следующем виде:

<?xml version="1.2" encoding="utf-8"?>

Значением атрибута version по умолчанию является “1.0”, то есть, для того, чтобы получить декларацию XML вида

<?xml version="1.0" ?>

достаточно опустить определение атрибута version:

<xsl:output method="xml"/>

Атрибут encoding

Атрибут encoding указывает на то, какая кодировка предпочтительна для выходящего документа. Множество кодировок зависит от используемого процессора, но при этом в соответствии с технической рекомендацией все они обязаны поддерживать Unicode-формы кодировок UTF-8 и UTF-16.

В случае если процессор не поддерживает кодировку, указанную в атрибуте encoding, процессор может либо выдать ошибку, либо использовать UTF-8 или UTF-16.

Если атрибут encoding опущен, процессор должен по умолчанию использовать UTF-8 или UTF-16. На практике абсолютное большинство процессоров используют по умолчанию кодировку UTF-8.

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

Пример

Представим себе входящий документ в кодировке UTF-8, содержащий символ кириллицы “Э” с Unicode-кодом #x42d (или #1069 в десятичной системе счисления):

<?xml version="1.0" encoding="utf-8"?>
<page>Э</page>

Если преобразование будет использовать для вывода кодировку, которая не может отображать символы кириллического алфавита, например ISO-8859-1, то символ “Э” в выходящем документе должен быть заменен символьной сущностью.

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="ISO-8859-1" indent="yes" />
    <xsl:template match="/">
        <xsl:copy-of select="/page"/>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.37. Выходящий документ

<?xml version="1.0" encoding="ISO-8859-1"?>
<page>Э</page>

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

<?xml version="1.0" encoding="utf-8"?>
<страница>Э</страница>

то вывести результирующее дерево в кодировке ISO-8859-1 будет невозможно.

Атрибут indent

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

<A><B><C/></B><C><B></B></C></A>

или

<A>
    <B>
        <C/>
    </B>
    <C>
        <B>
        </B>
    </C>
</A>

Очевидно, что второй случай гораздо легче для понимания, поскольку в нем легко можно видеть принадлежность элементов одного другому. Подобное форматирование можно использовать и при выводе преобразованного документа при помощи атрибута indent элемента xsl:output. Если этот атрибут имеет значение “yes”, процессор может добавить один или несколько пробельных символов или символов перевода строки — в зависимости от реализации. Как правило, каждый дочерний элемент помещают на новой строке, добавляя впереди два пробела на каждый уровень вложенности.

Пример

Листинг 8.38. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<A><B><C/></B><C><B></В></C></A>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="/">
        <xsl:copy-of select="/"/>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.40. Выходящий документ

<?xml version="1.0" encoding="utf-8"?>
<A>
    <B>
        <C/>
    </B>
    <C>
        <B/>
    </C>
</A>

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

Атрибут cdata-section-elements

Для того чтобы вывести текстовое содержимое некоторых элементов в виде секций CDATA, XSLT предлагает простой механизм — следует лишь перечислить в атрибуте cdata-section-elements элемента xsl:output элементы, которые на выходе должны содержать секции символьных данных.

Пример

Листинг 8.41. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page><br/><br/></page>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" cdata-section-elements="page"/>
    <xsl:template match="/">
        <xsl:copy-of select="/"/>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.43. Выходящий документ

<?xml version="1.0" encoding="utf-8"?>
<page><![CDATA[<br/>]]><br/>
</page>

В соответствии с синтаксисом XML, секции CDATA не могут содержать последовательности символов “]]>”. Потому, встретив такую комбинацию в тексте элемента, имя которого включено в cdata-section-elements, процессор заменит ее двумя секциями CDATA. Одна будет содержать “]]”, вторая – “>”.

Пример

Листинг 8.44. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page>
    <data>]]></data>
    <pre><!-- Comment --></pre>
</page>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" cdata-section-elements="data pre"/>
    <xsl:template match="/">
        <xsl:copy-of select="/"/>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.46. Выходящий документ

<?xml version="1.0" encoding="utf-8"?>
<page>
    <data><![CDATA[]]]]><![CDATA[>]]></data>
    <pre><![CDATA[<!-- Comment -->]]></pre>
</page>

Атрибут doctype-system

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

XSLT позволяет создавать ссылки на внешние определения типов при помощи атрибута doctype-system элемента xsl:output.

Пример

Предположим, что мы создаем документ, логическая схема которого определена во внешнем файле по адресу “/dtds/document.dtd”. Тогда, определив в преобразовании элемент xsl:output с атрибутом doctype-system, равным “/dtds/document.dtd”, мы получим в выходящем документе определение типа в виде

<!DOCTYPE элемент SYSTEM "/dtds/document.dtd">

где элемент — первый элемент выходящего документа.

Листинг 8.47. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page> content </page>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" doctype-system="/dtds/document.dtd"/>
    <xsl:template match="/"><xsl:copy-of select="/"/></xsl: template>
</xsl:stylesheet>

Листинг 8.49. Выходящий документ

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE page SYSTEM "/dtds/document.dtd">
<page> content </page>

Атрибут doctype-public

Если в преобразовании атрибутом doctype-system элемента xsl:output задано внешнее определение логического типа документа, это определение может быть расширено также и публичным идентификатором. Публичный идентификатор указывается в атрибуте doctype-public элемента xsl:output. Его использование может быть продемонстрировано следующим примером.

Листинг 8.50. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page> content </page>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"
        doctype-system="/dtds/document.dtd"
        doctype-public="-//Document//Description" />
    <xsl:template match="/">
        <xsl:copy-of select="/"/>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.52. Выходящий документ

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE page PUBLIC "-//Document//Description" "/dtds/document.dtd">
<page> content </page>

Атрибут media-type

Атрибут media-type позволяет задавать медиа-тип содержимого выходящего документа. Для метода вывода “xml” значением media-type по умолчанию является “text/xml”. Несмотря на то, что media-type не оказывает никакого влияния на содержимое самого документа, XSLT-процессоры, используемые на стороне сервера, могут в зависимости от значения этого атрибута изменять MIME-тип исходящих данных при использовании, к примеру, такого протокола, как HTTP.

Атрибут omit-xml-declaration

XML-документы, в принципе, могут быть корректными и без декларации XML. Поэтому XSLT позволяет опускать эту декларацию в выходящем документе, для чего значению атрибута omit-xml-declaration должно быть присвоено “yes”:

<xsl:output omit-xml-declaration="yes"/>

В случае если значение атрибута omit-xml-declaration опущено или не равно “yes”, процессор будет выводить в выходящем документе декларацию XML, которая включает информацию о версии (по умолчанию “1.0”) и кодировке документа (по умолчанию “utf-8” или “utf-16” в зависимости от процессора).

Атрибут standalone

Для того чтобы объявить документ как самостоятельный или несамостоятельный (standalone или non-standalone соответственно), следует использовать атрибут standalone элемента xsl:output. Если этот атрибут будет присутствовать в xsl:output, то процессор включит в декларацию XML объявление standalone с соответствующим значением. Если атрибут standalone не указан, объявление standalone в декларацию XML выходящего документа включено не будет.

Метод вывода “html”

В нынешнем состоянии языки XML и HTML сильно похожи синтаксически, но при этом имеют некоторые довольно весомые различия. Метод вывода “html” используется для того, чтобы выводить документы в формате, который будет понятен большинству существующих на данный момент Web-браузеров.

Одно из основных различий HTML и XML состоит в том, что в XML пустые элементы имеют формат <имя/>, в то время как в HTML тот же элемент был бы выведен, как <имя> — без косой черты. Метод вывода “html” учитывает эти различия и выводит теги пустых элементов HTML без косой черты после имени. В соответствии с технической рекомендацией языка HTML 4.0, пустыми элементами являются area, base, basefont, br, col, frame, hr, img, input, isindex, link, meta и param.

Пример

Листинг 8.53. Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page>
    <title>I'm just a simple page...</title>
    <content>I've got a simple content</content>
</page>

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

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="html"/>
    <xsl:template match="/page">
        <html>
            <head>
                <title>
                    <xsl:value-of select="title"/>
                </title>
            </head>
            <body>
                Welcome!<br/>
                Be our guest! <HR/>
                <xsl:value-of select="content"/>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.55. Выходящий документ

<html>
    <head>
        <meta http-equiv="Content-Type"
            content="text/html; charset=utf-8">
        <title>I'm just a simple page...</title>
    </head>
    <body>
        Welcome!<br>
        Be our guest! <HR>
        I've got a simple content
    </body>
</html>

Как можно заметить, метод вывода “html” распознает элементы HTML вне зависимости от регистра символов — в нашем примере пустой элемент <HR/> был выведен как <HR>, что соответствует синтаксису HTML.

Документы, которые преобразуются в HTML, могут также иметь программы, определенные внутри элемента script или стили, заданные внутри элемента style. В случае если внутри этих элементов оказываются символы, считающиеся в XML специальными — такие как “<”, “&” и так далее, процессор не должен заменять их символьными или встроенными сущностями.

Пример

Предположим, что в преобразуемом документе элемент script определен с использованием специальных символов, которые заменены сущностями:

<script> if (a > b) swap(a, b) </script>

или с использованием секций символьных данных:

<script><![CDATA[ if (a>b) swap(a, b) ]]></script>

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

<script> if (a>b) swap(a, b) </script>

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

Пример

 <P>This >o< is a black hole of this page!</P>

будет выведено как

<P>This >o< is a black hole of this page!</P>

В соответствии со спецификацией, некоторые атрибуты в HTML могут и не иметь значений — как правило, это атрибуты с булевыми значениями, такие, к примеру, как атрибут selected элемента option, присутствие которого в элементе означает то, что опция выбрана, отсутствие — то, что она не выбрана. Для того чтобы получить в выходящем документе

<option selected>

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

<option selected="selected">

то есть присваивать булевому атрибуту значение, равное собственному имени. Такие значения будут выведены в минимизированной форме, как это и требовалось.

HTML и XML также имеют небольшие различия в формате вывода инструкций по обработке. В то время как в XML эти инструкции имеют вид

<?приложение содержимое?>

в HTML инструкции по обработке заканчиваются не “?>”, а просто правой угловой скобкой (“>”):

<?приложение содержимое>

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

<xsl:processing-instruction name="app">content</xsl:processing-instruction>

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

<?app content?>

а при использовании метода HTML

<?app content>

Атрибут version

Атрибут version элемента xsl:output в методе “html” обозначает версию языка HTML, которая должна использоваться в выходящем документе. По умолчанию значением этого атрибута является “4.0”, что означает соответствие выходящего документа спецификации языка HTML версии 4.0. Отметим, что последней версией языка HTML на момент написания этой книги является версия 4.02, однако отличия между этими версиями незначительны.

Атрибут encoding

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

<html> <head>
<meta http-equiv="Content-Type"
    content="text/html; charset=windows-1251">
...

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

Пример

Элемент

<xsl:output encoding="ISO-8859-1"/>

добавит в элемент head выходящего HTML-документа элемент meta в следующем виде:

<meta http-equiv="Content-Type"
    content="text/html; charset=ISO-8859-1">

Таким образом, для определения кодировки выходящего HTML-документа не следует вручную создавать соответствующий элемент meta — нужно просто указать требуемую кодировку в атрибуте encoding элемента xsl:output.

Атрибут indent

XSLT позволяет использовать в HTML документах индентацию точно так же, как мы бы использовали ее в методе “xml”.

Атрибуты doctype-system и doctype-public

Декларация типа документа с внешними системными или публичными идентификаторами может быть использована в HTML точно так же, как в XML. Поскольку в объявлении типа документа после <!DOCTYPE должно стоять имя корневого элемента, при методе вывода “html” этим именем будет “HTML” или “html” в зависимости от регистра символов имени корневого элемента документа.

Атрибут media-type

Атрибут media-type определяет медиа-тип содержимого выходящего документа. Для HTML-документов значением media-type по умолчанию будет “text/html”.

Метод вывода “text”

XSLT позволяет выводить результат преобразования как простой текст. При использовании method="text" результирующее дерево приводится к строке, то есть в этом случае результатом преобразования будет строковое сложение всех текстовых узлов дерева.

Пример

Входящий документ

<?xml version="1.0" encoding="utf-8"?>
<page>
    <title>My heart's in the Highlands</title>
    <content>My heart is not here</content>
</page>

одним и тем же шаблоном:

<xsl:template match="/page">
    <poem title="{title}">
        <xsl:value-of select="title"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="content"/>
    </poem>
</xsl:template>

при использовании метода вывода “xml” будет преобразован к виду

<?xml version="1.0" encoding="utf-8"?>
<poem title="My heart's in the Highlands">
My heart's in the Highlands
My heart is not here
</poem>

а при использовании метода “text” к виду

My heart's in the Highlands
My heart is not here

Атрибут encoding

Атрибут encoding указывает на предпочтительную кодировку вывода текста документа. Значение атрибута encoding по умолчанию зависит от программной платформы, на которой производится преобразование. В большинстве процессоров по умолчанию используются кодировки UTF-8, ASCII и ISO-8859-1.

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

Атрибут media-type

По умолчанию в качестве значения атрибута media-type, используемого для простого текста, указывается “text/plain”. Значение атрибута media-type может быть использовано сервером, преобразующим документ в качестве MIME-типа.

Другие методы вывода

Как уже было сказано раньше, спецификация XSLT позволяет помимо основных методов “xml”, “html” и “text” использовать также и другие методы, реализация которых будет зависеть от производителя того или иного процессора. Кажется вполне логичной и закономерной возможность использования, к примеру, такого метода, как “pdf” для создания документов в Adobe Portable Document Format (переносимом формате документов) или метода “bin” для создания двоичного потока данных. Однако, на данном этапе, процесс сериализации (создания физической сущности из логической модели) пока еще не определен в общем виде для произвольного метода. Возможно, в будущем, по аналогии с объектной моделью документа (DOM) будут созданы схожие интерфейсы для более легкого определения методов сериализации и интеграции преобразований в другие программы, но в настоящее время следует ограничиваться тремя основными методами.

Отметим также, что спецификация языка XSLT определяет функциональность элемента xsl:output как возможную, но не обязательную. Процессоры обязаны манипулировать логическими моделями XML-документов, но при этом они не обязаны поддерживать сериализацию и уметь выводить преобразованный XML-документ как последовательность байт. Конечно же, абсолютное большинство процессоров поддерживает такую возможность, но при всем том она остается не более чем возможностью.

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

Типичным примером такой ситуации может быть использование процессора совместно с другими компонентами, которые обмениваются с процессором документами в виде DOM-структур, но сами загружают и выводят документы. В этом примере компоненты, занимающиеся выводом преобразованного документа, могут спокойным образом игнорировать все то, что было указано в элементе xsl:output или в атрибутах disable-output-escaping других элементов преобразования. Более того, они даже не будут знать, что было там указано, поскольку эти значения не касаются процесса преобразования как такового — они относятся к выводу, контролировать который процессор в данном случае не может.

Отсюда следует однозначный вывод: не нужно чересчур злоупотреблять возможностями xsl:output и disable-output-escaping.

Замена специальных символов

Как мы уже знаем, в XML есть несколько специальных символов, которые, как правило, заменяются процессором при выводе документа на соответствующие символьные или встроенные сущности. К примеру, для того, чтобы вывод был корректным XML-документом, процессор обязан заменять символы “<” и “&” на встроенные (< и &) или символьные (< и &) сущности.

Между тем довольно часто бывает необходимым выводить в выходящем документе символы разметки.

Пример

Пусть входящий документ содержит описание товара, заданное в секции CDATA:

<?xml version="1.0" encoding="utf-8"?>
<product>
    <title>An elephant</title>
    <description><![CDATA[
        This is a <em>big</em> and <b>grey</b> animal!
        ]]></description>
</product>

Если мы будем преобразовывать этот документ с использованием шаблона

<xsl:template match="product">
    <p>
        <xsl:value-of select="title"/>
        <xsl:text> </xsl:text>
        <br/>
        <xsl:value-of select="description"/>
    </p>
</xsl:template>

то в выходящем документе специальные символы будут заменены:

<p>An elephant
<br/>This is a <em>big</em> and <b>grey</b> animal!</p>

Для того чтобы избежать замены, можно воспользоваться атрибутом disable-output-escaping (отменить замену символов) элементов xsl:value-of и xsl:text. Этот атрибут может принимать значения “yes” и “no” (“no” — значение по умолчанию). Значение “yes” означает, что процессор при выводе текста, создаваемого xsl:text или xsl:value-of не должен заменять специальные символы. Если бы в предыдущем примере мы использовали преобразование.

Листинг 8.56. Преобразование, содержащее disable-output-escaping

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="product">
        <p>
            <xsl:value-of select="title"/>
            <xsl:text> </xsl:text>
            <br/>
            <xsl:value-of disable-output-escaping="yes"
                select="description"/>
        </p>
    </xsl:template>
</xsl:stylesheet>

то на выходе мы бы получили документ

<?xml version="1.0" encoding="utf-8"?>
<p>An elephant
<br/>This is a <em>big</em> and <b>grey</b> animal!</p>

Атрибут disable-output-escaping налагает ряд ограничений на использование текстовых узлов, генерируемых элементами xsl:text и xsl:value-of: эти узлы не могут входить в качестве текстового содержимого в узлы атрибутов, комментариев или инструкций по обработке. Кроме того, дерево, содержащее текстовые узлы, для которых была отменена замена специальных символов, не может быть приведено к строке или числу. И в том и в другом случае процессор может либо выдать ошибку преобразования, либо проигнорировать отмену замены специальных символов.

Атрибут disable-output-escaping имеет также и более концептуальное ограничение. Процессор сможет отменить замену символов только в том случае, когда он сам будет контролировать процесс вывода. Как мы уже обсуждали в предыдущем разделе, ситуации, когда процесс вывода не будет выполняться самим процессором, не такая уж и редкость. Поэтому следует использовать disable-output-escaping только в тех случаях, когда другой альтернативы нет или когда имеется полная уверенность, что этот метод будет работать.

Атрибут disable-output-escaping работает с методами вывода “xml” и “html”, но не оказывает никакого влияния на метод “text”, поскольку при этом методе все специальные символы и так выводятся без замены.

Кодировки в XSLT-преобразованиях

Несмотря на то, что в логических деревьях, которыми манипулирует XSLT, текстовые узлы представляются в кодировке Unicode, очень часто в обрабатываемых документах бывает необходимо использовать также другие кодировки. К примеру, большинство русскоязычных документов хранятся в кодировках Windows-1251 и KOI8-R.

Если внимательно присмотреться к преобразованиям, можно заметить, что, как правило, в них участвуют минимум три документа — входящий (преобразовываемый) документ, документ преобразования (преобразующий) и выходящий (преобразованный документ). Соответственно, каждый из них может иметь собственную кодировку.

Кодировка входящего документа указывается в его xml-декларации. Например, документы в кодировке Windows-1251 должны иметь xml-декларацию вида

<?xml version="1.0" encoding="windows-1251"?>

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

<?xml version="1.0" encoding="windows-1251"?>
<страница>
    <содержимое/>
</страница>

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

Пример

Листинг 8.57. Входящий документ

<?xml version="1.0" encoding="windows-1251"?>
<каждый>
    <охотник>
        <желает>
            <знать>
                <где>
                    <сидит>
                        <фазан/>
                    </сидит>
                </где>
            </знать>
        </желает>
    </охотник>
</каждый>

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

<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" encoding="windows-1251"/>
    <xsl:template match="каждый">
        <редкий>
            <xsl:apply-templates/>
        </редкий>
    </xsl:template>
    <xsl:template match="охотник">
        <рыболов>
            <xsl:apply-templates/>
        </рыболов>
    </xsl:template>
    <xsl:template match="желает/знать">
        <может>
            <забыть>
                <xsl:apply-templates/>
            </забыть>
        </может>
    </xsl:template>
    <xsl:template match="где">
        <как>
            <xsl:apply-templates/>
        </как>
    </xsl:template>
    <xsl:template match="сидит">
        <плавает>
            <xsl:apply-templates/>
        </плавает>
    </xsl:template>
    <xsl:template match="фазан">
        <щука>
            <xsl:apply-templates/>
        </щука>
    </xsl:template>
</xsl:stylesheet>

Листинг 8.59. Выходящий документ

<?xml version="1.0" encoding="windows-1251"?>
<редкий>
    <рыболов>
        <может>
            <забыть>
                <как>
                    <плавает>
                        <щука/>
                    </плавает>
                </как>
            </забыть>
        </может>
    </рыболов>
</редкий>

Напомним, что кодировка выходящего документа определяется атрибутом encoding элемента xsl:output и не зависит от кодировок преобразования и обрабатываемых документов. Например, можно легко создать преобразование, которое будет изменять кодировку входящего документа. Это будет идентичное преобразование с элементом xsl:output, определяющим целевой набор символов.

Листинг 8.60. Преобразование, изменяющее кодировку документа на KOI8-R

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output encoding="KOI8-R"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

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

Практически во всех процессорах поддерживаются кодировки UTF-8, US-ASCII и ISO-8859-1, но далеко не все могут работать с Windows-1251 или KOI8-R. Поэтому, создавая документы и преобразования в нестандартных кодировках, мы заведомо ограничиваем переносимость решений. В случаях, когда XML/XSLT приложения создаются под конкретный процессор с заведомо известными возможностями, это не является большой проблемой, однако в тех случаях, когда требуется универсальность или точно не известно, каким процессором будет производиться обработка, единственным выходом будет использовать UTF-8 — как во входящих документах, так и в самих преобразованиях.

Пример XSLT 2.0

Чтобы сгенерировать корректный код XHTML, следует использовать атрибут method="xhtml":

<?xml version="1.0"?>
<!-- output3.xsl -->
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xhtml"
        encoding="ISO-8859-3"
        doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
        doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
    <xsl:template match="/">
        <html>
            <head>
                <title><xsl:value-of select="/list/title"/></title>
            </head>
            <body>
                <h1><xsl:value-of select="/list/title"/></h1>
                <p>
                    <xsl:for-each select="/list/listitem">
                        <xsl:number format="1. "/>
                        <xsl:value-of select="."/>
                        <br/>
                    </xsl:for-each>
                </p>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Результат выглядит так:

<?xml version="1.0" encoding="ISO-8859-3"?>
<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <title>Albums I've bought recently:</title>
    </head>
    <body>
        <h1>Albums I've bought recently:</h1>
        <p>1. The Sacred Art of Dub
            <br></br>2. Only the Poor Man Feel It
            <br></br>3. Excitable Boy
            <br></br>4. Aki Special
            <br></br>5. Combat Rock
            <br></br>6. Talking Timbuktu
            <br></br>7. The Birth of the Cool
            <br></br>
        </p>
    </body>
</html>

Теперь элементы <br> соответствуют требованиям корректного кода XML.

См. также

Ссылки

MDN xsl:output на MDN
MSDN xsl:output на MSDN