Перейти к содержанию

xsl:output

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

Синтаксис

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<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.

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

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

Пример

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<HTML>
  <HEAD>
    <TITLE>XSL Transformations (XSLT)</TITLE>
  </HEAD>
  <BODY>
    <H1>
      XSL Transformations (XSLT)
      <BR />
      Version 1.0
    </H1>
  </BODY>
</HTML>

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

1
2
3
4
5
6
7
<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:

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

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

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

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

1
<?xml version="1.0" ?>

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

1
<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 в десятичной системе счисления):

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

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<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. Выходящий документ

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

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

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

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

Атрибут indent

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

1
2
3
4
5
6
7
8
<A>
  <B>
    <C />
  </B>
  <C>
    <B />
  </C>
</A>

или

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<A>
  <B>
    <C />
  </B>
  <C>
    <B>

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

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

Пример

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

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

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

1
2
3
4
5
6
7
8
9
<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. Выходящий документ

1
2
3
4
5
6
7
8
9
<?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. Входящий документ

1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<page>
  <br />
  <br />
</page>

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

1
2
3
4
5
6
7
8
9
<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. Выходящий документ

1
2
3
<?xml version="1.0" encoding="utf-8" ?>
<page>&lt;br/&gt;<br />
</page>

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

Пример

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

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8" ?>
<page>
  <data>]]></data>
  <pre>
    <!-- Comment -->
  </pre>
</page>

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<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. Выходящий документ

1
2
3
4
5
<?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", мы получим в выходящем документе определение типа в виде

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

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

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

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

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

1
2
3
4
5
<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. Выходящий документ

1
2
3
<?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. Входящий документ

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<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. Выходящий документ

1
2
3
4
<?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":

1
<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. Входящий документ

1
2
3
4
5
<?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. Преобразование

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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. Выходящий документ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<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 определен с использованием специальных символов, которые заменены сущностями:

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

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

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

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

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

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

Пример

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

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

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

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

1
    <option selected>

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

1
    <option selected="selected">

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

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

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

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

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

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

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

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

1
<?app content?>

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

1
<?app content>

Атрибут version

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

Атрибут encoding

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

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

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

Пример

Элемент

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

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

1
2
    <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" результирующее дерево приводится к строке, то есть в этом случае результатом преобразования будет строковое сложение всех текстовых узлов дерева.

Пример

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

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

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

1
2
3
4
5
6
7
8
9
<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" будет преобразован к виду

1
2
3
4
5
<?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" к виду

1
2
    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:

1
2
3
4
5
6
7
<?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>

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<xsl:template match="product">
  <p>
    <xsl:value-of select="title" />
    <xsl:text>

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

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

1
2
3
4
5
6
7
8
9
<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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<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>

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?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-декларацию вида

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

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

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

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

Пример

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="windows-1251"?>
<каждый>
    <охотник>
        <желает>
            <знать>
                <где>
                    <сидит>
                        <фазан/>
                    </сидит>
                </где>
            </знать>
        </желает>
    </охотник>
</каждый>

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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. Выходящий документ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?xml version="1.0" encoding="windows-1251"?>
<редкий>
    <рыболов>
        <может>
            <забыть>
                <как>
                    <плавает>
                        <щука/>
                    </плавает>
                </как>
            </забыть>
        </может>
    </рыболов>
</редкий>

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<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":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?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>

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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 />
      2. Only the Poor Man Feel It
      <br />
      3. Excitable Boy
      <br />
      4. Aki Special
      <br />
      5. Combat Rock
      <br />
      6. Talking Timbuktu
      <br />
      7. The Birth of the Cool
      <br />
    </p>
  </body>
</html>

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

Ссылки

Комментарии