Глава 6 Преобразование в XML, HTML, XHTML, RTF

Предположим, web-узел вашей компании использует основанное на XML программное обеспечение фирмы Commerce One, в котором для безопасной коммуникации через Интернет применяется Java Message Service (JMS). Ваша деятельность была настолько успешной, что вы только что поглотили своего конкурента. К сожалению, для своего узла в Интернете ваш бывший конкурент использует другой основанный на XML продукт, RosettaNet. Как вам теперь преобразовать заказ на покупку xCBL Commerce One, написанный на XML, в заказ на покупку RosettaNet, также написанный на XML, но совершенно на другом диалекте?

Разумеется, применить XSLT. Такого рода XML-XML преобразования становятся все более и более распространенными. Все больше компаний применяют JMS для безопасных коммуникаций через Интернет, и поскольку JMS выполняется в Java, будет разумным связать JMS с основанными на Java процессорами XSLT, такими, как Xalan или Saxon.

В этой книге мы уже рассматривали преобразование XML в HTML, XML и простой текст, но в текущей главе сделаем это более подробно. Мы также рассмотрим здесь новый тип преобразования — из XML в JavaScript. В главе 10 мы познакомимся с преобразованиями из XML в базу данных на основе SQL, а в главе 11 — с преобразованиями из XML в XSL-FO.

Основная задача XSLT состоит не просто в замене одного элемента на другой, но в полной реорганизации содержимого XML-документа. Например, вам может потребоваться реорганизовать

planets.xml
в терминах плотности планет при помощи XSLT для создания нового XML-документа:

 

  .983

 Mercury

 .0553

  58.65

 1516

 

 

  .943

  Venus

  .815

  116.75

  3716

 

 

  1

 Earth

 1

 1

 2107

 

Мы рассмотрим преобразование, которое полностью меняет содержимое

planets.xml
, оставляя только небольшой код HTML и код JavaScript для отображения нескольких кнопок в браузере.

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

,
,
и
для создания новых элементов, атрибутов, инструкций обработки и комментариев на этапе выполнения. Хорошее знание этих элементов необходимо при реорганизации содержимого XML.

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

В большей части этой главы исследуются возможности элемента

, с краткого обзора которого я и начну.

Элемент

С элементом

мы впервые познакомились в главе 2 и использовали его, главным образом, для задания типа результирующего документа. Этот тип может задать, например, будет ли процессор XSLT записывать инструкцию обработки XML,
, в начале документа, а также задать тип MIME (такой, как «
text/xml
» или «
text/html
») документов, отправляемых процессором XSLT из web-сервера браузеру. Кроме того, если вы установите выходной тип в HTML, большинство процессоров XSLT смогут распознать, что не всем элементам HTML необходимы закрывающие или открывающие теги и т.п.

В следующем списке перечислены атрибуты

:

cdata-section-elements
(необязательный). Задает имена тех элементов, чье содержимое должно выводиться как разделы
CDATA
. Принимает значения списка
QName
, разделенного символами-разделителями;

doctype-public
(необязательный). Задает открытый идентификатор, который будет использован в объявлении
в выходных данных. Устанавливается в строковое значение;

doctype-system
(необязательный). Задает системный идентификатор, который будет использован в объявлении
в выходных данных. Устанавливается в строковое значение;

encoding
(необязательный). Задает кодировку символов. Устанавливается в строковое значение;

indent
(необязательный). Определяет, будет ли выходной документ выровнен с отражением структуры вложенности. Устанавливается в
yes
или
no
;

media-type
(необязательный). Задает тип MIME вывода. Устанавливается в строковое значение;

method
(необязательный). Задает формат вывода. Принимает значения «
xml
», «
html
», «
text
» или допустимое имя
QName
;

omit-xml-declaration
(необязательный). Определяет, будет ли включено в вывод объявление XML. Устанавливается в «
yes
» или «
no
»;

standalone
(необязательный). Определяет, будет ли включено в вывод отдельное объявление XML, и если да — устанавливает его значение. Устанавливается в
yes
или
no
;

version
(необязательный). Задает версию вывода. Принимает значение допустимого NMToken.

Чаще, всего используется атрибут

method
, поскольку именно он определяет требуемый тип выходного дерева. Официально методом вывода до умолчанию является HTML, при условии, что выполняются все три следующих условия:

• корневой узел результирующего дерева имеет дочерний элемент;

• в названии элемента документа результирующего дерева присутствует часть «

html
» (в любой комбинации верхнего и нижнего регистров) и пустой URI пространства имен;

• все текстовые узлы перед первым дочерним элементом корневого узла содержат только символы-разделители.

Если выполняются все три этих условия, то по умолчанию метод вывода устанавливается в HTML. В ином случае методов вывода по умолчанию является XML.

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

method
— «
html
», «
xml
» и «
text
», и мы познакомимся с ними в следующих разделах.

Метод вывода: HTML

Для метода вывода HTML процессор XSLT должен предпринять определенные действия. Например, для этого метода атрибут

version
определяет версию HTML. Значение по умолчанию — 4.0.

Этот метод не должен добавлять завершающий тег для пустых элементов. (Для HTML 4.0 пустыми элементами являются

,
,
,

,
,
,

,
,
,
,
,
и
.) Метод вывода HTML должен распознавать названия элементов HTML независимо от регистра.

