• Деревья и узлы
  • Символ-разделитель
  • Модель информационного множества против модели дерева XSLT
  • Работа с элементами XSLT
  • Инструкция обработки <?xsl:stylesheet?>
  • Элемент <xsl:stylesheet>
  • Пространство имен XSL
  • Элементы таблиц стилей высокого уровня
  • Элемент <xsl:template>
  • Тела шаблонов
  • Инструкции XSLT
  • Элементы расширения
  • Элементы буквального результата
  • Совпадающие элементы в шаблонах
  • Элемент <xsl:apply-templates>
  • Доступ к значениям узлов
  • Поддержка XML Base
  • Выбор методов вывода
  • Метод вывода: HTML
  • Метод вывода: XML
  • Метод вывода: текст
  • Упрощенные таблицы стилей
  • Встроенные таблицы стилей
  • Элемент <xsl:include>
  • Элемент <xsl:import>
  • Элемент <xsl:apply-imports>
  • Преобразование документов XML при помощи Internet Explorer
  • Глава 2

    Создание и применение таблиц стилей

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

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

    Деревья и узлы

    При работе с XSLT следует перестать мыслить в терминах документов и начать — в терминах деревьев. Дерево представляет данные в документе в виде множества узлов — элементы, атрибуты, комментарии и т.д. трактуются как узлы — в иерархии, и в XSLT структура дерева соответствует рекомендации XPath W3C (www.w3.org/TR/xpath). В данной главе мы рассмотрим деревья и узлы концептуально, а в главах 3 и 4 я дам формальное введение в XPath и его связь с XSLT. Выражения XPath, записываемые в терминах деревьев и узлов, используются для поиска данных в XML-документах.

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

    Таким образом, с точки зрения XSLT документы представляют собой образованные из узлов деревья; XSLT распознает семь типов узлов:

    • Корневой узел. Это самое начало документа. Этот узел представляет для процессора XSLT весь документ. Важно: не путайте корневой узел с корневым элементом, который также называется элементом документа (подробнее об этом мы поговорим позже в этой главе);

    • Узел атрибута. Содержит значение атрибута после того, как были раскрыты ссылки на сущности и отброшены окружающие символы-разделители;

    • Узел комментария. Содержит текст комментария, не содержащий символов

    <!
    и
    >
    ;

    • Узел элемента. Состоит из части документа, заключенной в открывающий и соответствующий ему завершающий теги, или единственный пустой элемент-тег, например

    <br/>
    ;

    • Узел пространства имен. Представляет объявление пространства имен. Обратите внимание: этот узел добавляется к каждому элементу, к которому применяется это пространство имен;

    • Узел инструкции обработки. Содержит текст инструкции обработки, не содержащий символов

    <?
    и
    ?>
    . Скажем, объявление
    <?xml version="1.0"?>
    не является инструкцией обработки, несмотря на то, что выглядит таковой. Процессор XSLT отбросит его автоматически;

    • Текстовый узел. Текстовые узлы содержат последовательности символов, То есть текст PCDATA. Текстовые узлы по умолчанию в XSLT подвергаются нормализации, то есть смежные текстовые узлы объединяются.

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

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

    <library>
    :

    <?xml version="1.0"?>

    <library>

     <book>

      <title>

       Earthquakes for Lunch

      </title>

      <title>

       Volcanoes for Dinner

      </title>

     </book>

    </library>

    Термин корневой элемент (root element) пришёл из рекомендации XML, и, поскольку его легко спутать с корневым узлом (root node) XSLT, пришедшим из рекомендации XPath, некоторые авторы, пишущие на тему XSLT, называют корневой элемент элементом документа. Очень жаль, что существует такое перекрытие терминов.

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

    В XSLT узлы могут иметь имена — так же, как дочерние узлы (child node) и родительские узлы (parent node). Иными словами, узлы элементов, атрибутов, пространств имен и инструкций обработки могут иметь имена; каждый узел элемента и корневой узел могут иметь дочерние узлы; и все узлы, за исключением корневого, имеют родителей.

    Например, вот как выглядит рассмотренный нами ранее XML-документ в процессоре XSLT в виде дерева, состоящего из узлов:

                                root

                                 |

                        element: <library>

                                 |

                        element: <book>

                                 |

                 |-------------------------------|

                 |                               |

        element: <title>                element: <title>

                 |                               |

    text: "Earthquakes for Lunch" text: "Volcanoes for Dinner"

    Как видим, корневой узел расположен на самом верху дерева, за которым следует узел корневого элемента, ему соответствует элемент

    <library>
    . За ним следует узел
    <book>
    , у которого есть два дочерних узла
    <title>
    . Эти два узла
    <title>
    являются внуками элемента
    <library>
    . Родители, дедушки и прадедушки узла, назад до и включая корневой узел, являются предками (ancestor) элемента. Узлы, производные от узла (дети, внуки, правнуки и т.д.), называются его потомками (descendant). Узлы одного уровня называются братьями (sibling).

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

    ФРАГМЕНТЫ РЕЗУЛЬТИРУЮЩЕГО ДЕРЕВА

    Помимо работы с фрагментами входного дерева, процессоры могут включать в вывод специальный тип данных, в XSLT 1.0 называемый фрагментом результирующего дерева (result tree fragment). Этот тип данных, однако, не был включен в рабочий проект XSLT 1.1 (см. главу 7), поэтому он, скорее всего, не будет входить в состав XSLT 2.0.

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

    Символ-разделитель

    Пример XML-документа, с которым мы до сих пор работали, выровнен так, чтобы показать иерархическую структуру его элементов:

    <?xml version="1.0"?>

     <library>

      <book>

       <title>

        Earthquakes for Lunch

       </title>

       <title>

        Volcanoes for Dinner

       </title>

     </book>

    </library>

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

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

    <?xml version="1.0"?>

    <library>

    .<book>

    ..<title>

    ...Earthquakes for Lunch

    ..</title>

    ..<title>

    ...Volcanoes for Dinner

    ..</title>

    .</book>

    </library>

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

    <book>
    , один после элемента
    <book>
    , и точно так же один перед элементом
    <title>
    , один после и один между элементами:

                                          root

                                            |

                                   element: <library>

                                            |

                        |-------------------|------------|

                        |                   |            |

                  text: whitespace element: <book> text: whitespace

                                            |

          |-------------------|-------------|-------------------|-------------|

          |                   |             |                   |             |

    text: whitespace element: <title> text: whitespace element: <title> text: whitespace

                              |                                 |

                 text: "Earthquakes for Lunch"   text: "Volcanoes for Dinner"

    Такие узлы-разделители, как эти, представляют собой текстовые узлы, не содержащие ничего, кроме символа-разделителя. Поскольку процессоры XSLT по умолчанию сохраняют эти разделители, вас не должно удивлять их появление в результирующих документах. Такие дополнительные разделители обычно не представляют проблемы в документах HTML, XML и XHTML, и здесь в тексте результирующих документов я их не отображаю — для того, чтобы правильно показать выравниванием структуру документа. Мы рассмотрим, как процессоры XSLT могут удалять узлы-разделители из документов, а также как процессоры могут выравнивать результирующие документы. Заметьте, что текстовые узлы, содержащие символы, отличные от символов-разделителей, не считаются узлами-разделителями, поэтому они никогда не будут удалены из документов.

    Следует отметить еще один момент: сами атрибуты трактуются как узлы. Хотя узлы-атрибуты не считаются дочерними узлами тех элементов, в которых они появляются, элемент считается их родительским узлом. (В этом отличие данной модели от модели XML DOM, в которой атрибуты не являются детьми и не имеют родителей.) Если я добавлю атрибут в такой элемент:

    <?xml version="1.0"?>

    <library>

     <book>

      <title>

       Earthquakes for Lunch

      </title>

      <title pub_date="2001">

       Volcanoes for Dinner

      </title>

     </book>

    </library>

    то в дереве документа он отобразится следующим образом:

                                        root

                                          |

                                   element: <library>

                                          |

                      |-------------------|------------|

                      |                   |            |

                  text: whitespace element: <book> text: whitespace

                                          |

        |-------------------|-------------|-------------------|-------------|

        |                   |             |                   |             |

    text: whitespace element: <title> text: whitespace element: <title> text: whitespace

                            |                                 |

           text: Earthquakes for Lunch        |--------------------------|

                                              |                          |

                                text: Volcanoes for Dinner      attribute: pub_date="2001"

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

    • Имя. Имя узла;

    • Строка-значение. Текст узла;

    • Базовый URI. Базовый URI узла (XML-вариант URL);

    • Дети. Список дочерних узлов; ноль, если детей нет;

    • Родитель. Узел-родитель данного узла;

    • Имеет атрибут. Определяет атрибуты узла элемента, если таковые имеются;

    • Имеет пространство имен. Определяет узлы пространства имен узла-элемента.

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

    Модель информационного множества против модели дерева XSLT

    Разборщики XML передают только определенную информацию: как задается основной спецификацией информационного множества (Information Set) XML — которую можно найти по адресу www.w3.org/TR/xml-infoset, в то время как процессоры XSLT придерживаются модели дерева XSLT. Эти модели, а также элементы, считающиеся в них важными, различны, что может привести к проблемам.

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

    С другой стороны, разборщики XML могут удалить из XML-документов комментарии, о чем вам следует знать, так как в модели XSLT комментарии включаются. 

    Кроме того, информация об объявлениях DTD не передается от разборщика XML в процессор XSLT (возможно, потому, что W3C планирует более широко использовать схемы XML в XSLT 2.0, хотя пока еще нет официального механизма связывания схем XML с документами XML). Как правило, это не образует проблемы, поскольку проверка документа XML входит в задачи разборщика XML, за исключением одного случая: когда атрибут объявлен с типом ID. В XML с типом ID можно объявить атрибут с любым именем, поэтому процессор XSLT не знает, какие атрибуты принадлежат к этому типу, если только у процессора нет доступа к DTD. Это важно при использовании таблиц стилей, встроенных в документы XML, поскольку в этом случае процессор XSLT должен быть способен распознать, в каком элементе документа содержится таблица стилей, нужная для преобразования документа. В этом случае некоторые процессоры XSLT, например, Saxon, идут дальше рекомендации XSLT и проверяют DTD, если они есть, чтобы узнать, какие атрибуты принадлежат к типу ID.

    Еще несколько моментов могут представлять для вас интерес. Например, модель обработки XSLT открывает доступ к префиксам пространств имен во входном дереве, но предоставляет очень небольшие возможности управления ими в выходном дереве, где они обрабатываются автоматически. К тому же, в модели обработки XSLT для каждого узла в дереве определяется базовый URI, представляющий собой URI внешней сущности, от которой был произведен узел. (В рабочем проекте XSLT 1.1 эти возможности были расширены для поддержки спецификации XML Base, как вы увидите ближе к концу этой главы.) Однако в информационном множестве XML базовые URI считаются второстепенными, а это означает, что разборщик XML может не передать эту информацию в процессор XSL.

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

    Работа с элементами XSLT

    Для того чтобы создавать таблицы стилей XSLT, вы должны хорошо знать элементы XSLT, такие как

    <xsl:template>
    и
    <xsl:stylesheet>
    . Эти элементы поддерживают большое число атрибутов, и W3C выработал ряд формальных определений типов данных, которые можно присваивать этим атрибутам. Вот ряд определений XSLT; их необходимо знать:

    • 

    NCNameChar
    . Буква, цифра, точка, дефис или символ подчеркивания;

    • 

    NCName
    . Буква или символ подчеркивания, за которым (не обязательно) следуют данные типа
    NCNameChars
    . То есть это имя XML, не содержащее двоеточий (определение имен XML приводится в главе 1); 

    • 

    QName
    . Полностью определенное (qualified) имя. Оно формируется из префикса (должен принадлежать к типу
    NCName
    ), за которым следуют двоеточие и локальная часть (которая также должна быть типа
    NCName
    );

    • 

    NameTest
    . Имя (например, «book») или обобщенное имя с символами подстановки (как, например, «book*» или «*»).

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

    <?xsl:stylesheet?>
    .

    Инструкция обработки <?xsl:stylesheet?>

    Когда у нас есть таблица стилей XSL, которую нужно применить к документу XML, требуется каким-то образом связать эту таблицу стилей с документом, — для чего часто используется инструкция обработки

    <?xsl:stylesheet?>
    . У этой инструкции есть несколько возможных атрибутов:

    • 

    href
    (обязательный). URI таблицы стилей. Может быть полный URI, либо фрагмент из
    #new_style
    . Устанавливается в URI;

    • 

    type
    (обязательный). Тип MIME таблицы стилей. Обычно «text/xml» или «application/xml». Для Internet Explorer используйте «text/xsl». Устанавливается в допустимый тип MIME;

    • 

    title
    (необязательный). Заголовок позволяет различить несколько различных элементов
    <?xsl:stylesheet?>
    . Некоторые разборщики XML позволяют задать, какой из них использовать. Устанавливается в строковое значение;

    • 

    media
    (необязательный). Описание средств вывода, например «print» или «aural» (звуковой). Устанавливается в одно из значений, перечисленных в спецификации W3C HTML 4.0;

    • 

    charset
    (необязательный). Устанавливает кодировку символов. Заметьте, что таблицы стилей XSLT устанавливают свои собственные кодировки, поскольку они являются документами XML, так что практической пользы этот атрибут не имеет. Устанавливается в кодировку символов — например в «UTF-8»;

    • 

    alternate
    (необязательный). Принимает либо значение «yes» (да), которое является признаком альтернативной таблицы стилей, либо «no» (нет), означающее предпочитаемую таблицу стилей.

    Инструкция обработки

    <?xsl:stylesheet?>
    добавляется в документ XML, а не в таблицу стилей, и указывает процессору XSLT, какую таблицу стилей применять к данному документу.

    На практике

    <?xsl:stylesheet?>
    используется главным образом с браузерами, поскольку для отдельных процессоров таблица стилей, как правило, задается непосредственно — как, например, при использовании процессора XSLT Oracle:

    C:\planets>java oracle.xml.parser.v2.oraxsl planets.xml planets.xsi planets.html
     

    Возможно, вас это удивит, но

    <?xsl:stylesheet?>
    не является частью рекомендации XSLT. У этой инструкции обработки существует своя собственная рекомендация только для нее одной, которую можно найти по адресу www.w3c.org/TR/xml-stylesheet. Помимо прочего, это означает, что процессоры XSLT не обязаны поддерживать данную инструкцию обработки, и большинство отдельных процессоров не поддерживают ее.

    Ниже приведен пример. В главе 1 мы рассмотрели файл

    planets.xml
    — хорошо сформированный документ XML, содержащий данные о трех планетах: Меркурии, Венере и Земле. Можно применить инструкцию обработки
    <?xml-stylesheet?>
    к
    planets.xml
    для задания используемой таблицы стилей XSLT. В инструкции следует установить тип атрибута в «text/xml» (W3C также позволяет «application/xml», a Internet Explorer требует «text/xsl») и атрибут href — в URI таблицы стилей XSLT, например
    planets.xsl
    :

    Листинг 2.1. planets.xml

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xml" href="planets.xsl"?>

    <PLANETS>

     <PLANET>

      <NAME>Mercury</NAME>

      <MASS UNITS="(Earth = 1)">.0553</MASS>

      <DAY UNITS="days">58.65</DAY>

      <RADIUS UNITS="miles">1516</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.983</DENSITY>

      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Venus</NAME>

      <MASS UNITS="(Earth = 1)">.815</MASS>

      <DAY UNITS="days">116.75</DAY>

      <RADIUS UNITS="miles">3716</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.943</DENSITY>

      <DISTANCE UNITS="million miles">66.8</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

     </PLANET>

    </PLANETS>

    Вот как следует работать с элементом

    <?xml-stylesheet?>
    ; теперь можно начинать писать саму таблицу стилей. Я сделаю это, создав файл
    planets.xsl
    .

    Элемент <xsl:stylesheet>

    Таблицы стилей XSL начинаются с объявления XML, так как они являются хорошо сформированными документами XML, — поэтому

    planets.xsl
    начинается с такого же объявления:

    <?xml version="1.0"?>

    .

    .

    .

    Однако объявление XML немедленно исключается процессором XSLT, и мы не будем на нем останавливаться в нашем обсуждении XSLT. Первый только XSL-элемент таблицы стилей XSL — это элемент

    <xsl:stylesheet>
    (не путайте его с инструкцией обработки
    <?xml-stylesheet?>
    из XML документа). Встречались и возражения против такого названия элемента: обычно он используется в преобразованиях XSLT, поэтому W3C позволяет в то же время ссылаться на этот элемент как на
    <xsl:transform>
    .

    Вот пример использования этого элемента:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     .

     .

     .

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

    <xsl:stylesheet>
    :

    • 

    id
    (необязательный). Идентифицирует таблицу стилей. Устанавливается в имя XML;

    • 

    version
    (обязательный). Определяет версию XSLT, необходимую для работы с таблицей стилей. Сейчас это значение обычно равно «1.0». Хотя можно установить это значение и в «1.1»; так как XSLT 1.1 не выйдет из стадии рабочего проекта, это значение, вероятно, не будет «корректным» значением с точки зрения W3C;

    • 

    extension-element-prefixes
    (необязательный). Задает расширения в таблице стилей, используемые для идентификации элементов расширения. Принимает значение списка имен
    NCName
    , разделенных символами-разделителями;

    • 

    exclude-result-prefixes
    (необязательный). Задает пространства имен таблицы стилей, которые не будут копироваться в выходные данные (если только они явно не используются в выходном документе). Принимает значение списка имен NCName, разделенных символами-разделителями.

    Содержимое этого элемента может содержать любой из следующих элементов XSL высокого уровня:

    <xsl:attribute-set>
    ,
    <xsl:decimal-format>
    ,
    <xsl:import>
    ,
    <xsl:include>
    ,
    <xsl:key>
    ,
    <xsl:namespace-alias>
    ,
    <xsl:output>
    ,
    <xsl:param>
    ,
    <xsl:preserve-space>
    ,
    <xsl:strip-space>
    ,
    <xsl:template>
    или
    <xsl:variable>
    . XSLT добавляет к списку
    <xsl:script>
    .

    Заметьте, что атрибут

    id
    этого элемента можно использовать в том случае, когда требуется сослаться на определенную таблицу стилей (заметьте также, что в этом случае необходим процессор XSLT, который умеет читать объявления DTD или схемы XML).

    Атрибут задания версии обязателен, в данный момент его можно установить в «1.0». Можно также установить его в «1.1», определяя рабочий проект XSLT 1.1; однако, так как XSLT 1.1 не собирается выходить из стадии рабочего проекта, значение «1.1», скорее всего, не будет считаться корректным значением этого атрибута в долгосрочной перспективе. Везде в книге я буду устанавливать этот атрибут в значение «1.0», поскольку это текущая рекомендация XSLT W3C, а версия 1.1, видимо, останется только на стадии рабочего проекта. Как говорилось в главе 1, W3C также выпустил требования для XSLT 2.0, которая и будет следующей версией.

    ПРОЦЕССОРЫ XSLT И СОВМЕСТИМОСТЬ ВПЕРЕД

    Если процессор XSLT не распознает версию XSLT, то, в соответствии с утверждениями W3C, процессор должен считать, что все новые элементы входят в новую версию XSLT, и не завершать работу, — это W3C называет совместимостью вперед (forward compatibility). Все нераспознанные элементы не должны отвергаться процессором, если только таблица стилей не попытается создать экземпляр этого элемента и не найдет дочернего элемента <xsl:fallback> (см. главу 5). Таким образом, вы можете установить версию XSLT в 2.0 даже в процессорах XSLT, написанных для XSLT 1.0, и это не приведет к проблемам, если вы не будете использовать возможности, существующие только в XSLT 2.0. (Исключением является MSXML3, который в данный момент генерирует ошибки, если установить значение версии, отличное от 1.0.)

    Пространство имен XSL

    Заметьте, что элементы XSLT, такие как

    <xsl:stylesheet>
    , используют префикс пространства имен (namespace)
    xsl
    , который теперь, после стандартизации XSLT, всегда установлен в «http://www.w3.org/1999/XSL/Transform». Это пространство имен обычно устанавливается с атрибутом
    xmlns
    (это не атрибут XSL, а, скорее, атрибут любого элемента XML) в корневом элементе таблицы стилей,
    <xsl:stylesheet>
    :

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

     .

     .

     .

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

    <stylesheet>
    — это не создает проблемы, поскольку новый элемент не будет конфликтовать с элементом XSL
    <xsl:stylesheet>
    .

    В таблицах стилей для элементов XSLT обычно используется префикс пространства имен

    xsl
    . Формально можно использовать для элементов XSLT любой префикс пространства имен (или даже вообще никакого), но практически повсюду применяется
    xsl
    , поскольку это пространство имен фигурирует в рекомендации XSLT.

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

    <xsl:stylesheet>
    . Следовательно, надо начинать таблицу стилей XSLT с элемента
    <xsl:stylesheet>
    . (Есть одно исключение: в «упрощенных» таблицах стилей этот элемент опускается, как мы увидим позже в этой главе.)

    Как и любое другое приложение XML, XSLT имеет хорошо разработанный набор правил допустимости таблицы стилей XSLT. W3C даже определил для XSLT псевдо-DTD, где перечислены все правила синтаксиса, — эти объявления DTD приведены в приложении А, которое послужит вам хорошим справочником в случае затруднений с синтаксисом XSLT. Как показано в приложении А, элемент

    <xsl:stylesheet>
    может содержать несколько других элементов XSLT, называемых элементами верхнего уровня.

    ОБРАБОТКА ПРОСТРАНСТВ ИМЕН ПО УМОЛЧАНИЮ

    Работа с пространствами имен может оказаться не слишком простой. Например, иногда присваивают пространство имен по умолчанию всему элементу <xsl:stylesheet>, как в <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="mydefault">, ожидая, что <xsl:template match="mysymbol"> выберет mysymbol в пространстве имен "mydefault" исходного документа. Однако это не будет работать. Обработка пространств имен по умолчанию, как в таком случае, — одна из проблем, которую призван решить XSLT 2.0.

    Элементы таблиц стилей высокого уровня

    В XSL определен ряд элементов высокого уровня, которые могут быть прямыми дочерними элементами

    <xsl:stylesheet>
    :

    <xsl:attribute-set>
    ;

    <xst:decimal-format>
    ;

    <xsl:import>
    ;

    <xsl:include>
    ;

    <xsl:key>
    ;

    <xsl:namespace-alias>
    ;

    <xsl:output>
    ;

    <xsl:param>
    ;

    <xsl:preserve-space>
    ;

    <xsl:strip-space>
    ;

    <xsl:template>
    ;

    <xsl:variable>
    .

    Рабочий проект XSLT 1.1 добавляет еще один элемент высокого уровня:

    <xsl:script>
     

    В книге мы поработаем со всеми этими официальными элементами XSLT высокого уровня.

    Заметьте, что, в дополнение ко всем элементам высокого уровня, вы можете также повсюду использовать обычные комментарии XML, поскольку таблицы стилей XSLT являются также документами XML:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <!-- Этот шаблон содержит все элементы PLANETS -->

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

       .

       .

       .

    В дополнение к официальным элементам высокого уровня, некоторые процессоры XSLT определяют свои собственные элементы высокого уровня, использующие пространства имен, отличающиеся от пространства имен XSL. Функциональность таких элементов полностью определяется разработчиком процессора XSLT.

    Вы также можете определять собственные элементы высокого уровня, называемые «элементами высокого уровня, определенными пользователем». Эти элементы должны иметь пространство имен, отличное от XSL и элементов, определенных разработчиком процессора. Процессор XSLT игнорирует определенные пользователем элементы высокого уровня; но, поскольку вы способны сами получить доступ ко всему документу при помощи функции документа (как мы увидим в главе 8), вы можете самостоятельно работать с этими элементами.

    Из всех элементов высокого уровня самым популярным является элемент

    <xsl:template>
    :

    <?xml version="1.0">

     <xsl:stylesheet version="1.0"

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

     <xsl:template>

      .

      .

      .

     </xsl:template>

     .

     .

     .

    Создание шаблонов и работа с ними — суть XSLT, и сейчас мы рассмотрим этот элемент, продолжая создавать таблицу

    planets.xsl
    .

    Элемент <xsl:template>

    Шаблоны XSL позволяют задать способ выполнения вашего преобразования. Каждый элемент

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

    • 

    match
    (необязательный). Задает шаблон, выбирающий обрабатываемые узлы. Устанавливается в допустимый шаблон;

    • 

    name
    (необязательный). Содержит имя шаблона, что разрешает его вызов. Если вы не используете этот атрибут, вы должны использовать атрибут
    match
    . Принимает значение типа
    QName
    ;

    • 

    priority
    (необязательный). Положительное или отрицательное целое или действительное число, задающее приоритет шаблона. Используется, когда один и тот же узел удовлетворяет нескольким шаблонам. Устанавливается в число;

    • 

    mode
    (необязательный). Если вы применяете
    <xsl:apply-templates>
    к множеству узлов, будут использоваться только шаблоны с совпадающим режимом (mode). Принимает значение типа
    QName
    .

    Каждый такой элемент

    <xsl:template>
    называется правилом (rule). В общем случае элемент
    <xsl:template>
    может содержать ноль или более элементов
    <xsl:param>
    (как мы увидим в главе 9), за которыми следует тело шаблона, задающего способ осуществления преобразования.

    Тела шаблонов

    Шаблоны формируются по жестко заданным правилам. Они способны содержать элементы

    <xsl:param>
    , за которыми следует тело шаблона; в последнем могут содержаться данные
    PCDATA
    , инструкции XSLT, элементы расширения и элементы буквального результата.

    Инструкции XSLT

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

    <xsl:apply-imports>
    ;

    <xsl:apply-templates>
    ;

    <xsl:attribute>
    ;

    <xsl:call-template>
    ;

    <xsl:choose>
    ;

    <xsl:comment>
    ;

    <xsl:copy>
    ;

    <xsl:copy-of>
    ;

    <xsl:element>
    ;

    <xsl:fallback>
    ;

    <xsl:for-each>
    ;

    <xsl:if>
    ;

    <xsl:message>
    ;

    <xsl:number>
    ;

    <xsl:processing-instruction>
    ;

    <xsl:text>
    ;

    <xsl:value-of>
    ;

    <xsl:variable>
    .

    В теле шаблона больше никакие элементы XSLT непосредственно появиться не могут. Как вы увидите в главе 9, элемент

    <xsl:param>
    может появиться в шаблоне перед телом, но он не называется инструкцией XSLT. В шаблонах могут также появляться и другие элементы XSLT, такие как
    <xsl:sort>
    ,
    <xsl:otherwise>
    и
    <xsl:with-param>
    , но только в определенных местах, поэтому W3C не называет их инструкциями. Далее в книге мы рассмотрим, как использовать каждую из этих инструкций.

    Элементы расширения

    Элементы расширения рассматриваются в главе 5; эти элементы, расширяющие XSLT, определяются пользователем или процессором XSLT. Во многих процессорах XSLT были определены собственные расширения — и это стало одной из причин, по которым W3C представил рабочий проект XSLT 1.1, где механизм расширений был более регламентирован. Вероятно, эта функциональность будет включена в XSLT 2.0.

    Элементы буквального результата

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

    Например, в следующем теле шаблона элемент

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

    <xsl:template match="RADIUS">

     <TD>RADIUS</TD>

    </xsl:template>

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

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

    version
     можно указать, что все элементы XSLT внутри элемента буквального результата должны быть элементами XSLT версии 1.0:

    <xsl:template match="RADIUS">

     <TD xsl:version="1.0">RADIUS</TD>

    </xsl:template>

    В следующем списке перечислены все возможные атрибуты элемента буквального результата:

    • Attribute Value Templates, шаблон значений атрибута (необязательный). Любые выражения XPath в фигурных скобках вычисляются, и результат в виде строкового значения копируется в атрибут в результирующем дереве. Устанавливается в шаблон значений атрибута (см. главу 3);

    • 

    xsl:exclude-result-prefixes
    (необязательный). Определяет, какие пространства имен не будут скопированы в результирующее дерево. Принимает значения списка префиксов пространств имен, разделенных символами- разделителями;

    • 

    xsl:extension-element-prefixes
    (необязательный). Заставляет процессор XSLT трактовать дочерние элементы элемента буквального результата в перечисленных пространствах имен как элементы расширения, а не элементы буквального результата;

    • 

    xsl:use-attribute-sets
    (необязательный). Атрибуты в перечисленных наборах атрибутов добавляются в элемент буквального результата и копируются в результирующее дерево. Принимает значение списка
    QName
    , идентифицирующих поименованные элементы
    <xsl:attribute-set>
    ;

    • 

    xsl:version
    (необязательный). Устанавливает версию элементов XSL в элементе буквального результата. Принимает численное значение.

    Теперь можно начать работать с этой информацией.

    Совпадающие элементы в шаблонах

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

    match
    элемента
    <xsl:template>
    в образец (pattern), определяющий имя узла или узлов, с которыми вы хотите работать. В главе 3, посвященной шаблонам, будет показано, как создавать образцы. Например, образец «/» соответствует корневому узлу; образец «*» задает любой узел элемента; образцу «PLANET» удовлетворяют все узлы элемента
    <PLANET>
    и т.д.

    Для начала я создал короткий пример, заменяющий корневой узел, — а следовательно, и весь документ — на HTML-странице. Первое, что я сделал, — создал шаблон с элементом

    <xsl:template>
    , установив атрибут
    match
    в образец для совпадения

    <?xml version="1.0">

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/">

     .

     .

     .

     </xsl:template>

    </xsl:stylesheet>

    Когда устанавливается соответствие с корневым узлом, шаблон применяется к самому узлу. В данном случае (листинг 2.2) я хочу заменить корневой узел документом HTML, поэтому я только включу этот документ HTML непосредственно в качестве содержимого элемента

    <xsl:template>
    .

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

    <?xml version="1..0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/">

      <HTML>

       <HEAD>

        <TITLE>

         A trivial transformation

        </TITLE>

       </HEAD>

       <BODY>

        This transformation has replaced the entire document.

       </BODY>

      </HTML>

     </xsl:template>

    </xsl:stylesheet>

    Результат: при помощи элемента

    <xsl:template>
    я установил правило в таблице стилей. Когда процессор XSL считывает документ, первым узлом является корневой узел. Это правило находит данный корневой узел, и от того процессор XSL копирует литералы в результирующее дерево, что даст нам HTML doc и заменит его документом HTML, генерируя следующий результат:

    <HTML>

     <HEAD>

      <TITLE>

       A trivial transformation

      </TITLE>

     </HEAD>

     <BODY>

      This transformation has replaced the entire document.

     </BODY>

    </HTML>

    Рассмотренный пример иллюстрирует первое, устаревшее преобразование. Была создана простая таблица стилей с единственным элементом

    <xsl:template>
    , который содержит только элемент буквального результата. Все, что сделано в примере, — замена всего документа XML на документ HTML, что не очень впечатляет. Далее мы увидим, как работает рекурсивная обработка с использованием элемента
    <xsl:apply-templates>

    Элемент <xsl:apply-templates>

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

    <xsl:apply-templates>
    .

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

    • 

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

    • 

    mode
    (необязательный). Устанавливает режим обработки. К этому узлу применяются правила шаблона с режимом выбора. Принимает значение типа
    QName
    .

    Элемент

    <xsl:apply-templates>
    может содержать ноль или более элементов
    <xsl:sort>
    , или ноль или более элементов
    <xsl:with-param>
    .

    В следующем примере шаблон ищет корневой узел и замещает его элементом буквального результата <HTML>:

    <?xml version="1.0">

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/">

      <HTML>

      </HTML>

     </xsl:template>

     .

     .

     .

    С другой стороны, мы только нашли корневой узел, а дерево данных planets.xml имеет ряд узлов под корневым узлом:

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xml" href="planets.xsl"?>

    <PLANETS>

     <PLANET>

      <NAME>Mercury</NAME>

      <MASS UNITS="(Earth = 1)">.0553</MASS>

      <DAY UNITS="days">58.65</DAY>

      <RADIUS UNITS="miles">1516</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.983</DENSITY>

      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--B перигелии-->

     </PLANET>

     .

     .

     .

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

    <xsl:apply-templates>
    , добавив этот элемент следующим образом:

    <?xml version="1.0">

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/">

      <HTML>

       <xsl:apply-templates/>

      </HTML>

     </xsl:template>

     .

     .

     .

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

    <PLANET>
    на
    <P>Planet</P>
    . Элементы
    <PLANET>
    — дочерние узлы элемента
    <PLANETS>
    , поэтому сначала я добавил новый шаблон для
    <PLANETS>
    , что говорит процессору о том, что следует продолжать поиск дочерних узлов:

    <?xml version="1.0">

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


     <xsl:template match="/">

      <HTML>

       <xsl:apply-templates/>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANETS">

      <xsl:apply-templates/>

     </xsl:template>

     .

     .

     .

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

    <PLANET>
    . В этом случае я просто заменю каждый элемент
    <PLANET>
    элементом буквального результата
    <P>Planet</P>
    (листинг 2.3).

    Листинг 2.3. Использование <xsl:apply-templates/>

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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


     <xsl:template match="/">

      <HTML>

       <xsl:apply-templates/>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANETS">

      <xsl:apply-templates/>

     </xsl:template>


     <xsl:template match="PLANET">

      <P>

       Planet

      </P>

     </xsl:template>

    </xsl:stylesheet>

    Вот результат применения этой таблицы стилей:

    <HTML>

     <Р>

      Planet

     </Р>

     <Р>

      Planet

     </Р>

     <P>

      Planet

     </Р>

    </HTML>

    Как видите, от элемента

    <PLANETS>
    ничего не осталось. Все, что осталось, — три элемента буквального результата
    <P>Planet</P>
    , которые заменили три элемента
    <PLANET>
    .

    ПРОПУСК АТРИБУТА SELECT

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

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

    Доступ к значениям узлов

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

    <xsl:value-of>
    , у которого есть два возможных атрибута:

    • 

    select
    (обязательный). Выходное значение. Устанавливается в выражение;

    • disable-output-escaping (необязательный). Указывает, что символы, такие как

    >
    , будут отправляться в выходной поток как есть, не изменяясь на
    &gt;
    . Значения этого атрибута:
    yes
    или
    no
    .

    Элемент

    <xsl:value-of>
    всегда пуст.

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

    select
    можно указать, значение какого узла требуется получить. Например, вам может потребоваться значение узла
    <NAME>
    в каждом элементе
    <PLANET>
    , то есть текст, заключенный в этом узле. Это можно сделать следующим образом (листинг 2.4).

    Листинг 2.4. Использование <xsl:value-of>

    <?xml version="1.0">

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/">

      <HTML>

       <xsl:apply-templates/>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANETS">

      <xsl:apply-templates/>

     </xsl:template>


     <xsl:template match="PLANET">

      <P>

       <xsl:value-of select="NAME"/>

      </P>

     </xsl:template>

    </xsl:stylesheet>

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

    planets.xml
    следующий:

    <HTML>

     <P>Mercury</P>

     <P>Venus</P>

     <P>Earth</P>

    </НТМL>

    АТРИБУТ DISABLE-OUTPUT-ESCAPING

    Атрибут disable-output-escaping элемента <xsl:value-of> более подробно рассмотрен в главе 3.

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

    planets.xml
    в HTML-таблицу в новом файле
    planets.html
    (рис. 2.1), как мы видели в главе 1. Теперь это можно сделать при помощи
    <xsl:value-of>
    .

    Рис. 2.1. Planets.html в Internet Explorer


    Здесь важно учесть один момент. В

    planets.xml
    формально не задан порядок элементов
    <MASS>
    ,
    <RADIUS>
    ,
    <DAY>
    и
    <DISTANCE>
    , однако важно, чтобы эти элементы обрабатывались в определенном порядке в соответствии с заголовками таблицы. Поэтому я буду использовать элементы
    <xsl:value-of>
    в том порядке, в котором они требуются в таблице HTML.

    Таким образом, чтобы создать HTML-таблицу, изображенную на рис. 2.1, я сначала ищу элемент

    <PLANETS>
    и затем заменяю его на HTML для создания самой HTML-таблицы. Элемент
    <PLANETS>
    — дочерний элемент корневого узла, и поскольку на корневой узел можно сослаться через «/», на элемент
    <PLANETS>
    можно сослаться непосредственно через "
    /PLANETS
    ", без необходимости предварительно применять шаблон для корневого узла. Это пример выражения XPath, большое число подобных мы также увидим в главе 4.

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

    <PLANETS>
    непосредственно как "
    /PLANETS
    " — заметьте, что для применения шаблонов к любым дочерним узлам
    <PLANETS>
    я использовал
    <xsl:apply-templates>
    :

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

         </TR>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>

     .

     .

     .

    Каждый дочерний узел

    <PLANET>
    имеет дочерние узлы
    <NAME>
    ,
    <MASS>
    ,
    <RADIUS>
    и
    <DAY>
    , и я хочу обрабатывать их именно в таком порядке — для того чтобы они добавлялись в HTML-таблицу в соответствии с заголовками таблицы. Для задания порядка их обработки я поместил элементы
    <xsl:value-of>
    (листинг 2.5).

    Листинг 2.5. planets.xsl

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

         </TR>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANET">

      <TR>

       <TD><xsl:value-of select="NAME"/></TD>

       <TD><xsl:value-of select="MASS"/></TD>

       <TD><xsl:value-of select="RADIUS"/></TD>

       <TD><xsl:value-of select="DAY"/></TD>

      </TR>

     </xsl:template>

    </xsl:stylesheet>

    Это все, что нам нужно; вот результат:

    <HTML>

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

     </HEAD>

     <BODY>

      <H1>

       The Planets Table

      </H1>

      <TABLE BORDER="2">

       <TR>

        <TD>Name</TD>

        <TD>Mass</TD>

        <TD>Radius</TD>

        <TD>Day</TD>

       </TR>

       <TR>

        <TD>Mercury</TD>

        <TD>.0553</TD>

        <TD>1516</TD>

        <TD>58.65</TD>

       </TR>

       <TR>

        <TD>Venus</TD>

        <TD>.815</TD>

        <TD>3716</TD>

        <TD>116.75</TD>

       </TR>

       <TR>

        <TD>Earth</TD>

        <TD>1</TD>

        <TD>2107</TD>

        <TD>1</TD>

       </TR>

      </TABLE>

     </BODY>

    </HTML>



    Это практически то, что требовалось. Если взглянуть на рис. 2.2, видно, что в этом HTML-файле не выведены значения атрибута

    UNITS
    , который присутствует у каждого элемента (кроме атрибута
    <NAME>
    ) в
    planets.xml
    :


    Рис. 2.2. Planets.html без атрибутов в Internet Explorer


    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xml" href="planets.xsl"?>

    <PLANETS>

     <PLANET>

      <NAME>Mercury</NAME>

      <MASS UNITS="(Earth = 1)">.0553</MASS>

      <DAY UNITS="days">58.65</DAY>

      <RADIUS UNITS="miles">1516</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.983</DENSITY>

      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--В перигелии-->

     </PLANET>

     .

     .

     .

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

    Однако перед тем, как начать углубляться в работу с шаблонами, необходимо еще изучить достаточно много материала о таблицах стилей в общем. Например, в рабочий проект XSLT 1.1 включена поддержка рекомендации XML Base, а это значит, что она также появится и в XSLT 2.0.

    Поддержка XML Base

    Одним из пунктов, добавленных в рабочий проект XSLT 1.1, была поддержка спецификации W3C XML Base. На момент написания книги спецификация XML Base существует в форме предлагаемой рекомендации (Proposed Recommendation), датированной 20 декабря 2000 г.; текущую версию документа можно найти по адресу www.w3.org/TR/xmlbase/.

    Эта спецификация позволяет обеспечивать для документов XML и XSL базовый идентификаторы URI аналогично элементу HTML

    <BASE>
    . (Фактически, благодаря элементу HTML
    <BASE>
    существует XBase: W3C взял на себя обязательство дать XML всю мощь ссылочной модели HTML 4.0 и затем развивать ее.) Как вы помните, одним из свойств элементов XSL является их базовый URI, и теперь его можно устанавливать при помощи XML Base. Однако пока ни один из известных мне процессоров XSLT не поддерживает XML Base.

    Здесь будет приведен только обзор работы с XML Base: для установки базового URI XML-документа можно использовать атрибут

    xml:base
    . Другие идентификаторы URI документа затем вычисляются, используя это значение в качестве базы. Заметьте, что
    xml:base
    использует пространство имен
    xml
    , которое предопределено в XML как "
    http://www.w3.org/XML/1998/namespace
    ". В следующем примере используются ссылки XML, XML links (или XLinks):

    <?xml version="1.0"?>

    <MOVIE_REVIEW xmlns:xlink="http://www.w3.org/1999/xlink"

     xml:base="http://www.starpowder.com/"

     xlink:type="simple" xlink:show="new" xlink:href="reviews.xml">

     Mr. Blandings Builds His Dream House

    </MOVIE_REVIEW>

    Используя значение, присвоенное атрибуту

    xml:base
    , URI атрибута
    xlink:href
    , "
    reviews.xml
    " раскрывается в полный URI "
    http://www.starpowder.com/reviews.xml
    ". Подобным образом можно при помощи xml:base задать базовый URI для документа или конкретного элемента.

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

    • базовый URI корневого узла — это URI документа;

    • базовый URI узла элемента— это базовый URI, заданный в элементе атрибутом

    xml:base
    (если таковой существует), или базовый URI элемента- родителя элемента в документе, или внешняя сущность (если существует), или базовый URI сущности документа или внешней сущности, содержащей элемент;

    • базовый URI для узла инструкции обработки — это URI, который будет применен к ссылке URI в содержимом инструкции обработки. В соответствии со спецификацией XML Base, базовым URI для ссылки URI, появляющейся в содержимом инструкции обработки, является базовый URI родительского элемента инструкции обработки (если таковой имеется) в пределах сущности документа или внешней сущности, или базовый URI сущности документа или внешней сущности, содержащей инструкцию обработки;

    • базовым URI для текстового узла, узла комментария или узла атрибута является базовый URI родителя этого узла;

    • базовый URI для узла пространства имен, однако, зависит от реализации.

    Установка базовых URI документов и элементов может оказаться удобной, если вам приходится работать с очень большим множеством документов. При реорганизации этого множества документов вам нужно будет переустановить только один базовый URI, а не все индивидуальные URI. Однако, как я уже говорил, из известных мне процессоров XSLT ни один пока не поддерживает XML Base.

    Выбор методов вывода

    Еще один важный аспект создания таблиц стилей — выбор метода вывода: XML, HTML, текст (то есть любой текстовый документ, не являющийся документом XML или HTML) и т.д. Другими словами, метод вывода (output method) определяет тип создаваемого документа. По умолчанию методом вывода является XML, хотя большинство процессоров при встрече элемента <HTML> создают документы HTML. (Некоторые процессоры действуют подобным образом, если расширение создаваемого файла документа

    .html
    .)

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

    <xsl:output>
    . Выходной тип может задать, например, будет ли процессор XSLT записывать инструкцию обработки XML,
    <?xml:version="1.0"?>
    , в начало документа, а также указать тип MIME (такой, как «text/xml» или «text/html») документов, отправляемых процессором XSLT с web-сервера браузеру. Кроме того, если вы установите тип вывода в HTML, большинство процессоров XSLT распознают, что не всем элементам в HTML требуются закрывающие и открывающие теги, и т.д.

    Преобразованию из XML в другие типы документов посвящена глава 6, но здесь мы также кратко рассмотрим элемент

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

    • 

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

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

    method
    элемента, потому что с его помощью устанавливается требуемый тип дерева вывода. Самые распространенные значения — «html», «xml» и «text».

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

    В нашей таблице стилей

    planets.xsl
    элемент
    <xsl:output>
    не используется; это значит, что для этой таблицы я полагался на правила вывода по умолчанию. Типом вывода по умолчанию является XML, если только процессор XSLT не встретит тег
    <HTML>
    или
    <html>
    . (Заметьте, что это не формальное требование, а только соглашение, которому не обязаны следовать все процессоры XSLT.) В
    planets.xsl
    я использовал тег <HTML> следующим образом:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       .

       .

       .

    Однако, если удалить этот тег:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="/PLANETS">

      <HEAD>

       <TITLE>

        The Planets Table

       </TITLE>

      </HEAD>

      .

      .

      .

    то такой вид вывода вы получите от процессора XT Джеймса Кларка. Обратите внимание на инструкции обработки XML в начале:

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

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

     </HEAD>

     .

     .

     .

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

    <xsl:output>
    , даже не прибегая к элементу
    <HTML>
    :

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:output method="html"/>

     <xsl:template match="/PLANETS">

      <HEAD>

       <TITLE>

        The Planets Table

       </TITLE>

      </HEAD>

      .

      .

      .

    Вот вывод XT в данном случае — только фрагмент HTML, никаких инструкций обработки XML:

    <HEAD>

     <TITLE>

      The Planets Table

     </TITLE>

    </HEAD>

    .

    .

    .

    ЭЛЕМЕНТЫ <META>, АВТОМАТИЧЕСКИ ДОБАВЛЯЕМЫЕ В HTML

    Если вы явно используете элемент <xml:output method="html"/>, некоторые процессоры XSLT, такие как Saxon, добавляют в элемент <head> выходного документа элемент <meta> подобным образом: <meta http-equiv="Content-Type" content="text/html; charset=utf-8">.

    В общем случае процессоры XSLT должны учитывать, что в HTML определенные элементы, такие как

    <br>
    ,
    <img>
    ,
    <frame>
    и т.д., пусты. Также пробелы и другие символы в значениях атрибута URI преобразуются в соответствии со спецификацией HTML (пробел становится «%20» и т.п.), инструкции обработки завершаются символом
    >
    , а не
    ?>
    , и учитывается тот факт, что отдельным атрибутам значение не присваивается.

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

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

    <xsl:copy>
    , с которым мы познакомимся в главе 3, для создания таблицы стилей, которая создает копию любого XML-документа.

    Я воспользуюсь образцом совпадения «*», которому, как говорилось ранее, удовлетворяет любой элемент, и применю элемент

    <xsl:copy>
    для копирования текущего элемента в выходной документ. Вот как выглядит новая таблица стилей, копирующая исходный документ в результирующий:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="*">

      <xsl:copy>

       <xsl:apply-templates/>

      </xsl:copy>

     </xsl:template>

    </xsl:stylesheet>

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

    <html>
    , — я явно указываю, что здесь методом вывода является XML. Если бы я этого не сделал, скопированные документы XHTML не начинались бы с объявления XML:

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:output method="xml"/>

     <xsl:template match="*">

      <xsl:copy>

       <xsl:apply-templates/>

      </xsl:copy>

     </xsl:template>

    </xsl:stylesheet>

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

    Помните, что XML — это метод вывода по умолчанию, если только ваш входной документ не содержит тег <HTML> или <html>. Тем не менее, даже если вы выполняете преобразование одного XML-документа в другой, зачастую удобно использовать элемент

    <xsl:output>
    — для того, чтобы, например, задать кодировку символов (по умолчанию это обычно UTF-8, восьмибитовое подмножество Unicode) или выравнивание выходного документа (это описывается в главе 3).

    РАБОТА С ФРАГМЕНТАМИ XML

    Можно работать не только с документами XML целиком, но и с их фрагментами. В этом случае следует установить атрибут omit-xml-declaration в «yes» — для того, чтобы опустить объявление XML в начале дерева вывода, как обсуждается в главе 6.

    Когда вы используете метод вывода XML, дерево вывода представляет собой хорошо сформированный XML (однако он не обязан быть допустимым). Не обязательно оно должно быть хорошо сформированным XML-документом, это может быть общая разобранная внешняя сущность XML. Содержимое вывода может включать символьные данные, разделы CDATA, ссылки на сущности, инструкции обработки, комментарии и элементы. Вывод должен также удовлетворять объявлению пространств имен XML.

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

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

    В листинге 2.6 приведен пример таблицы стилей (которую мы увидим в главе 6), преобразующей

    planets.xml
    в
    planets.rtf
    .

    Листинг 2.6. Таблица стилей RTF

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:output method="text"/>

     <xsl:strip-space elements="*"/>

     <xsl:template match="/PLANETS">{\rtf1\ansi\deff0{\fonttbl {\\fcharset0 Courier New:}}

      \viewkind4\uc1\pard\langl033\b\ The Planets Table\par\b0

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

      <xsl:apply-templates/>

      \par

     }</xsl:template>


     <xsl:template match="PLANET">

      <xsl:value-of select="NAME"/>

      \tab

      <xsl:value-of select="MASS"/>

      \tab

      <xsl:value-of select="RADIUS"/>

      \tab

      <xsl:value-of select="DAY"/>

      \tab

      \par

     </xsl:template>

    </xsl:stylesheet>

    Результирующий документ RTF, planets.rtf, изображен на рис. 2.3 в Microsoft Word 2000. Обратите внимание на то, что я установил метод вывода в текст в элементе

    <xsl:output method="text">
    :

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:output method="text"/>

     <xsl:template match="/PLANETS">{\rtf1\ansi\deff0{\fonttbl(\\fcharset0 Courier New;}}

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

      .

      .

      .

    Рис. 2.3. Planets.rtf в Microsoft Word


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

    <xsl:template>
    — я сделал так потому, что в документах RTF коды RTF должны появляться с самого начала. Если бы я решил вставлять коды RTF на следующей строке — например, так:

    <?xml versions="1.0">

    <xsl:stylesheet version="1.0"

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

     <xsl:output method="text"/>

     <xsl:template match="/PLANETS">

      {\rtf1\ansi\deff0{\fonttbl{\\fcharset0 Courier New;}}

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

      .

      .

      .

    то выходной файл RTF начинался бы с символа новой строки, что вызвало бы ошибку приложения для работы с файлами RTF — такого, как Microsoft Word. Более подробно RTF и другие форматы будут рассмотрены в главе 6.

    Упрощенные таблицы стилей

    Как можно заметить на основе рассмотренного до сих пор материала, создавать таблицы стилей XSLT не так-то просто. W3C попытался облегчить эту процедуру, разработав упрощенные таблицы стилей (simplified stylesheets), в которые не нужно — а на самом деле и невозможно — включать элемент

    <xsl:stylesheet>
    или какие-либо еще элементы высокого уровня.

    Фактически упрощенная таблица стилей представляет собой результирующий документ, содержащий несколько элементов XSL невысокого уровня. W3C называет такую таблицу «элемент буквального результата как таблица».

    В листинге 2.7 я осуществлю преобразование

    planets.xml
    в
    planets.html
    , но теперь я сделаю это при помощи упрощенной таблицы стилей. В упрощенных таблицах стилей вы не можете применять элементы высокого уровня, такие как
    <xsl:template>
    , позволяющие рекурсивную обработку всех элементов в исходном документе. Поэтому здесь я зайду немного вперед и воспользуюсь элементом
    <xsl:for-each>
    (рассматриваемым в главе 5), который, не являясь элементом высокого уровня, позволяет обработать в цикле сразу несколько узлов.

    Мне также нужно каким-либо образом выбрать все элементы

    <PLANET>
    в исходном документе, и вы можете подумать, что это невозможно без использования шаблонов нескольких уровней — например, один для корневого узла, затем один для выбора на следующем уровне вниз, корневом элементе
    <PLANETS>
    , и затем еще один уровень вниз для самих элементов
    <PLANET>
    . Однако, используя XPath, можно при помощи выражения "
    //PLANET
    " найти все узлы элемента
    <PLANET>
    , производные от корневого узла (см. главу 4). Это значит, что я могу написать упрощенную таблицу стилей следующим образом.

    Листинг 2.7. Упрощенная таблица стилей

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

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

     </HEAD>

     <BODY>

      <H1>

       The Planets Table

      </H1>

      <TABLE BORDER="2">

       <TR>

        <TD>Name</TD>

        <TD>Mass</TD>

        <TD>Radius</TD>

        <TD>Day</TD>

       </TR>

       <xsl:for-each select="//PLANET">

        <TR>

         <TD><xsl:value-of select="NAME"/></TD>

         <TD><xsl:value-of select="MASS"/></TD>

         <TD><xsl:value-of select="RADIUS"/></TD>

         <TD><xsl:value-of select="DAY"/></TD>

        </TR>

       </xsl:for-each>

      </TABLE>

     </BODY>

    </HTML>

    Данная версия работает точно так же, как и предыдущая версия

    planets.xsl
    , при этом совсем не используя элементы высокого уровня. Упрощенные таблицы стилей, такие как эта, были представлены в помощь авторам HTML при осуществлении преобразований в XSL, однако их применимость весьма ограничена. Очевидно, все равно нужно знать, как работать с элементами XSL, а отсутствие возможности использовать
    <xsl:template>
    в данном случае только затруднило работу. Однако вы должны знать, что упрощенные таблицы стилей существуют и включены в спецификацию XSLT.

    ОБРАБОТКА ПО УМОЛЧАНИЮ БЕЗ ЭЛЕМЕНТА <XSL:STYLESHEET>

    Если процессор XSLT не может найти в таблице стилей элемент <xsl:stylesheet>, он трактует таблицу как упрощенную таблицу стилей.

    Встроенные таблицы стилей

    Рекомендация XSLT также поддерживает встроенные таблицы стилей, embedded stylesheets (вслед за использованием встроенных таблиц стилей и элементов стиля в HTML), но, как и упрощенные таблицы стилей, они не очень распространены.

    Встроенные таблицы стилей могут обрабатывать не все процессоры XSLT, но некоторые — в частности, Saxon — могут. Давайте рассмотрим пример. В этом случае я включил весь элемент таблицы стилей целиком из

    planets.xsl
    в
    planets.xml
    для создания нового документа,
    embedded.xml
    . В новом документе будут содержаться все данные и вся таблица стилей. Заметьте, что для того, чтобы быть хорошо сформированным XML,
    embedded.xml
    должен иметь только один корневой элемент, поэтому я сделал таблицу стилей (то есть элемент
    <xsl:stylesheet>
    ) родительским элементом корневого элемента
    <PLANETS>
    .

    Чтобы указать, какой элемент будет трактоваться как встроенная таблица стилей, я задал элементу

    <xsl:stylesheet>
    ID "stylesheet", установив атрибут
    id
    в это имя:

    <xsl:stylesheet version="1.0" id="stylesheet"

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

    В начале документа я также присваиваю это имя, "stylesheet", атрибуту

    href
    элемента
    <?xml-stylesheet?>
    :

    <?xml-stylesheet type="text/xml" href="#stylesheet"?>

    Теперь процессору XSLT известно, какой элемент я хочу использовать в качестве таблицы стилей — элемент с ID "stylesheet". Но что это за элемент? Элементы XML формируют элементы типа ID в объявлениях DTD или схемах XML, и, как вы помните, информация объявлений DTD и схем пока еще не передается процессору XSLT.

    Некоторые процессоры XSLT, такие как Saxon, читают объявление DTD, если оно есть, для определения атрибутов, обладающих типом ID, поэтому я включил DTD в

    embedded.xml
    (листинг 2.8).

    Листинг 2.8. planets.xml со встроенной таблицей стилей

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xml" href="#stylesheet"?>

    <!DOCTYPE PLANETS [

    <!ELEMENT PLANET (CUSTOMER)*>

    <!ELEMENT CUSTOMER (NAME,MASS,RADIUS,DAY)>

    <!ELEMENT NAME (#PCDATA)>

    <!ELEMENT MASS (#PCDATA)>

    <!ELEMENT RADIUS (#PCDATA)>

    <!ELEMENT DAY (#PCDATA)>

    <!ELEMENT xsl:stylesheet (xsl:template)*>

    <!ELEMENT xsl:template (#PCDATA)>

    <!ATTLIST xsl:stylesheet

     id ID #REQUIRED

     version CDATA #IMPLIED>

    ]>

    <PLANETS>

     <PLANET>

      <NAME>Mercury</NAME>

      <MASS UNITS="(Earth = 1)">.0553</MASS>

      <DAY UNITS="days">58.65</DAY>

      <RADIUS UNITS="miles">1516</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.983</DENSITY>

      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Venus</NAME>

      <MASS UNITS="(Earth = 1)">.815</MASS>

      <DAY UNITS="days">116.75</DAY>

      <RADIUS UNITS="miles">3716</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.943</DENSITY>

      <DISTANCE UNITS="million miles">66.8</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">128.4</DISTANCE><!--B перигелии-->

     </PLANET>


     <xsl:stylesheet version="1.0" id="stylesheet"

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

      <xsl:template match="/PLANETS">

       <HTML>

        <HEAD>

         <TITLE>

          The Planets Table

         </TITLE>

        </HEAD>

        <BODY>

         <H1>

          The Planets Table

         </H1>

         <TABLE BORDER="2">

          <TR>

           <TD>Name</TD>

           <TD>Mass</TD>

           <TD>Radius</TD>

           <TD>Day</TD>

          </TR>

          <xsl:apply-templates/>

         </TABLE>

        </BODY>

       </HTML>

      </xsl:template>


      <xsl:template match="PLANET">

       <TR>

        <TD><xsl:value-of select="NAME"/></TD>

        <TD><xsl:value-of select="MASS"/></TD>

        <TD><xsl:value-of select="RADIUS"/></TD>

        <TD><xsl:value-of select="DAY"/></TD>

       </TR>

      </xsl:template>


      <xsl:template match="xsl:stylesheet"></xsl:template>

     </xsl:stylesheet>

    </PLANETS>

    Следует отметить еще одно: включив всю таблицу стилей в файле

    embedded.xml
    в элемент
    <xsl:stylesheet>
    , я должен был предоставить шаблон таблицы стилей для элемента
    <xsl:stylesheet>
    . (Если бы я этого не сделал, текст из текстовых узлов таблицы стилей был бы скопирован в результирующий документ, — это обсуждается в главе 3 в разделе, посвященном правилам по умолчанию для шаблонов.) Я оставил этот элемент пустым, поместив в конце таблицы стилей в
    embedded.xml
    следующую строку, поэтому из самой таблицы стилей в результирующий документ ничего не копируется:

    <xsl:template match="xsl:stylesheet"></xsl:template>

    Теперь в Saxon я могу из

    embedded.xml
    создать
    planets.html
    . В Windows для указания того, что используется встроенная таблица стилей, в Saxon служит параметр
    :

    C:\planets>saxon -a embedded.xml > planets.html

    Элемент <xsl:include>

    Другой способ вставить таблицы стилей внутрь других документов — использовать элемент <xsl:include>, позволяющий включить содержимое файла в определенное место в таблице стилей. У этого элемента только один атрибут:

    • 

    href
    (обязательный). URI таблицы стилей, которую вы хотите включить.

    Этот элемент пустой и не обладает никаким содержимым.

    Рассмотрим листинг 2.9. В этом случае я помещу часть таблицы стилей из

    planets.xsl
    в новый документ,
    rules.xml
    . Затем я смогу включить
    rules.xml
    в
    planets.xsl
    .

    Листинг 2.9. Включение таблицы стилей

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:include href="rules.xsl"/>

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TD>Name</TD>

         <TD>Mass</TD>

         <TD>Radius</TD>

         <TD>Day</TD>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>

    </xsl:stylesheet>

    А вот как выглядит

    rules.xsl
    (листинг 2.10). Обратите внимание на то, что это полный документ XSL с объявлением XML и элементом
    <xsl:stylesheet>
    .

    Листинг 2.10. rules.xsl

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="PLANET">

      <TR>

       <TD><xsl:value-of select="NAME"/></TD>

       <TD><xsl:value-of select="MASS"/></TD>

       <TD><xsl:value-of select="RADIUS"/></TD>

       <TD><xsl:value-of select="DAY"/></TD>

      </TR>

     </xsl:template>

    </xsl:stylesheet>

    Вот как это работает. Кроме

    <xsl:include>
    , для вставки таблиц стилей или фрагментов таблицы стилей можно также применять
    <xsl:import>
    .

    НОВШЕСТВА В XSLT 2.0

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

    Элемент <xsl:import>

    Так же как и

    <xsl:include>
    ,
    <xsl:import>
    позволяет вставить таблицу стилей или фрагмент таблицы стилей в другую таблицу стилей. И так же, как
    <xsl:include>
    , у
    <xsl:import>
    есть только один атрибут:

    • 

    href
    (обязательный). URI включаемой таблицы стилей.

    И так же, как

    <xsl:include>
    ,
    <xsl:import>
    пуст и не имеет содержимого. В чем же тогда разница между ними? Разница заключается в старшинстве импорта (import precedence).

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

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

    <xsl:import>
    вместо
    <xsl:include>
    :

    Листинг 2.11. Импорт таблицы стилей

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:import href="rules.xsl"/>

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TD>Name</TD>

         <TD>Mass</TD>

         <TD>Radius</TD>

         <TD>Day</TD>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>

    </xsl:stylesheet>

    Элемент <xsl:apply-imports>

    Если вы импортируете таблицу стилей с шаблоном, например, для элемента

    <PLANET>
    , и затем определите свой собственный элемент
    <PLANET>
    , импортируемая версия будет перекрыта. Как можно получить доступ к перекрытой версии? Этому служит элемент
    <xsl:apply-imports>
    .

    В XSLT 1.0 у этого элемента нет атрибутов и нет содержимого. В рабочем проекте XSLT 1.1 элемент

    <xsl:apply-imports>
    может обрабатывать параметры, поэтому он может содержать ноль или более элементов
    <xsl:with-param>
    (подробнее о параметрах см. главу 9).

    В качестве примера я модифицирую только что рассмотренный нами пример

    <xsl:import>
    . В этом случае я добавлю еще один столбец в генерируемую в этом примере (листинг 2.12) HTML-таблицу, названную DATA, путем перекрытия шаблона
    <PLANET>
    в
    rules.xsl
    новым шаблоном
    <PLANET>
    из
    planets.xsl
    . Новый шаблон просто добавляет в таблицу новый столбец и затем применяет старый шаблон
    <PLANET>
    к оставшимся данным. Доступ к старому шаблону осуществляется при помощи
    <xsl:apply-imports>
    .

    Листинг 2.12. Использование <xsl:apply-imports>

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:import href="rules.xsl"/>

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Date</TD>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

          <xsl:apply-templates/>

         </TR>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANET">

      <TR>

       <TD>4/1/2002</TD>

       <xsl:apply-imports/>

      </TR>

     </xsl:template>

    </xsl:stylesheet>

    А вот как выглядит новая версия

    rules.xsl
    (листинг 2.13).

    Листинг 2.13. Новая версия rules.xsl

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.0"

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

     <xsl:template match="PLANET">

      <TD><xsl:value-of select="NAME"/></TD>

      <TD><xsl:value-of select="MASS"/></TD>

      <TD><xsl:value-of select="RADIUS"/></TD>

      <TD><xsl:value-of select="DAY"/></TD>

     </xsl:template>

    </xsl:stylesheet>

    Результаты можно видеть на рис. 2.4. Я создал один шаблон при помощи другого, что является ближайшим аналогом в XSLT для наследования из объектно-ориентированной парадигмы.

    Рис. 2.4. Использование <xsl:apply-imports>


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

    <xsl:apply-imports>
    можно использовать параметры таблицы стилей, что означает, что вы можете использовать элементы
    <xsl:with-param>
    в качестве содержимого
    <xsl:apply-imports>
    . Подробное обсуждение параметров и элемента
    <xsl:with-param>
    приводится в главе 9.

    Преобразование документов XML при помощи Internet Explorer

    В нашем обзоре таблиц стилей есть еще одна тема для обсуждения: как использовать таблицы стилей в Internet Explorer. Как мы видели в главе 1, для считывания документов XML и XSL можно использовать JavaScript, и осуществлять преобразование при помощи разборщика MSXML3. (Дополнительная информация по этой теме приведена в главе 10. Документацию по Internet Explorer можно также прочитать по адресу http://msdn.microsoft.com/xml/XSLGuide/.)

    Однако, если вам нужно открыть XML-документ непосредственно в Internet Explorer при навигации (например, набрав URI в адресной строке), в использовании элементов

    <?xml-stylesheet?>
    и
    <xsl:stylesheet>
    вы полагаетесь на браузер, а это означает, что для IE версии 5.5 и более ранних необходимо провести ряд изменений. 

    INTERNET EXPLORER 6.0 И ПОЛУЧЕНИЕ И УСТАНОВКА РАЗБОРЩИКА MSXML

    Обратите внимание: IE 6.0 только что вышел, когда книга готовилась к печати, и он поддерживает полный синтаксис XSLT (за исключением того, что вы все еще должны использовать тип «text/xsl» для таблиц стилей, как в <?xml-stylesheet type="text/xsl" href="planets.xsl"?>, вместо «text/xml»). Если вы используете IE 5.5 или более ранних версий, вы также можете загрузить и установить последнюю версию разборщика MSXML прямо от Microsoft вместо предыдущей версии, используемой Internet Explorer. Если это сделать, вам не нужно будет проводить изменения, перечисленные в этом разделе. Дополнительную информацию можно получить по адресу http://msdn.microsoft.com/ xml/general/xmlparser.asp. Загрузить разборщик сейчас можно по адресу http://msdn.microsoft.com/downloads/default.asp?URL=/code/sample.asp?url=/msdn-files/027/000/541/msdncompositedoc.xml. (Учтите, однако, что Microsoft, кажется, реорганизует свой web-узел примерно каждые пятнадцать минут.) Если вы работаете с IE 5.5 или более ранней версии, я настоятельно рекомендую вам загрузить MSXML, чтобы вам не пришлось изменять все ваши таблицы стилей XSLT для их использования в IE, или обновить браузер до версии 6.0 или более поздней.

    Для IE версии 5.5 или более ранней необходимо внести изменения и в

    planets.xml
    , и в
    planets.xsl
    . Для того чтобы использовать
    planets.xml
    в IE, необходимо преобразовать атрибут
    type
    в инструкции обработки
    <?xml-stylesheet?>
    из «text/xml» в «text/xsl» (листинг 2.14).

    Листинг 2.14. Версия planets.xml для Internet Explorer

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="planets.xsl"?>

    <PLANETS>

     <PLANET>

      <NAME>Mercury</NAME> <MASS UNITS="(Earth = 1)">.0553</MASS>

      <DAY UNITS="days">58.65</DAY>

      <RADIUS UNITS="miles">1516</RADIUS>

      <DENSITY UNITS="(Earth = 1)">983</DENSITY>

      <DISTANCE UNITS="million miles">43.4</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Venus</NAME>

      <MASS UNITS="(Earth = 1)">.815</MASS>

      <DAY UNITS="days">116.75</DAY>

      <RADIUS UNITS="miles">3716</RADIUS>

      <DENSITY UNITS="(Earth = 1)">.943</DENSITY>

      <DISTANCE UNITS="million miles">66.8</DISTANCE><!--B перигелии-->

     </PLANET>

     <PLANET>

      <NAME>Earth</NAME>

      <MASS UNITS="(Earth = 1)">1</MASS>

      <DAY UNITS="days">1</DAY>

      <RADIUS UNITS="miles">2107</RADIUS>

      <DENSITY UNITS="(Earth = 1)">1</DENSITY>

      <DISTANCE UNITS="million miles">1284</DISTANCE><!--B перигелии-->

     </PLANET>

    </PLANETS>

    Для работы в IE версии 5.5 или младше необходимо также преобразовать таблицу стилей

    planets.xsl
    . Главное отличие между рекомендацией W3C XSL и реализацией XSL в IE состоит в том, что в IE версии 5.5 и младше не реализованы никакие правила XSL по умолчанию — см. главу 3 (заметьте, что IE версии 6.0 на момент выхода этой книги в свет не обременён такой проблемой). Это значит, что для IE версии 5.5 или младше я должен включать правило XSL для корневого узла документа, который задается при помощи «/». Я также должен использовать в таблице стилей другое пространство имен XSL, «http://www.w3.org/TR/WD-xsl», и опустить атрибут версии в элементе
    <xsl:stylesheet>
    (листинг 2.14).

    Листинг 2.15. Версия planets.xsl для Internet Explorer

    <?xml version="1.0"?>

    <xsl:stylesheet xmlns:xsl="http.//www w3.org/TR/WD-xsl">

     <xsl:template match="/">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

         </TR>

         <xsl:apply-templates/>

        </TABLE>

       </BODY>

      </HTML>

     </xsl:template>


     <xsl:template match="PLANETS">

      <xsl:apply-templates/>

     </xsl:template>


     <xsl:template match="PLANET">

      <TR>

       <TD><xsl:value-of select="NAME"/></TD>

       <TD><xsl:value-of select="MASS"/></TD>

       <TD><xsl:value-of select="RADIUS"/></TD>

       <TD><xsl:value-of select="DAY"/></TD>

      </TR>

     </xsl:template>

    </xsl:stylesheet>

    Вот и все! Теперь мы успешно изменили

    planets.xml
    и
    planets.xsl
    для прямого просмотра в Internet Explorer. Такие изменения необходимо провести для навигации непосредственно по XML-документам с таблицами XSL в этом браузере.

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







     


    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх