Алексей Валиков - Технология XSLT
Типичным примером такой ситуации может быть использование процессора совместно с другими компонентами, которые обмениваются с процессором документами в виде 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">
<xsl:value-of select="title"/><xsl:text>
</xsl:text><br/>
<xsl:value-of select="description"/>
</xsl:template>
то в выходящем документе специальные символы будут заменены:
An elephant
<br/>This is a <em>big</em> and <b>grey</b> animal!
Для того чтобы избежать замены, можно воспользоваться атрибутом 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">
<xsl:value-of select="title"/><xsl:text>
</xsl:text><br/>
<xsl:value-of disable-output-escaping="yes" select="description"/>
</xsl:template>
</xsl:stylesheet>
то на выходе мы бы получили документ
<?xml version="1.0" encoding="utf-8"?>
An elephant
<br/>This is a <em>big</em> and <b>grey</b> animal!
Атрибут 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"/>