В соответствии с W3C, метод вывода HTML не должен скрывать содержимое элементов

или следующий, использующий раздел CDATA:

должен быть преобразован в:

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

При установке метода вывода в HTML процессор может учесть атрибут выравнивания. Если этот атрибут установлен в

yes
, процессор XSLT может добавить (или удалить) символы-разделители для выравнивания результирующего документа, поскольку это не влияет на отображение документа в браузере. Для метода вывода HTML значением по умолчанию является «yes».

Как вы могли предположить, метод вывода HTML завершает инструкции обработки при помощи

>
, а не
?>
, а также поддерживает отдельные атрибуты, как и HTML. Например, тег

будет преобразован в:

Для этого метода можно установить атрибут

media-type
, значением по умолчанию для которого является «
text/html
». Метод HTML не должен убирать символ &, который появляется в значении атрибута, если сразу за ним следует фигурная скобка. Атрибут
encoding
задает используемую кодировку. Если присутствует элемент
, этот метод вывода должен добавить элемент
<МЕТА>
сразу же после тега
, определяя кодировку символов:

 <МЕТА http-equiv="Content-Type" content="text/html; charset=utf-8">

 .

 .

 .

При помощи атрибутов

doctype-public
или
doctype-system
можно вывести объявление типа документа непосредственно перед первым элементом, как мы увидим при преобразовании XML в XHTML.

Таковы правила вывода HTML. Ниже приведен пример преобразования из XML в HTML с небольшими отклонениями. В этом случае таблица стилей будет фактически генерировать код JavaScript, демонстрируя создание JavaScript при помощи XSLT. В частности, мы прочитаем

planets.xml
и создадим новый документ HTML, отображающий три кнопки — по одной для каждой из трех планет в
planets.xml
. При щелчке на кнопке на странице будет выведена масса соответствующей планеты.

Все, что нам понадобится (листинг 6.1), — это два элемента

: один для прохода в цикле по трем планетам и создания для каждой кнопки HTML; и один для прохода по планетам и создания для каждой функции JavaScript. В качестве имен функций JavaScript я воспользуюсь названием планет; при вызове функция выведет массу соответствующей планеты. Заметьте, что для создания нужного кода JavaScript нужно всего лишь применить элемент
для получения названий и масс планет. Я также применю два новых элемента XSLT,
и
, которые мы рассмотрим позже в этой главе, для создания нового элемента и задания для него набора атрибутов.

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

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

   

   </code></pre></p>
     <p><pre><code>    The Mass Page</code></pre></p>
     <p><pre><code>   

    

   

  

   

    

The Mass Page

   

   

    

   

   

   

    

   

   

 

 


 

  BUTTON

  

 ()

 

Результат, включая элемент

 

 

  

  

The Mass Page

  

  

  

 

  

 

  

  

 

  

 

Как видите, при помощи XSLT я написал код JavaScript для прохода в цикле по планетам. Этот документ HTML показан на рис. 6.1. При щелчке на кнопку выводится масса соответствующей планеты.

Рис. 6.1. Преобразование XML в HTML при помощи JavaScript

Метод вывода: XML

Формально при использовании метода вывода XML процессор XSLT создает хорошо сформированный внешний объект XML, который можно разобрать на общих условиях. Если корневой узел результирующего дерева имеет единственный дочерний узел-элемент и не имеет текстовых дочерних узлов. Тогда объект будет также хорошо сформированным документом XML.

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

version
устанавливает версию XML результата. Заметьте, что если процессор XSLT не поддерживает эту версию XML, он будет использовать ту версию XML, которую поддерживает. По умолчанию установлено значение 1.0.

Атрибут

encoding
устанавливает кодировку для результирующего документа. Процессоры XSLT должны поддерживать, по крайней мере, значения «UTF-8» и «UTF-16». Если процессор XSLT работает с другими значениями и не поддерживает указанную кодировку, он может сгенерировать ошибку. Если он этого не сделает, процессор должен использовать вместо нее UTF-8 иди UTF-16. Процессор XSLT не должен использовать кодировку, которая не была принята консорциумом W3C (см. www.ww3.org/TR/REC-xml). Если никакой атрибут кодировки не указан, по умолчанию процессор XSLT должен выбрать «UTF-8» или «UTF-16».

ОБРАБОТКА НЕИЗВЕСТНЫХ СИМВОЛОВ

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

Как и в случае с методом вывода HTML, если атрибут

indent
установлен в «yes», метод вывода XML может добавить или удалить символы-разделители в результирующее дерево для того, чтобы выровнять результат. Значение по умолчанию — no. Заметьте, что если символы-разделители отбрасываются, информационное множество результирующего XML-документа должно быть таким же, как если бы символы-разделители вообще не добавлялись и не удалялись для выравнивания документа.

ВЫРАВНИВАНИЕ ДОКУМЕНТОВ СО СМЕШАННЫМ СОДЕРЖИМЫМ

Для документов со смешанным содержимым лучше не устанавливать атрибут indent в «yes», поскольку это вносит путаницу в работу процессора XSLT.

При помощи атрибута

cdata-section-elements
можно задать разделенный символами-разделителями список имен элементов, чье содержимое должно трактоваться как разделы
CDATA
. Например, если установить атрибут
cdata-section-elements
в «
DATA
»:

то следующий элемент буквального результата:

<:DOCUMENT>

будет преобразован в:

]]>

Кроме того, метод вывода XML будет выводить в результирующий документ объявление XML, если только атрибут

omit-xml-declaration
не будет установлен в
yes
. Как правило, объявление XML, помещаемое в результирующий документ, обычно включает версию XML (что обязательно) и информацию о кодировке (хотя формально информация о кодировке в документах XML не обязательна). Если задан атрибут
standalone
, результирующий документ должен включать объявление отдельного документа с тем же значением, что и значение у атрибута
standalone
.

При использовании атрибута

doctype-system
процессор создает объявление типа документа непосредственно перед первым элементом. В этом случае имя, следующее за
, будет именем корневого элемента. Заметьте, что если вы также используете атрибут
doctype-public
, процессор XSLT выведет «
PUBLIC
», вслед за ним открытый идентификатор и затем системный идентификатор. Если вы не используете атрибут
doctype-public
, процессор выведет «
SYSTEM
» и вслед за ним системный идентификатор. Теоретически атрибут
doctype-public
должен игнорироваться, если не задан также атрибут
doctype-system
, хотя большинство процессоров, кажется, не следуют этому правилу. Мы увидим, как работать с атрибутами
doctype-public
и
doctype-system
в этой главе при преобразовании XML в XHTML.

Наконец, для метода вывода XML значением по умолчанию для атрибута

media-type
является «
text/xml
».

Вы уже встречали в этой книге многие XML-XML преобразования. Например, преобразование из главы 4 просто копировало один документ XML в другой. Обратите внимание на метод вывода, который установлен в XML:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 

Этот пример был приведен в начале главы, в нем

planets.xml
реорганизован на основе плотности планет:

 

  .983

 Mercury

 .0553

 58.65

 1516

 

 

  .943

 Venus

 .815

 116.75

  3716

 

 

  1

  Earth

 1

 1

 2107

 

Вот таблица стилей (листинг 6.3), создающая это преобразование.

Листинг 6.3. Реорганизация planets.xml на основе плотности

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 


 

 

   

   

   

  

 

 


 

 

  

 

 


 

 

  

 

 


 

 

  

 

 


 

 

  

  

 


 

 


 

 

Следующий пример впервые был приведен в главе 5. В этом случае я только перечислил планеты из

planets.xml
, но в выходном документе я хотел видеть не просто фразу «The first three planets are: Mercury Venus Earth» (первые три планеты: Меркурий Венера Земля), a «The first three planets are: Mercury, Venus, and Earth.». Для этого я применил элементы
:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  </code></pre></p>
     <p><pre><code>   The Planets</code></pre></p>
     <p><pre><code>   

  

    The first three planets are: 

   

 

 


 

 

 . 

 and 

 .

 

И вот результат:

 </code></pre></p>
     <p><pre><code>  The Planets</code></pre></p>
     <p><pre><code> 

 

  The first three planets are: Mercury, Venus, and Earth.

 

Хотя многие книги рассматривают главным образом преобразования из XML в HTML, важно понять, что преобразования XML-XML завоевывают все большую популярность, поэтому на них я также останавливаю ваше внимание.

Метод вывода: текст

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

Значением по умолчанию для атрибута

media-type
является «
text/plain
». Атрибут
encoding
устанавливает кодировку, используемую процессором XSLT для преобразования последовательностей символов в последовательности байтов. Заметьте, что если результирующий документ содержит символ, который не может быть представлен в выходной кодировке, процессор XSLT должен сгенерировать ошибку.

В листинге 6.4

planets.xml
преобразуется в простой текст при помощи метода текстового вывода.

Листинг 6.4. Преобразование в простой текст

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

 's mass is 

 

  Earth masses. Its radius is 

 

  miles. Its day is 

 

  Earth days long.

 

И вот результат — просто чистый текст, никакой разметки, никаких пропущенных символов, никаких инструкций обработки:

Mercury's mass is .0553 Earth masses. Its radius is 1516 miles. Its day is 58.65 Earth days long.

Venus's mass is .815 Earth masses. Its radius is 3716 miles. Its day is 116.75 Earth days long.

Earth's mass is 1 Earth masses. Its radius is 2107 miles. Its day is 1 Earth days long.

С другой стороны, метод текстового вывода предназначен не только для создания простого текста, он также применяется для любых текстовых форматов, отличных от XML и HTML. Как мы видели в главе 2, с его помощью можно создавать форматированные документы в формате Rich Text Format (RTF). Rich Text Format использует встроенные текстовые коды, задающие формат документов, и при помощи метода текстового вывода вы можете самостоятельно поместить эти коды в документы.

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

planets.xml
в
planets.rtf
, используя коды RTF как элементы буквального результата:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 {\rtf1\ansi\deff0{\fonttbl

 {\\fcharset0 Courier New:}}

  \viewkind4\ucl\pard\lang1033\b\ The Planets Table\par

 \b0 Name\tab Mass\tab Rad.\tab Day\par

 

 \par

 }


 

 

 \tab

  

 \tab

  

 \tab

  

  \tab

  \par

 

Результирующий документ RTF,

planets.rtf
, показан на рис. 6.2 в редакторе Microsoft Word 2000.

Рис. 6.2. Файл planets.rtf в Microsoft Word


Заметьте, что методом вывода является текст, а не что-нибудь наподобие «

rtf
»:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 {\rtf1\ansi\deff0{\fonttbl

 {\\fcharset0 Courier New:}}

  \viewkind4\ucl\pard\lang1033\b\ The Planets Table\par

  .

  .

  .

Отметьте также, что я поместил коды RTF сразу же после элемента

, поскольку документы RTF должны с самого начала начинаться с кодов RTF; если бы я начал вставлять коды RTF на следующей строке, как, например:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 {

 \rtf1\ansi\deff0{\fonttbl

 {\\fcharset0 Courier New:}}

  \viewkind4\ucl\pard\lang1033\b\ The Planets Table\par

  .

  .

  .

то выходной файл RTF начинался бы с символа новой строки, что привело бы к ошибке в приложении, работающем с файлом RTF (например, вероятно, Microsoft Word).

Вывод в формате XHTML

W3C представил XHTML как последователя HTML, но ни в XSLT 1.0, ни в рабочем проекте XSLT 1.1 нет никакой специальной поддержки для преобразований из XML в XHTML. Предполагается, что надлежащая поддержка будет включена в XSLT 2.0. Тем не менее, при помощи процессоров XSLT все равно можно создавать документы XHTML.

ПОДРОБНЕЕ О XHTML

Если вы хотите узнать больше о XHTML, обратитесь к источникам: W3C рекомендация XHTML 1.0 по адресу www.w3.org/TR/xhtml1/, а также рекомендация XHTML 1.1 по адресу www.w3.org/TR/xhtml11/.

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

Ниже приведены элементы

, которые следует использовать с тремя типами XHTML 1.0 — строгим (strict), переходным (transitional) и кадровым (frameset):

 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"

 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

А вот элемент

для XHTML 1.1:

 PUBLIC "-//W3C//DTD XHTML 1.1//EN"

 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

ЭЛЕМЕНТЫ И HTML 4.01

Строго говоря, даже документы HTML должны начинаться с элемента . Официально существует три формы HTML 4.01: строгая (strict), переходная (transitional) и кадровая (frameset). Вот полные элементы для этих версий: , и . Если вы генерируете совершенно правильные документы HTML, не забудьте добавить в них этот элемент. Дополнительную информацию можно получить по адресу www.w3.org/TR/html40/struct/global.html.

При установке метода вывода в XML для создания элемента

можно воспользоваться атрибутами
doctype-system
и
doctype-public
элемента
. Вот пример элемента
, создающего элемент
для переходного XHTML 1.0:

 doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

 doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"

 indent="yes"/>

В листинге 6.5 приведена полная таблица стилей

planets.html
, использующая этот элемент
для преобразования
planets.xml
в допустимый документ XHTML.

Листинг 6.5. Преобразование planets.xml в XHTML

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

 doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"

 indent="yes"/>

 

  

  

   </code></pre></p>
     <p><pre><code>   The Planets Table</code></pre></p>
     <p><pre><code>   

   

   

   

   The Planets Table

   

   

    

   

    

    

    

    

   

    
Name Mass Radius Day

   

 

 


 

 

  

   

   

   

 

 


 

 

  

 

 


 

 

  

 

 


 

 

  

 

 

Вот результирующий файл XHTML:

 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

 </code></pre></p>
     <p><pre><code>  The Planets Table</code></pre></p>
     <p><pre><code>  

 

 

  

  The Planets Table

 

  

   

   

   

   

   

  

  

   

   

   

   

   

  

   

   

   

   

   

  

   

   

   

   

  

 
Name Mass Radius Day
Mercury .0553 (Earth = 1) 1516 miles 58.65 days
Venus .815 (Earth = 1) 3716 miles 116.75 days
Earth 1 (Earth = 1) 2107 miles 1 days

 

Полученный документ,

planets.html
, является и хорошо сформированным, и допустимым документом XHTML 1.0 — в соответствии с программой допустимости W3C для HTML и XHTML, расположенной по адресу: http://validator.w3.org/file-upload.html. Заметьте, что, поскольку документы XHTML являются в то же время хорошо сформированными XML-документами, мы воспользовались методом вывода XML, — поэтому преобразование не было слишком сложным; единственной сложностью оказалось создание элемента
.

Изменение структуры документа на основе входных данных

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

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

У вас уже есть небольшой опыт в этой области, поскольку мы работали с шаблонами значений атрибутов в главе 3. Как вы помните, при помощи таких шаблонов можно присвоить атрибуту значение выражения XPath, если заключить это выражение в фигурные скобки, { и }. Например, чтобы установить атрибут

NAME
в строковое значение элемента
, дочернего элемента контекстного узла, это значение можно присвоить так:
NAME={DESCRIPTION}
. Теперь мы можем более подробно рассмотреть всю тему создания новых элементов и атрибутов «с ходу», начав с
.

Элемент : создание новых элементов на этапе выполнения

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

У этого элемента три атрибута:

name
(обязательный). Имя создаваемого элемента. Принимает значение шаблона значений атрибута, возвращающего
QName
;

namespace
(необязательный). URI пространства имен нового элемента. Принимает значение шаблона значений атрибута, возвращающего URI;

use-attribute-sets
(необязательный). Задает наборы атрибутов, содержащие атрибуты этого элемента. Принимает значение списка элементов
QName
, разделенных символами-разделителями.

Элемент

содержит тело шаблона.

Пусть, например, мне нужно хранить названия планет в атрибутах

NAME
, а не в элементе
в
planets.xml
:

 

  .0553

 58.65

 1516

 .983

 43.4

 

 .

 .

 .

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

,
и
:

 

  .0553

  58.65

  1516

  .983

  43.4

 

 .

 .

 .

В этом случае я не знаю имени выходного элемента до времени выполнения, потому и не могу просто применить элемент буквального результата. Я мог бы скомпоновать новый элемент, трактуя его как текст (что и показано в примере ниже, где я вывожу символы, подобные «<», при помощи атрибута

disable-output-escaping
элемента
):

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 


 

  <

 

  >

  

  </

 

  >

 

Но это грубый способ, при котором разметка рассматривается как простой текст. С другой стороны, зная название планеты, я могу создать новый элемент при помощи (листинг 6.6), получив название новой планеты из атрибута

NAME
следующим образом.

Листинг 6.6. Применение

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

  

 

 


 

 

  

 

 

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

 

  .0553

 58.65

 1516

 .983

 43.4

 

 

  .815

 116.75

 3716

 .943

 66.8

 

 

  1

 1

 2107

 1

  128.4

 

Таким способом можно создавать новые элементы и задавать им имя во время преобразования XSLT.

Элемент : создание новых атрибутов

Аналогично тому, как вы можете создавать новые элементы при помощи

и устанавливать имя и содержимое элемента на этапе выполнения, при помощи элемента
это можно делать для атрибутов.

У элемента два атрибута:

name
(обязательный). Имя нового атрибута. Принимает значение шаблона значений атрибута, возвращающего
QName
;

namespace
(необязательный). Пространство имен нового атрибута. Устанавливается в URI.

Этот элемент содержит в себе тело шаблона, которое устанавливает значение атрибута.

В листинге 6.7 я создаю новые элементы

с атрибутами, которые соответствуют различным названиям планет (значения берутся из атрибута
COLOR
исходных элементов
).

Листинг 6.7. Применение

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

   </code></pre></p>
    <p><pre><code>   Planets</code></pre></p>
    <p><pre><code>   

   

   

   

   

 

 


 

 

  

   

   

 

 

Как можно видеть в приведенном ниже результате, я создал новые атрибуты «с ходу», используя названия планет:

<НТМL>

 

 </code></pre></p>
    <p><pre><code>  Planets</code></pre></p>
    <p><pre><code> 

 

 

  

 

  

 

  

 

 

Элемент : создание комментариев

По ходу дела можно также создавать и комментарии при помощи элемента

. Этот элемент не имеет атрибутов и содержит тело шаблона, задающего текст комментария.

В листинге 6.8 я создаю комментарии для замены элементов

; текст комментария включает название планеты.

Листинг 6.8. Применение

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

   </code></pre></p>
    <p><pre><code>    Planets</code></pre></p>
    <p><pre><code>   

   

  

   

  

  

 


 

  This was the  element

 

Вот результат:

 

 </code></pre></p>
    <p><pre><code>  Planets</code></pre></p>
    <p><pre><code> 

 

 

  

 

 

 

Элемент : создание инструкций обработки

При помощи элемента

можно создавать новые инструкции обработки. У этого элемента один атрибут:

name
(обязательный). Задает имя инструкции обработки. Принимает значение шаблона значений атрибута, возвращающего NCName.

В следующем примере я удалил инструкцию

из начала
planets.xml
:

 

 Mercury

 .0553

 58.65

 1516

 .983

 43.4

 

 

  Venus

  .815

 116.75

 3716

 .943

 66.8

 

 .

 .

 .

Для того чтобы снова добавить эту инструкцию обработки, можно применить элемент

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

Листинг 6.9. Применение

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  type="text/xml" href="planets.xsl"

 

 

 


 

  

  

  

 

Вот результат, где инструкция обработки

снова на месте:

 

  Mercury

 .0553

 58.65

 1516

 .983

 43.4

 

 

  Venus

  .815

 116.75

 3716

 .943

  66.8

 

 .

 .

 .

Элемент : создание нескольких выходных документов

В рабочем проекте XSLT 1.1 был представлен новым элемент,

, предназначенный для поддержки нескольких выходных документов, — и, скорее всего, этот элемент будет добавлен в XSLT 2.0. Он имеет следующие атрибуты:

href
(обязательный). Указывает место, в которое должен быть помещен новый документ. Устанавливается в абсолютный или относительный URI, без идентификатора фрагмента;

method
(необязательный). Устанавливает метод вывода, используемый для создания результирующего документа. Устанавливается в «xml», «html», «text» или QName, которое не является NCName;

version
(необязательный). Задает версию выходного документа. Устанавливается в NMTOKEN;

encoding
(необязательный). Задает кодировку выходного документа. Устанавливается в строку;

omit-xml-declaration
(необязательный). Принимает значения «yes» или «no» для того, чтобы пропускать или не пропускать объявление XML;

cdata-section-elements
(необязательный). Определяет имена тех элементов, чье содержимое вы хотите вывести как разделы CDATA. Принимает значение разделенного символами-разделителями списка QName;

doctype-public
(необязательный). Определяет открытый идентификатор, который будет использован в объявлении
вывода. Устанавливается в строковое значение;

doctype-system
(необязательный). Определяет системный идентификатор, который будет использован в объявлении
вывода. Устанавливается в строковое значение;

encoding
(необязательный). Задает кодировку символов. Устанавливается в строковое значение;

indent
(необязательный). Определяет выравнивание вывода для отображения структуры вложенности. Устанавливается в «yes» или «no»;

media-type
(необязательный). Задает тип MIME вывода. Устанавливается в строковое значение;

standalone
(необязательный). Определяет, нужно ли включать в вывод отдельное объявление, и если да, задает его значение. Устанавливается в «yes» или «no».

Этот элемент содержит тело шаблона.

В следующем примере, основанном на упрощенной таблице стилей, я создаю в документе HTML две рамки (frame), и два HTML-документа, которые будут в них отображаться,

frame1.html
и
frame2.html
. Первую рамку и документ, который в ней появится,
frame1.html
, я создам при помощи
следующим образом (заметьте, что здесь я устанавливаю атрибут version в «1.1», поскольку мы используем возможность, входящую только в рабочий проект XSLT 1.1, но «1.1», вероятно, не будет правильным значением атрибута
version
в долгосрочном периоде; если элемент
будет включен в XSLT 2.0, версию следует установить в «2.0»):

 

 </code></pre></p>
    <p><pre><code>  Two Frames</code></pre></p>
    <p><pre><code> 

 

 

  

   

   

    </b></code></pre></p>
    <p><pre><code><b>    Frame 1</b></code></pre></p>
    <p><pre><code><b>    

   

   

   

This is frame 1.

   

   

 

  .

  .

  .

После этого я могу создать вторую рамку и документ для вывода в нее,

frame2.html
(листинг 6.10).

Листинг 6.10. Применение

 

  </code></pre></p>
    <p><pre><code>  Two Frames</code></pre></p>
    <p><pre><code> 

 

 

 

  

   

   </code></pre></p>
    <p><pre><code>     Frame 1</code></pre></p>
    <p><pre><code>    

   

    

    

This is frame 1.

   

  

  


 

  

  

    

    </b></code></pre></p>
    <p><pre><code><b>    Frame 2</b></code></pre></p>
    <p><pre><code><b>    

   

   

    

This is frame 2.

   

   

 

 

ПРИМЕР ТОЛЬКО ДЛЯ XSLT 1.1

Обратите внимание на то, что этот пример предназначен только для рабочего проекта XSLT 1.1. Ни один из известных мне доступных процессоров XSLT пока не обрабатывает элемент .

Элемент : создание объявлений пространств имен

В XSLT 2.0 включен еще один новый элемент:

, позволяющий добавлять в результирующий документ объявления пространств имен. Однако на текущий момент больше об этом элементе ничего не известно, так что я не могу дать здесь более подробную информацию. Следите за web-узлом W3C.

Элемент : создание наборов атрибутов

Иногда при создании нового элемента возникает потребность добавить в него сразу несколько атрибутов. Существует простой способ сделать это при помощи элемента

. У этого элемента два атрибута:

name
(обязательный). Имя набора атрибутов. Устанавливается в
QName
;

use-attribute-sets
(необязательный). Имена других наборов атрибутов, которые вы хотите включить в этот набор. Устанавливается в список
QName
, разделенных символами-разделителями.

Элемент

содержит элементы
, по одному для каждого нового создаваемого атрибута. При использовании
для создания нового набора атрибутов элемента нужно задать имя набору. Затем при создании нового элемента для использования набора атрибутов это имя можно присваивать атрибуту
use-attribute-sets
элементов
,
,
и даже самого элемента
.

Ранее в текущей главе мы уже рассматривали один пример применения наборов атрибутов в JavaScript при создании шаблона. В том примере я при помощи набора атрибутов задавал все атрибуты HTML-кнопок планет и затем создавал их, используя этот набор атрибутов в элементе

:

  

  

   

The Mass Page

  

   

   

   

  

   

  

  

  

 


 BUTTON

 

 ()

В результирующем документе такой набор атрибутов был добавлен каждой кнопке HTML:

<Р>

Листинг 6.11. Применение 

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version=1.0">

 

 

 

  

 

 


 

  

   

 

 


 

  

  

 


Обратите внимание на то, что в результирующем документе каждый элемент

имеет атрибуты
number
и
total
:

 

Mercury .0553 58.65 1516 .983 43.4 

Venus .815 116.75 3716 .943 66.8 

 Earth 1 1 2107 1 128.4 

Пропуск объявления XML и создание фрагментов XML

При знакомстве с XSLT многих смущает объявление XML, которое всегда появляется наверху их результирующих документов, особенно если они не отдают себе отчёт в том, что методом вывода по умолчанию является XML. Разумеется, существует способ избавиться от объявления XML, что может быть полезно при создании хорошо сформированных фрагментов XML, не обязательно являющихся законченными документами. Достаточно только установить атрибут

omit-xml-declaration
элемента в «yes»:
.

В следующем примере я только уберу из документа объявление XML, копируя при этом все остальное. Заметьте, что объявление XML не есть узел, поэтому ничего страшного, если оно будет удовлетворять копирующему шаблону:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 

Эта таблица стилей преобразует

planets.xml
:

 

  Mercury

 .0553

 58.65

 1516

 .983

 43.4

 

 

  Venus

  .815

 116.75

 3716

 .943

 66.8

 

 .

 .

 .

в новую версию без объявления XML:

 

  Mercury

 .0553

 58.65

 1516

 .983

 43.4

 

 

  Venus

  .815

 116.75

 3716

 .943

 66.8

 

 .

 .

 .

Полезно знать об этом при создании фрагментов XML или выполнении другой работы. Тем не менее, заметим, что во всех законченных документах XML — даже написанных самостоятельно при помощи разнообразных приложений XML, таких как WML — в начале обязательно должно быть объявление XML.

Создание уникальных идентификаторов при помощи generate-id

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

generate-id
.

В следующем примере я добавляю составленное из гиперссылок оглавление в

planets.html
. Для создания оглавления я прохожу в цикле по всем планетам при помощи элемента
. На каждом шаге цикла я создаю гиперссылку и при помощи шаблона значений атрибута создаю атрибут
HREF
, который устанавливается в уникальный идентификатор для рассматриваемой планеты. Заметьте, что, несмотря на свое имя, функция
generate-id
создает только строковый идентификатор элемента, она не создает атрибуты ID:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

   </code></pre></p>
    <p><pre><code>   The Planets Table</code></pre></p>
    <p><pre><code>   

   

   

   

   The Planets Table

   

   

   

    

   

    

   

   .

   .

   .

Эта таблица стилей (листинг 6.12) генерирует для каждой планеты идентификатор и создает требуемые гиперссылки. Функция

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

Листинг 6.12. Применение функции generate-id

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

  

   </code></pre></p>
    <p><pre><code>   The Planets Table</code></pre></p>
    <p><pre><code>    

   

   

   

   The Planets Table

   

   

    

    

   

    

   

   

    

    

    

    

    

    

   

   
Name Mass Radius Day

   

 

 


 

 

  

   

  

  

   

   

 

 


 

 

   

 

 


 

 

  

 

 


 

 

  

 

 

Вот как это делается: сейчас я создал гиперссылки с атрибутом HREF, значение которого равно идентификатору элемента

; при помощи этого же идентификатора я сделал каждый элемент
назначением гиперссылки. Когда пользователь щелкает на гиперссылку в оглавлении, браузер прокручивает данные до соответствующей записи планеты в HTML-таблице. (Заметьте, что для того чтобы большинство браузеров осуществляли прокрутку, HTML-таблица должна быть вне пределов экрана.) Каждый процессор XSLT создает свои собственные идентификаторы; ниже приведен результат для процессора Xalan:

 

 </code></pre></p>
    <p><pre><code>  The Planets Table</code></pre></p>
    <p><pre><code>  

 

 

 

  The Planets Table

 

 

  Mercury

  

  <Р>

  <Н2>

  Venus

  

  

  

  Earth

  

  <Р>

  

   

   

   

   

   

  

  

   

   

   

   

   

  

   

   

   

   

   

  

   

   

   

   

   

  
Name Mass Radius Day
Mercury .0553 (Earth = 1) 1516 miles 58.65 days
Venus .815 (Earth = 1) 3716 miles 116.75 days
Earth 1 (Earth = 1) 2107 miles 1 days

 

Результат показан на рис. 6.3 (в том числе — оглавление из гиперссылок). Пользователю достаточно щелкнуть на гиперссылке к соответствующей записи в таблице.

Рис. 6.3. Использование сгенерированных идентификаторов в гиперссылках

Создание разделов CDATA

При преобразованиях XML-XML может потребоваться вывести разделы CDATA. В XSLT это легко осуществимо при помощи атрибута

cdata-section-elements
элемента
. Упомянутый атрибут позволяет указать, содержимое каких элементов следует заключить в раздел CDATA. Последнее может понадобиться, например, при создании элементов сценария, когда браузер требует заключения кода сценария в раздел CDATA.

В следующем примере я поместил содержимое элементов

и
в
planets.xml
в разделы
CDATA
:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 

И вот результат:

 

  

  

 58.65

 1516

 .983

 43.4

 

 

  

 

 116.75

 3716

 .943

 66.8

 

 .

 .

 .

ОБРАБОТКА CDATA В ИСХОДНОМ И РЕЗУЛЬТИРУЮЩЕМ ДОКУМЕНТЕ

Рассмотренная техника создает разделы CDATA результирующего документа, она не рассматривает как CDATA какие-либо данные исходного документа. Например, если вам нужно преобразовать в , поскольку ваш браузер требует, чтобы код сценария заключался в разделы CDATA, процессор XSLT испытает трудности с символом < в «х < у». В этом случае необходимо написать , для того чтобы процессор XSLT сгенерировал .

Установка кодировки символов

Для значительных переработок исходных документов важно знать, что можно устанавливать кодировку символов в результирующих документах при помощи атрибута encoding элемента

. Однако нет гарантии, что ваш процессор XSLT будет поддерживать выбранную кодировку, поскольку процессоры обязаны поддерживать только кодировки UTF-8 и UTF-16. С другой стороны, если вы используете символ, не поддерживаемый в используемой кодировке, процессор XSLT либо выведет символ как ссылку на сущность, либо сгенерирует ошибку.

ЕЩЕ О КОДИРОВКАХ СИМВОЛОВ

Принятые кодировки символов указаны в рекомендации XML 1.0, www.w3.org/TR/REC-xml.

Атрибут

encoding
не обязателен в объявлении XML документа; если он отсутствует, разборщики XML по умолчанию принимают кодировку UTF-8. Если вы хотите явно задать кодировку или использовать другую, ее можно задать следующим образом — там, где я задаю кодировку UTF-16:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

  

 

 

Вот что появится в выходном документе:

 

  Mercury

 .0553

 58.65

 "miles">1516

 .983

  43.4

 

 

  Venus

  .815

 116.75

 3716

 .943

 66.8

 

 .

 .

 .

Режимы: форматирование в зависимости от контекста

В некоторых случаях выбор узлов может требовать буквально мастерства. Например, шаблон с условием выбора «*» выбирает и «PLANET». Если вам нужно обрабатывать элементы

по-другому, чем все остальные элементы, вы можете задать шаблон, выбирающий «
PLANET
»; тогда процессор XSLT определит, что «
PLANET
» ближе к элементу
, чем «*», и воспользуется правилом выбора «
PLANET
». Но не всегда все так просто. Например, вам может быть нужно, чтобы правило «
PLANETS
» выбирало не все, а лишь некоторые элементы
. Один из способов решения этой задачи — воспользоваться режимами (mode).

Для задания режима обработки служит атрибут

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

Рассмотрим пример. Здесь я создал новый режим обработки данных планет «fancy» (красивый), отображающий данные полужирным шрифтом. Но я хочу, чтобы полужирным выделялись только данные Земли, а не других планет. Это может составить проблему: поскольку все данные планет хранятся в одном типе элемента —

, — постольку образец «
PLANET
» выберет их все. Режим решает это затруднение. В частности, если текущая планета — Земля, я могу установить режим обработки в «
fancy
»:

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

   </code></pre></p>
    <p><pre><code>   The Planets Table</code></pre></p>
    <p><pre><code>   

   

   

   

   The Planets Table

   

   

    

    

    

    

    

    

   

   
Name Mass Radius Day

  

  

 


 

 

   

   

   

    

   

   

 

  

   

    

   

   

   

   

 

 

 .

 .

 .

После этого я устанавливаю нужные правила шаблона (листинг 6.13), оба для режима обработки «

fancy
», который выделяет выходные данные полужирным, и не задаю никакого специального режима обработки.

Листинг 6.13. Применение режимов

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

   

   </code></pre></p>
    <p><pre><code>   The Planets Table</code></pre></p>
    <p><pre><code>   

   

   

   

   The Planets Table

   

   

    

    

    

    

    

    

   

   
Name Mass Radius Day

  

  

 


 

 

   

   

   

    

   

   

 

  

   

    

   

   

   

   

 

 


 

  

 


 

 

  

 

 


 

  

   

 

 


 

 

   

 

 


 

  

 


 

 

  

    

   

  

 


 

 

  

   

  

  

 


 

 

  

   

   

 

 

Вот результат. Заметьте, что одни только данные Земли выделены полужирным:

 

 </code></pre></p>
    <p><pre><code>  The Fancy Planets Table</code></pre></p>
    <p><pre><code> 

 

 

 

  The Fancy Planets Table

 

  

   

   

   

   

   

  

  

   

   

   

   

   

  

   

   

   

   

   

  

   

   

   

   

  

  
Name Mass Radius Day
Mercury .0553 (Earth = 1) 1516 miles 58.65 days
Venus .815 (Earth = 1) 3716 miles 116.75 days
Earth 1 (Earth = 1) 2107 miles 1 days

 

Этот документ показан на рис. 6.4.

Рис. 6.4. Применение режимов обработки


Режимы также очень удобны в том случае, когда требуется обработать один и тот же документ более одного раза; классический пример — создание оглавления.

Следующий пример демонстрирует создание оглавления. Я добавил в

planets.xml
оглавление в элементе
(table of contents, оглавление), имеющем три элемента
для каждой из планет. Заметьте, что здесь мне необходимо применить два шаблона, выбирающие элементы
, — один для создания оглавления и еще один для копирования всех элементов
в результирующий документ — я использую режимы для того, чтобы их различать. Начну с установки режима в «
toc
» и применения шаблона, который поддерживает этот режим и создает оглавление:

 xmlns:xsl="http//www.w3.org/1999/XSL/Transform">

 

 

 

   

   

   

  .

  .

  .

  

 


 

 

  

 

 

 .

 .

 .

Затем я применяю общий шаблон без каких-либо режимов обработки ко всем элементам и атрибутам, копируя их в результирующий документ (листинг 6.14).

Листинг 6.14. Создание оглавления

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

 

 

   

   

   

  

 

 


 

 

  

  

 


 

 

  

 

 

И, наконец, результат, выводящий

planets.xml
с оглавлением:

 

  Mercury

 Venus

 Earth

 

 

  Mercury

 .0553

 58.65

 1516

 .983

 43.4
                        
                                                            < Назад
                            
                            

                                                            Далее >
                                                        
                                            
Загрузка...