• XSLT и JavaScript в Internet Explorer
  • Обработка ошибок разбора
  • Internet Explorer и динамические стили
  • Internet Explorer и участки данных XML
  • Вызов Java непосредственно из процессоров XSLT
  • Работа с API XSLT для Java
  • Взаимодействие Xalan с Java
  • Взаимодействие Saxon с Java
  • Взаимодействие процессора XSLT Oracle с Java
  • Взаимодействие XT с Java
  • Преобразование XML в реляционную базу данных
  • Применение XSLT с активными серверными страницами
  • Применение XSLT с Java Server Pages
  • Применение XSLT с сервлетами Java
  • Глава 10

    Работа с API процессоров XSLT

    Как вы видели на протяжении всей книги, при работе с XSLT вам не требовалось никакого программирования. Но все процессоры XSLT, с которыми мы работали до сих пор, — Xalan, Saxon, XT, Oracle и MSXML — разработаны так, что при желании к ним можно обращаться и из кода программы. Здесь мы рассмотрим, как работать с этими процессорами в прикладной программе. Можете спокойно пропустить эту главу, если вы не программист или не собираетесь им становиться. Но если вы не будете использовать возможности программного интерфейса, вы потеряете довольно много, в том числе поддержку XSLT на web-серверах. В этой главе будет также показано, как преобразовывать XML в реляционную базу данных.

    Для взаимодействия с различными прикладными программными интерфейсами (API, Application Programming Interface) процессоров XSLT я буду применять Java и JavaScript. С различными процессорами XSLT можно работать и при помощи таких языков, как С++ или Visual Basic, но до сих пор подавляющее большинство программистов выбирало Java, а язык JavaScript удобен для обработки преобразований в Internet Explorer. Кроме того, используемые вами процессоры XSLT специально разработаны для взаимодействия с Java, хотя с процессором MSXML3 можно работать из программы как с СОМ-объектом. Как я говорил, с процессором MSXML в Internet Explorer можно работать при помощи JavaScript, такой пример был показан еще в главе 1. И, как я обещал в главе 1, здесь я рассмотрю его более подробно.

    ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ДЛЯ РАБОТЫ С XSLT ИЗМЕНЯЕТСЯ ОЧЕНЬ БЫСТРО!

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

    XSLT и JavaScript в Internet Explorer

    Любите вы Microsoft или нет, нельзя отрицать тот факт, что эта фирма включает в Internet Explorer все больше средств поддержки XSLT (дополнительную информацию можно найти по адресу http://msdn.microsoft.com/xml/general/xmlparser.asp), и поэтому работа с браузером заслуживает нашего внимания. В главе 1 я представил пример создания преобразований XSLT в Internet Explorer при помощи JavaScript, и здесь мы рассмотрим этот пример подробнее. Как вы помните (см. главу 2), IE версии 5.5 и младше может осуществлять настоящие преобразования XSLT, если они реализованы на JavaScript (новый, только что вышедший IE 6.0 может разбирать непосредственно синтаксис XSLT просто путем просмотра XML-документов).

    В этом случае я, пользуясь MSXML и JavaScript, преобразую

    planets.xml
    при помощи
    planets.xsl
    . Для хранения этих документов я создаю два новых объекта,
    XMLDocument
    и
    XSLDocument
    , опираясь на классы
    ActiveXObject
    и
    DOMDocument
    процессора MSXML в функции
    xslt
    . (Эта функция запускается сразу при загрузке страницы, поскольку я установил атрибут
    onload
    элемента
    <BODY>
    в «
    xslt()
    »). Я также создам объект, соответствующий элементу
    <DIV>
    , который отображает результаты преобразования:

    <HTML>

     <HEAD>

      <TITLE>XSLT Using JavaScript</TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       function xslt() {

        var XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var HTMLtarget = document.all['targetDIV'];

        .

        .

        .

    И

    planets.xml
    , и
    planets.xsl
    являются документами XML; и процессор MSXML может работать и как проверяющий на допустимость разборщик XML, если установить свойство
    validateOnParse
    в true. Для загрузки
    planets.xml
    и
    planets.xsl
    в объекты
    XMLDocument
    и
    XSLDocument
    служит метод
    load
    . Я также проверяю наличие ошибок, просматривая код ошибок разбора следующим образом:

    <HTML>

     <HEAD>

      <TITLE>XSLT Using JavaScript</TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       function xslt() {

        var XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var HTMLtarget = document.all['targetDIV'];

        XMLDocument.validateOnParse = true;

        XMLDocument.load('planets.xml');

        if (XMLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        XSLDocument.validateOnParse = true;

        XSLDocument.load('planets.xsl');

        if (XSLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        .

        .

        .

    Теперь, после того как оба файла,

    planets.xml
    и
    planets.xsl
    , были загружены, преобразование можно осуществить методом
    transformNode
    . Посмотрите, как я преобразую
    XMLDocument
    при помощи
    XSLDocument
    и показываю результат в элементе-приемнике
    <DIV>
    :

    <HTML>

     <HEAD>

      <TITLE>XSLT Using JavaScript</TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       function xslt() {

        var XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var HTMLtarget = document.all['targetDIV'];

        .

        .

        .

        HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

        return true;

       }

      </SCRIPT>

     </HEAD>

     <BODY onload="xslt()">

      <DIV ID="targetDIV">

      </DIV>

     </BODY>

    </HTML>

    Эти результаты показаны на рис. 10.1.

    Рис. 10.1. Использование JavaScript для преобразования документа

    Обработка ошибок разбора

    При использовании JavaScript для загрузки документов XML и XSL и работы с ними важно знать, как сообщать об ошибках разбора. В предыдущем примере я сообщал об ошибках, выводя сообщение «Error!» в элементе-приемнике

    <DIV>
    документа HTML, но это не очень информативно. Как получить дополнительную информацию? 

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

    <PLANET>
    в
    planets.xml
    на тег
    <PLANETS>
    :

    <?xml version="1.0"?>

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

    <PLANETS>

     <PLANETS>

      <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>

     .

     .

     .

    Я установил свойство

    validateOnParse
    объекта
    XMLDocument
    в
    true
    (значение по умолчанию —
    false
    , что означает отсутствие проверки), поэтому процессор MSXML отловит эту ошибку разбора. Объект
    XMLDocument
    содержит объект
    parseError
    , и если его свойство
    errorCode
    не равно нулю, это означает наличие ошибки. Сейчас я хочу не просто вывести сообщение «Error!», а расшифровать ошибку при помощи новой функции
    getError
    , которая возвращает строку с информацией о месте и причине ошибки.

    С целый получения этой дополнительной информации я использую свойства <url, line, linepos и reason объекта parseError для того, чтобы определить вызвавший проблему файл, строку, позицию ошибки и ее описание (листинг 10.1). 

    Листинг 10.1. Создание преобразования XSLT и отображение ошибок разбора

    <HTML>

     <HEAD>

      <TITLE>XSLT Using JavaScript</TITLE>

       <SCRIPT LANGUAGE="JavaScript">

        function xslt() {

        var XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        var HTMLtarget = document.all['targetDIV'];

        XMLDocument.validateOnParse = true;

        XMLDocument.load('planets.xml');

        if (XMLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = getError(XMLDocument);

         return false;

        }

        XSLDocument.validateOnParse = true;

        XSLDocument.load('planets.xsl');

        if (XSLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = getError(XSLDocument);

         return false;

        }

        HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

        return true;

       }


       function getError(errorObject) {

        var Error = new String;

        Error = "Error. " + errorObject.parseError.url + "<BR>" +

         "Line: " + errorObject.parseError.line + "<BR>" +

         "Character: " + errorObject.parseError.linepos + "<BR>" +

         "Description: " + errorObject.parseError.reason;

        return Error;

       }

      </SCRIPT>

     </HEAD>

     <BODY onload="xslt()">

      <DIV ID="targetDIV">

      </DIV>

     </BODY>

    </HTML>

    Результат можно увидеть на рис. 10.2, где показаны вызвавший ошибку файл, место ошибки и описание ошибки процессором MSXML. Если вы собираетесь реализовывать преобразования XSLT в Internet Explorer, когда пользователи просматривают ваши документы случайным образом, обработка подобных ошибок разбора исключительно важна.

    Рис. 10.2. Обработка ошибки разбора


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

    Internet Explorer и динамические стили

    Для того чтобы продемонстрировать все возможности управления преобразованиями XSLT при использовании процессора MSXML, в этом примере я разрешу пользователю динамически сортировать таблицу Planets. Общая идея показана на рис. 10.3. Пользователю достаточно щелкнуть на кнопку, чтобы отсортировать таблицу по названию, массе, радиусу или дню.

    Рис. 10.3. Поддержка динамических преобразований XSLT


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

    <xsl:sort>
    (листинг 10.2). По умолчанию я сортирую планеты по названию.

    Листинг 10.2. Применение динамических XSLT-преобразований

    <?xml version="1.0" encoding="iso-8859-1"?>

    <xsl:stylesheet

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

     <xsl:template match="/">

      <HTML>

       <HEAD>

        <TITLE>

         The Sorted Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Sorted Planets Table

        </H1>

        <TABLE BORDER="2">

         <TR>

          <TD>Name</TD>

          <TD>Mass</TD>

          <TD>Radius</TD>

          <TD>Day</TD>

         </TR>

         <xsl:apply-templates select="/PLANETS/PLANET">

          <xsl:sort select="NAME" order="ascending"/>

         </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>

    Эта таблица стилей сортирует планеты в алфавитном порядке по их названиям; но есть и другие возможности: можно позволить пользователю осуществлять сортировку и по другому критерию. Для этого выберите в данной таблице стилей атрибут

    select
    элемента
    <xsl:sort>
    и при помощи JavaScript измените его динамически с «NAME» на «MASS», «RADIUS» или на другой критерий по желанию пользователя, и затем снова выполните преобразование XSLT. При повторном осуществлении преобразования появится новая таблица с новым порядком сортировки.

    В качестве первого шага в создании нужной нам HTML-страницы я загружу

    planets.xml
    и требуемую таблицу стилей и выполню сортировку по умолчанию, то есть по названию планет:

    <HTML>

     <HEAD>

      <TITLE>

       Applying Dynamic Styles

      </TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       var XMLDocument;

       var XSLDocument;

       var HTMLtarget;

       function initialize() {

        XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        HTMLtarget = document.all['targetDIV'];

        XMLDocument.validateOnParse = true;

        XMLDocument.load('planets.xml');

        if (XMLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        XSLDocument.validateOnParse = true;

        XSLDocument.load('planets.xsl');

        if (XSLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

       }

       .

       .

       .

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

    sort
    — ей при щелчке на кнопке передается имя узла (например, «MASS»), по которому нужно провести сортировку. Вот как создаются различные кнопки, показанные на рис. 10.3:

    <INPUT ТУРЕ="BUTTON" ONCLICK="sort('NAME')" VALUE="Sort by name"></INPUT>

    <INPUT TYPE="BUTTON" ONCLICK="sort('MASS')" VALUE="Sort by mass"></INPUT>

    <INPUT TYPE="BUTTON" ONCLICK="sort('RADIUS')" VALUE="Sort by radius"></INPUT>

    <INPUT TYPE="BUTTON" ONCLICK="sort('DAY')" VALUE="Sort by day"></INPUT>

    Затем в функции

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

    <xsl:apply-templates select="/PLANETS/PLANET">

     <xsl:sort select="NAME" order="ascending"/>

    </xsl:apply-templates>

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

    XSLDocument
    , передав в метод
    selectSingleNode
    упомянутого объекта выражение XPath. Метод
    selectSingleNode
    возвращает объект
    node
    , и можно изменить текстовое значение узла при помощи свойства
    nodeValue
    объекта
    node
    . В таком случае я только устанавливаю атрибут select в имя нового узла, по которому будет вестись сортировка:

    <HTML>

     <HEAD>

      <TITLE>

       Applying Dynamic Styles

      </TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       function initialize() {

       .

       .

       .

      }


      function sort(sortNode) {

       (XSLDocument.selectSingleNode("//xsl:sort/@select")).nodeValue

        = sortNode;

       .

       .

       .

      }

     </SCRIPT>

     .

     .


    Теперь все, что осталось сделать, — снова выполнить преобразование и вывести результаты:

    <HTML>

     <HEAD>

      <TITLE>

       Applying Dynamic Styles

      </TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       function initialize() {

        .

        .

        .

       }


       function sort(sortNode) {

        (XSLDocument.selectSingleNode("//xsl:sort/@select")).nodeValue

         = sortNode;

         HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

        }

       </SCRIPT>

     </HEAD>

     .

     .

     .

    Операция завершена. Результаты показаны на рис. 10.3. При щелчке на кнопке таблица сортируется заново по выбранному значению узла (имейте в виду, что сортировка ведется по алфавиту; сортировка по числовым значениям обсуждается в главе 5, где описывается элемент

    <xsl:sort>
    ) и отображается еще раз с новым порядком сортировки. Вот вся HTML-страница (листинг 10.3).

    Листинг 10.3. Применение динамических XSLT-преобразований

    <HTML>

     <HEAD>

      <TITLE>

       Applying Dynamic Styles

      </TITLE>

      <SCRIPT LANGUAGE="JavaScript">

       var XMLDocument;

       var XSLDocument;

       var HTMLtarget;

       function initialize() {

        XMLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        XSLDocument = new ActiveXObject('MSXML2.DOMDocument.3.0');

        HTMLtarget = document.all['targetDIV'];

        XMLDocument.validateOnParse = true;

        XMLDocument.load('planets.xml');

        if (XMLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        XSLDocument.validateOnParse = true;

        XSLDocument load('planets.xsl');

        if (XSLDocument.parseError.errorCode != 0) {

         HTMLtarget.innerHTML = "Error!";

         return false;

        }

        HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

       }


       function sort(sortNode) {

        (XSLDocument.selectSingleNode("//xsl:sort/@select")).nodeValue

         = sortNode;

        HTMLtarget.innerHTML = XMLDocument.transformNode(XSLDocument);

       }

      </SCRIPT>

     </HEAD>

     <BODY ONLOAD="initialize()">

      <CENTER>

       <DIV ID="targetDIV"></DIV>

       <BR>

       <BR>

       <INPUT TYPE="BUTTON" ONCLICK="sort('NAME')" VALUE="Sort by name"></INPUT>

       <INPUT TYPE="BUTTON" ONCLICK="sort('MASS')" VALUE="Sort by mass"></INPUT>

       <INPUT TYPE="BUTTON" ONCLICK="sort('RADIUS')" VALUE="Sort by radius"></INPUT>

       <INPUT TYPE="BUTTON" ONCLICK="sort('DAY')" VALUE="Sort by day"></INPUT>

      </CENTER>

     </BODY>

    </HTML>

    На самом деле загрузить документы XML и XSL в Internet Explorer можно несколькими способами. Для создания объектов

    XMLDocument
    и
    XSLDocument
    я использовал класс ActiveXObject, но эти объекты можно создавать и непосредственно обращаясь к содержащим документы XML объектам ActiveX по идентификатору класса, хранимому в реестре Windows. В следующем примере я таким образом загружу
    planets.xml
    и
    planets.xsl
    в
    XMLDocument
    и
    XSLDocument
    :

    XMLDocument = document.all['XMLdoc'];

    XSLDocument = document.all['XSLdoc'];

    XMLDocument.load('planets.xml');

    XSLDocument.load(' planets.xsl');

    .

    .

    .

    <OBJECT ID="XMLdoc" WIDTH="0" HEIGHT="0"

     CLASSID="clsid:f5078f32-c551-11d3-89b9-0000f81fe221">

    </OBJECT>

    <OBJECT ID="XSLdoc" WIDTH="0" HEIGHT="0"

     CLASSID="clsid:f5078f32-c551-11d3-89b9-0000f81fe221">

    </OBJECT>

    Эта техника не так надежна, как использование класса

    ActiveXObject
    , поскольку идентификаторы классов могут различаться в разных версиях Internet Explorer. (Приведены идентификаторы классов для Internet Explorer 5.5). Но есть еще один способ загрузить документы XML и XSL в Internet Explorer — при помощи участков (island) XML.

    Internet Explorer и участки данных XML

    В Internet Explorer есть специальный тег

    <XML>
    , при помощи которого можно создавать участки (island) XML. Участок XML может содержать либо сам код XML, либо ссылку на XML-документ.

    Участки XML упрощают загрузку документов XML и XSL, поэтому их стоит здесь рассмотреть. В следующем примере я создаю два участка XML,

    sourceDocument
    и
    stylesheet
    , и загружаю
    planets.xml
    и
    planets.xsl
    , просто обратившись к ним через атрибут
    src
    :

    <HTML>

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

      <XML id="sourceDocument" src="planets.xml"></XML>

      <XML id="stylesheet" src="planets.xsl"></XML>

      .

      .

      .

    Теперь для осуществления XSLT-преобразования мне нужно только применить, как и раньше, метод

    transformNode
    и присвоить результаты элементу
    <DIV>
    , чтобы вывести их (листинг 10.4).

    Листинг 10.4. Загрузка документов XML и XSL при помощи участков XML

    <HTML>

     <HEAD>

      <TITLE>

       The Planets Table

      </TITLE>

      <XML id="sourceDocument" src="planets.xml"></XML>

      <XML id="stylesheet" src="planets.xsl"></XML>

      <SCRIPT FOR="window" EVENT="onload">

       targetDIV.innerHTML =

        sourceDocument.transformNode(stylesheet.XMLDocument);

      </SCRIPT>

     </HEAD>

     <BODY>

      <CENTER>

       <DIV id="targetDIV"></DIV>

      </CENTER>

     </BODY>

    </HTML>

    Вот и все. Заметьте, что по умолчанию Internet Explorer 5.5 и младше использует устаревший процессор XSLT, как обсуждалось в главе 2 (если специально не установить процессор MSXML3 в режиме замены или IE 6.0, о чем также говорилось в главе 2). Если вы работаете с IE 5.5 или младше, у вас в распоряжении таблица стилей Internet Explorer прежнего образца, в которой нет правил по умолчанию и в которой вам придется использовать старое пространство имен XSL, как в этом примере (листинг 10 5).

    Листинг 10.5. Таблица стилей Internet Explorer старого образца

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.1" 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>

    Как видите, при помощи JavaScript и XSLT в Internet Explorer можно сделать весьма многое. Дополнительную информацию можно подучить из руководства разработчика XSLT фирмы Microsoft, которое сейчас расположено по адресу http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/xmlsdk/xslp8tlx.htm.

    Пришло время рассмотреть взаимодействие XSLT с Java, начав с обращения к Java непосредственно из процессоров XSLT.

    Вызов Java непосредственно из процессоров XSLT

    Как мы говорили в главе 5, до недавнего времени процессоры XSLT могли реализовывать функции расширения любым способом, и один из этих способов включал прямой вызов функций Java. Например, в Saxon и Xalan можно выполнять код Java, если определить пространство имен, указывающее класс Java как последнюю часть своего URI — как в следующем примере, где я определил пространство имен

    Date
    , соответствующее классу Java
    Date
    :

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.1"

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

     xmlns:Date="http://www.saxon.com/java/java.util.Date">

     .

     .

     .

    Как вы видели в главе 5, это означает, что теперь вы можете применять такие функции Java, как

    toString
    и new, для встраивания текущей даты в заголовок HTML
    <Н1>
    , — например, так (листинг 10.6).

    Листинг 10.6. Работа с функциями класса Date Java

    <?xml version="1.0"?>

    <xsl:stylesheet version="1.1"

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

     xmlns:Date="http://www.saxon.com/java/java.util.Date">

     <xsl:template match="/PLANETS">

      <HTML>

       <HEAD>

        <TITLE>

         The Planets Table

        </TITLE>

       </HEAD>

       <BODY>

        <H1>

         The Planets Table

        </H1>

        <BR/>

        <H1>

         <xsl:value-of select="Date:toString(Date:new())"/>

        </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:template match="PLANET">

      <TR>

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

       <TD><xsl:apply-templates select="MASS"/></TD>

       <TD><xsl:apply-templates select="RADIUS"/></TD>

       <TD><xsl:applу-templates select="DAY"/></TD>

      </TR>

     </xsl:template>


     <xsl:template match="MASS">

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

     </xsl:template>


     <xsl:template match="RADIUS">

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

     </xsl:template>


     <xsl:template match="DAY">

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

     </xsl:template>

    </xsl:stylesheet>

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

    Каждый из процессоров XSLT Xalan, Saxon, XT и Oracle определяет API, к которому можно обращаться из Java. Достаточно только проверить, что нужные файлы JAR находятся в

    classpath
    Java. Мы уже рассматривали, как работать с файлами JAR и путями к классам, в главе 1; теперь мы перейдем к написанию кода на Java, а не просто выполнению предопределенных классов из командной строки. Код можно загрузить с http://www.newriders.com/books/title.cfm?isbn=0735711364, поэтому если вы не программист на Java, можете пропустить эту часть главы.

    Работа с API XSLT для Java

    Во всех основанных на Java процессорах XSLT определен объемный интерфейс, API, для связи с Java. Как правило, при помощи API вызываются методы и создаются объекты Java, как мы увидим в этой главе. Но все процессоры XSLT определяют свои API по-разному, и обычно эти API довольно велики, поскольку каждый процессор может создавать собственные иерархии классов по своему усмотрению. В следующих разделах мы пройдем по этапам создания XSLT-преобразований из Java с использованием процессоров XSLT Xalan, Saxon, XT и Oracle. Все их возможности описаны в документации. Заметьте, что описание API большинства этих процессоров может само занять отдельную книгу, потому наше обсуждение вынужденно представляет собой лишь краткий обзор.

    НАЗВАНИЯ ФАЙЛОВ JAVA

    В отличие от остальных примеров книги, при создании файлов Java имеет значение имя файла. Java требует, чтобы имя файла совпадало с именем содержащегося в файле открытого класса. По этой причине для каждого листинга я включил в заголовок имя используемого файла. Например, заголовок «Листинг 10.7, xalanjava.java, взаимодействие Xalan с Java» означает, что перед тем, как использовать код листинга вместе с Java, необходимо сохранить листинг как xalanjava.java (для простоты имена всех открытых классов и файлов Java я писал в нижнем регистре). Обратите внимание: если вы загрузили код книги, этот пример будет называться 10-07.java, и перед работой с ним вам нужно будет его переименовать в xalanjava.java. Кроме того, требуемое имя файла будет приведено в комментариях в начале каждого файла Java.

    Взаимодействие Xalan с Java

    Несмотря на свой размер, Xalan — один из простейших процессоров XSLT для взаимодействия с Java. В качестве примера я создал новый класс Java,

    xalanjava
    , и для осуществления XSLT-преобразования к нему положено обращаться следующим образом:

    C:\>java xalanjava planets.xml planets.xsl planets.html

    Чтобы создать XSLT-преобразование, я начну с создания объекта класса

    TransformerFactory
    в классе
    xalanjava
    :

    import javax.xml.transform.Transformer;

    import javax.xml.transform.TransformerFactory;

    import javax.xml.transform.stream.StreamSource;

    import javax.xml.transform.stream.StreamResult;

    import javax.xml.transform.TransformerException;

    import javax.xml.transform.TransformerConfigurationException;

    import java.io.FileOutputStream;

    import java.iо.FileNotFoundException;

    import java.io.IOException;


    public class xalanjava {

     public static void main(String[] args)

      throws TransformerException, TransformerConfigurationException,

      FileNotFoundException, IOException {

      TransformerFactory tFactory = TransformerFactory.newInstance();

      .

      .

      .

    Имена документа XML, документа XSL и результирующего документа были нам переданы в аргументах соответственно как

    args[0]
    ,
    args[1]
    и
    args[2]
    . На следующем шаге нужно загрузить документ XSL в новый созданный мной объект
    TransformerFactory
    . Для этого я создал объект
    StreamSource
    и передал его в метод
    newTransformer
    объекта
    TransformerFactory
    , чтобы создать новый объект
    Transformer
    :

    import javax.xml.transform.Transformer;

    .

    .

    .

    public class xalanjava {

     public static void main(String[] args)

      throws TransformerException, TransformerConfigurationException,

      FileNotFoundException, IOException {

      TransformerFactory tFactory = TransformerFactory.newInstance();

      Transformer transformer =

       tFactory.newTransformer(new StreamSource(args[1]));

      .

      .

      .

    Объект

    transformer
    реализует XSLT-преобразование. Для того чтобы выполнить такое преобразование, нужно вызвать метод
    transform
    этого объекта, передав ему соответствующий XML-документу объект
    StreamSource
    и соответствующий результирующему документу объект
    StreamResult
    :

    import javax.xml.transform.Transformer;

    .

    .

    .

    public class xalanjava {

     public static void main(String[] args)

      throws TransformerException, TransformerConfigurationException,

      FileNotFoundException, IOException {

      .

      .

      .

      transformer.transform(new StreamSource(args[0]),

       new StreamResult(new FileOutputStream(args[2])));

     }

    }

    Вот полный файл Java, xalanjava.java (листинг 10.7).

    Листинг 10.7. xalanjava.java, взаимодействие Xalan с Java

    import javax.xml.transform.Transformer;

    import javax.xml.transform.TransformerFactory;

    import javax.xml.transform.stream.StreamSource;

    import javax.xml.transform.stream.StreamResult;

    import javax.xml.transform.TransformerException;

    import javax.xml.transform.TransformerConfigurationException;

    import java.io.FileOutputStream;

    import java.io.FileNotFoundException;

    import java.io.IOException;


    public class xalanjava {

     public static void main(String[] args)

      throws TransformerException, TransformerConfigurationException,

      FileNotFoundException, IOException {

      TransformerFactory tFactory = TransformerFactory.newInstance();

      Transformer transformer =

       tFactory.newTransformer(new StreamSource(args[1]));

      transformer transform(new StreamSource(args[0]),

       new StreamResult(new FileOutputStream(args[2])));

     }

    }

    Чтобы скомпилировать файл

    xalanjava.java
    в
    xalanjava.class
    и выполнить этот класс, задайте
    classpath
    так, чтобы путь включал Xalan и разборщик XML, который вы обычно используете с Xalan, Xerces (о Xerces говорилось в главе 1, в том числе и о том, где его взять), — в Windows это будет выглядеть так (как всегда, пишите пути в соответствии со своей системой):

    C:\>set classpath=.;c:\xalan\xalan.jar;c:\xalan\xerces.jar

    Затем скомпилируйте

    xalanjava.java
    компилятором с Java,
    javac
    :

    C:\>javac xalanjava.java

    Здесь считается, что путь к

    javac.exe
    прописан, и его можно сразу активизировать из командной строки. (Как правило, компилятор Java javac.exe находится в каталоге Java bin — поэтому если путь к нему не задан, к нему можно обратиться, например, так:
    C:\>c:\jdk1.3\bin\javac xalanjava.java
    .) Компилятор Java создаст файл
    xalanjava.class
    , при помощи которого производится преобразование:

    C:\>java xalanjava planets.xml planets.xsl planets.html

    При этом из файлов

    planets.xml
    и
    planets.xsl
    будет создан файл
    planets.html
    — здесь я его создал при помощи своего собственного класса Java.

    РАБОТА С ПАКЕТОМ JAXP ФИРМЫ SUN ДЛЯ XSLT

    Фирма Sun, создатель Java, обладает пакетом Java для обработки XML, JAXP, который можно загрузить с http://java.sun.com/xml. JAXP способен также осуществлять XSLT-преобразования. Но я не буду отдельно рассматривать JAXP в текущей главе, поскольку этот пакет (по крайней мере, сейчас) для всех своих преобразований использует Xalan, поставляемый в xalan.jar. Значит, предыдущий пример, листинг 10.7, без всяких изменений можно использовать с пакетом JAXP.

    Взаимодействие Saxon с Java

    Процессор Saxon также определяет API для работы с Java, но, конечно, в деталях этот прикладной интерфейс отличается от API Xalan. Для демонстрации создания преобразований при помощи Saxon API версии 6.0.2 я создам новый класс Java

    saxonjava
    . Начать нужно с создания нового объекта
    XSLTProcessor
    , вызвав метод
    newInstance
    класса
    Processor
    в файле
    saxonjava.java
    :

    import java.io.*;

    import org.xml.sax.*;

    import org.w3c.dom.*;

    import com.icl.saxon.trax.*:


    public class saxonjava {

     public static void main(String args[])

      throws ProcessorException, ProcessorFactoryException,

      TransformException, SAXException, IOException {

      Processor processor = Processor.newInstance("xslt");

      .

      .

      .

    Затем необходимо создать объект

    Templates
    на основе таблицы стилей XSL, которую мы хотим применить, хранимой в
    args[1]
    . Это можно сделать при помощи класса
    InputSource
    :

    import java.io.*;

    .

    .

    .

    public class saxonjava {

     public static void main(String args[])

      throws ProcessorException, ProcessorFactoryException,

      TransformException, SAXException, IOException {

      Processor processor = Processor.newInstance("xslt");

      Templates templates =

       processor.process(new InputSource(args[1]));

      .

      .

      .

     }

    }

    При помощи нового объекта

    Templates
    можно создать объект
    Transformer
    , который в действительности делает работу:

    import java.io.*;

    .

    .

    .

    public class saxonjava {

     public static void main(String args[])

      throws ProcessorException, ProcessorFactoryException,

      TransformException, SAXException, IOException {

      Processor processor = Processor.newInstance("xslt");

      Templates templates =

       processor.process(new InputSource(args[1]));

      Transformer transformer = templates.newTransformer();

      .

      .

      .

     }

    }

    Наконец, чтобы осуществить XSLT-преобразование, нужно вызвать метод

    transform
    объекта
    transformer
    , записывая результат в выходной документ при помощи объекта
    FileWriter
    (листинг 10.8).

    Листинг 10.8. saxonjava.java, взаимодействие Saxon с Java

    import java.io.*;

    import org.xml.sax.*;

    import org.w3c.dom.*;

    import com.icl.saxon.trax.*;


    public class saxonjava {

     public static void main(String args[])

      throws ProcessorException, ProcessorFactoryException,

      TransformException, SAXException, IOException {

      Processor processor = Processor.newInstance("xslt");

      Templates templates =

       processor.process(new InputSource(args[1]));

      Transformer transformer = templates.newTransformer();

      transformer.transform(new InputSource(args[0]),

       new Result(new FileWriter(args[2])));

     }

    }

    Чтобы скомпилировать и использовать новый класс

    saxonjava
    , нужно установить
    classpath
    так, чтобы переменная включала путь к
    saxon.jar
    :

    С:\>set сlasspath=.;с:\saxon\saxon.jar

    Затем при помощи компилятора Java,

    javac
    , создается
    saxonjava.class
    .

    Как и многие использующие API процессоры XSLT, Saxon ожидает, что ему будут переданы URL документов, с которыми вы хотите работать, — что я и делаю на следующем шаге:

    C:\>java saxonjava http://www.starpowder.com/planets.xml http://www.starpowder.com/planets.xsl planets.html

    Таким образом, создается

    planets.html
    , как и раньше. Заметьте, что если документы расположены локально, можно использовать URL файла. Например, в Windows, если документ XML расположен в
    c:\XSL\saxonjava\planets.xml
    , а документ XSL в
    c:\XSL\saxonjava\planets.xsl
    , можно выполнить такую командную строку:

    C:\>java saxonjava file:///XSL/saxonjava/planets.xml file:///XSL/saxonjava/planets.xsl planets.html

    ПРЕОБРАЗОВАНИЕ ИМЕН ФАЙЛОВ В URL

    Если вам больше нравится писать в командной строке имена файлов, а не URL, имена можно преобразовывать в URL в коде. Для этого необходимо передать полный путь к файлу в класс Java URL, а путь можно получить методом getAbsolutePath класса File: File file = new File(filename); String fullpath = file.getAbsolutePath();.

    В этом примере мы работали с Saxon версии 6.0.2, о котором на web-узле Saxon говорится как о вполне надежной версии, но на момент написания книги появилась новая, полностью не протестированная версия Saxon 6.2.2. (Не существовало версии Saxon 6.1.x.) В последней версии Saxon, кажется, собирается вернуться к той же модели API, которую использует Xalan, и код, работоспособный в версии 6.0.2, не будет работать в версии 6.2.2 (сюрприз!). Ниже приведен код

    saxonjava.java
    для версии 6.2.2 — проверьте, что при работе с этим кодом вы включили в
    classpath
    новую версию
    saxon.jar
    , и обратите внимание на то, что при его выполнении вам нужно передавать не URL файлов, а только их имена. Этот код идентичен показанному ранее
    xalanjava.java
    , за исключением имени класса,
    saxonjava
    :

    import javax.xml.transform.Transformer;

    import javax.xml.transform.TransformerFactory;

    import javax.xml.transform.stream.StreamSource;

    import javax.xml.transform.stream.StreamResult;

    import javax.xml.transform.TransformerException;

    import javax.xml.transform.TransformerConfigurationException;

    import java.io.FileOutputStream;

    import java.io.FileNotFoundException;

    import java.io.IOException;


    public class saxonjava {

     public static void main(String[] args)

      throws TransformerException, TransformerConfigurationException,

      FileNotFoundException, IOException {

      TransformerFactory tFactory = TransformerFactory.newInstance();

      Transformer transformer =

       tFactory.newTransformer(new StreamSource(args[1]));

      transformer transform(new StreamSource(args[0]),

       new StreamResult(new FileOutputStream(args[2])));

     }

    }

    Взаимодействие процессора XSLT Oracle с Java

    Несколько больше усилий потребуется для осуществления XSLT-преобразования при помощи API процессора XSLT фирмы Oracle. Новый пример,

    oraclejava.java
    , продемонстрирует работу с этим API.

    В

    oraclejava.java
    в первую очередь необходимо считывать требуемые документы при помощи объекта
    DOMParser
    :

    import org.w3c.dom.*;

    import java.util.*;

    import java.io.*;

    import java.net.*;

    import oracle.xml.parser.v2.*;


    public class oraclejava {

     public static void main (String args[]) throws Exception {

      DOMParser parser;

      try {

       parser = new DOMParser();

       parser.setPreserveWhitespace(true);

       .

       .

       .

    Затем, чтобы считать исходный документ XML и документ таблицы стилей XSLT, нужно преобразовать их URL в объекты

    URLJava
    при помощи метода
    parse
    объекта
    parser
    . После этого я вызываю метод разборщика
    getDocument
    , для того чтобы извлечь и сохранить документы XML и XSLT в объектах
    XMLDocument
    :

    public class oraclejava {

     public static void main (String args[]) throws Exception {

      DOMParser parser;

      XMLDocument xmldoc, xsldoc;

      URL xslURL;

      URL xmlURL;

      try {

       parser = new DOMParser();

       parser.setPreserveWhitespace(true);

       xmlURL = new URL(args[0]);

       parser.parse(xmlURL);

       xmldoc = parser.getDocument();

       xslURL = new URL(args[1]);

       parser.parse(xslURL);

       xsldoc = parser.getDocument();

       .

       .

       .

    В этот момент

    planets.xml
    и
    planets.xsl
    заключены в объекты
    XMLDocument
    . Для выполнения преобразования мне необходимы еще объекты
    XSLStylesheet
    и
    XSLProcessor
    для таблицы стилей XSLT. Фактическое преобразование XSLT осуществляется методом
    processXSL
    объекта
    parser
    , возвращающего фрагмент документа:

    public class oraclejava {

     public static void main (String args[]) throws Exception {

      DOMParser parser;

      .

      .

      .

      xslURL = new URL(args[1]);

      parser.parse(xslURL);

      xsldoc = parser.getDocument();

      XSLStylesheet xslstylesheet = new XSLStylesheet(xsldoc, xslURL);

      XSLProcessor processor = new XSLProcessor();

      DocumentFragment docfragment =

       processor.processXSL(xslstylesheet, xmldoc);

      .

      .

      .

    Этот код завершает преобразование. Теперь задача состоит в том, чтобы преобразовать данный фрагмент документа в документ XML, который можно записать на диск, — для чего я и создам новый XML-документ,

    newdoc
    , и вставлю фрагмент документа в корень нового документа:

    import org.w3c.dom.*;

    .

    .

    .

    public class oraclejava {

     public static void main (String args[]) throws Exception {

      DOMParser parser;

      XMLDocument xmldoc, xsldoc, newdoc;

      URL xslURL;

      URL xmlURL;

      try {

       .

       .

       .

       DocumentFragment docfragment =

        processor processXSL(xslstylesheet, xmldoc);

       newdoc = new XMLDocument();

       Element rootElement = newdoc.createElement("root");

       newdoc.appendChild(rootElement);

       rootElement.appendChild(docfragment);

       .

       .

       .

    Теперь осталось только сохранить на диске новый XML-документ с именем, заданным в

    args[2]
    . В этих целях я использую объект
    FileOutputStream
    , и вот полный код (листинг 10.9). 

    Листинг 10.9. oraclejava.java, взаимодействие процессора XSLT Oracle с Java

    import org.w3c.dom.*;

    import java.util.*;

    import java.io.*;

    import java.net.*;

    import oracle.xml.parser.v2.*;


    public class oraclejava {

     public static void main (String args[]) throws Exception {

      DOMParser parser;

      XMLDocument xmldoc, xsldoc, newdoc;

      URL xslURL;

      URL xmlURL;

      try {

       parser = new DOMParser();

       parser.setPreserveWhitespace(true);

       xmlURL = new URL(args[0]);

       parser.parse(xmlURL);

       xmldoc = parser.getDocument();

       xslURL = new URL(args[1]);

       parser.parse(xslURL);

       xsldoc = parser.getDocument();

       XSLStylesheet xslstylesheet = new XSLStylesheet(xsldoc, xslURL);

       XSLProcessor processor = new XSLProcessor();

       DocumentFragment docfragment =

        processor.processXSL(xslstylesheet, xmldoc);

       newdoc = new XMLDocument();

       Element rootElement = newdoc.сreateElement("root");

       newdoc.appendChild(rootElement);

       rootElement.appendChild(docfragment);

       OutputStream out = new FileOutputStream(args[2]);

       newdoc.print(out);

       out.close();

      } catch (Exception e) {}

     }

    }

    На этом

    oraclejava.java
    заканчивается. Чтобы скомпилировать пример, включите в
    classpath
    путь к разборщику XML процессора XSLT Oracle,
    xmlparserv2.jar
    :

    C:\>set classpath=.;c:\oraclexml\lib\xmlparserv2.jar

    Затем скомпилируйте

    oraclejava.java
    , как мы это уже делали, компилятором Java
    javac
    . Для выполнения XSLT-преобразований нужно указать URL документов, с которыми вы хотите работать (если документы локальны, можно указать URL файлов, как и раньше):

    C:\>java oraclejava http://starpowder.com/planets.xml http://starpowder.com/planets.xsl planets.html

    Взаимодействие XT с Java

    Процессор XT также может работать с Java. API XT спроектирован для работы с классами, определенными в Project X TR2 фирмы Sun, которые поддерживают обработку XML. Вам будет необходим файл

    xml.jar
    фирмы Sun, который можно получить, загрузив Project X TR2. Чтобы получить
    xml.jar
    , необходимо зарегистрироваться на web-узле разработчиков Sun, http://developer.java.sun.com, что, к счастью, бесплатно, хотя и потребует от вас заполнения изрядного количества форм.

    Файл

    xml.jar
    нужен для класса
    com.sun.xml.tree.XmlDocument
    . Этот класс поддерживает XML-документы, и я начну свой новый пример,
    xtjava.java
    , с создания нового объекта
    XmlDocument
    для исходного документа, таблицы стилей XSLT и результирующего документа:

    import java.io.IOException;

    import java.io.OutputStream;

    import java.io.FileOutputStream;

    import org.xml.sax.SAXException;

    import com.sun.xml.tree.XmlDocument;

    import com.jclark.xsl.dom.Transform;

    import com.jclark.xsl.dom.TransformEngine;

    import com.jclark.xsl.dom.TransformException;

    import com.jclark.xsl.dom.XSLTransformEngine;


    class xtjava {

     public static void main(String[] args)

      throws IOException. SAXException, TransformException {

      XmlDocument XMLdoc =

       new XmlDocument().createXmlDocument(args[0]);

      XmlDocument XSLdoc =

       new XmlDocument().createXmlDocument(args[1]);

      XmlDocument newdoc = new XmlDocument();

      .

      .

      .

    После этого я создаю объект

    XSLTranformationEngine
    и вызываю его метод
    createTransform
    для создания нового объекта
    Transform
    на основе таблицы стилей
    XSLT
    :

    import java.io.IOException;

    .

    .

    .

    class xtjava {

     public static void main(String[] args)

      throws IOException, SAXException, TransformException {

      XmlDocument doc = new XmlDocument();

      XSLTransformEngine transformEngine = new XSLTransformEngine();

      Transform transform = transformEngine.createTransform(XSLdoc);

      .

      .

      .

    Затем я могу преобразовать XML-документ в объект результирующего документа следующим способом:

    import java.io.IOException;

    .

    .

    .

    class xtjava {

     public static void main(String[] args)

      throws IOException, SAXException, TransformException {

      XmlDocument XMLdoc =

       new XmlDocument().createXmlDocument(args[0]);

      XmlDocument XSLdoc =

       new XmlDocument().createXmlDocument(args[1]);

      XmlDocument newdoc = new XmlDocument();

      XSLTransformEngine transformEngine = new XSLTransformEngine();

      Transform transform = transformEngine.createTransform(XSLdoc);

      transform transform(XMLdoc, newdoc);

      .

      .

      .

    Так завершается преобразование. Осталось только записать результирующий документ,

    newdoc
    , на диск, что можно сделать при помощи объекта
    FileOutputStream
    (листинг 10.10).

    Листинг 10.10. xtjava.java, взаимодействие XT с Java

    import java.io.IOException;

    import java.io.OutputStream;

    import java.io.FileOutputStream;

    import org.xml.sax.SAXException;

    import com.sun.xml.tree.XmlDocument;

    import com.jclark.xsl.dom.Transform;

    import com.jclark.xsl.dom.Transform Engine;

    import com.jclark.xsl.dom.TransformException;

    import com.jclark.xsl.dom.XSLTransformEngine;


    class xtjava {

     public static void main(String[] args)

      throws IOException, SAXException, TransformException {

      XmlDocument XMLdoc =

       new XmlDocument().createXmlDocument(args[0]);

      XmlDocument XSLdoc =

       new XmlDocument().createXmlDocument(args[1]);

      XmlDocument newdoc = new XmlDocument();

      XSLTransformEngine transformEngine = new XSLTransformEngine();

      Transform transform = transformEngine.createTransform(XSLdoc);

      transform.transform(XMLdoc, newdoc);

      OutputStream out = new FileOutputStream(args[2]);

      newdoc.write(out);

      out.close();

     }

    }

    Чтобы запустить пример, включите

    xt.jar
    и
    xml.jar
    в
    classpath
    :

    C:\>set classpath=.;d:\xt\xt.jar;xml.jar

    Скомпилируйте теперь

    xtjava.java
    компилятором Java
    javac
    и запустите на выполнение следующим образом, передав URL документов XML и XSL (можно передать и URL файлов, как было показано ранее):

    C:\>java xtjava http://www.starpowder.com/planets.xml http://www.starpowder.com/planets.xsl planets.html

    Теперь все сделано.

    Преобразование XML в реляционную базу данных

    При обсуждении дополнительных возможностей XSLT стоит упомянуть элементы расширения SQL процессора Saxon. Через драйвер Java Database Connectivity (JDBC) можно работать с реляционными базами данных. Мы уже рассмотрели преобразования из XML в XML, в простой текст, в RTF, в JavaScript и т.д. Теперь пришла очередь преобразованию XML в реляционную базу данных.

    РАБОТА С ИНТЕРПРЕТИРУЕМЫМ SAXON

    Обратите внимание: для связи с базами данных через JDBC нельзя использовать исполняемый файл для Windows saxon.exe. Нужно запустить реализующий Saxon класс Java com.id.saxon.StyleSheet, как я сделаю в конце примера. 

    В примере я передам данные

    planets.xml
    в базу данных формата Microsoft Access
    planets.mdb
    . Если вы хотите повторить пример, создайте этот файл базы данных, в нем — таблицу
    planets
    с четырьмя текстовыми полями
    Name
    ,
    Mass
    ,
    Radius
    и
    Day
    , а оставшуюся часть файла оставьте пустой. В Windows я зарегистрирую этот файл базы данных в качестве источника ODBC с именем «planets» через значок Data Sources (ODBC) (Источники данных (ODBC)) в панели управления (в Windows 2000 он расположен в панели управления в папке Administrative Tools (Администрирование)). При запуске пример считает данные планет из
    planets.xml
    и добавит их в файл базы данных,
    planets.mdb
    .

    Для подключения к этой базе данных через JDBC я применил элемент

    <sql:connect>
    процессора Saxon. Префикс пространства имен
    sql
    определяется в Saxon следующим образом:

    <xsl:stylesheet

     xmlns:sql="http://icl.com/saxon/extensions/com.icl.saxon.sql.SQLElementFactory"

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

     .

     .

     .

    Для фактического подключения к источнику данных

    planets
    служит элемент расширения
    <sql:connect>
    с атрибутами
    database
    ,
    user
    ,
    password
    и
    driver
    . Для работы через JDBC установите атрибут
    driver
    в «
    sun.jdbc.odbc.JdbcOdbcDriver
    », атрибут
    database
    — в источник данных
    ODBC
    , «
    jdbc:odbc:planets
    », а атрибуты
    user
    и
    password
    — в имя пользователя и пароль, нужные для подключения к базе данных. Здесь нам не требуется задавать имя пользователя и пароль, но я задал этим параметрам шаблонные значения, так как они требуются в большинстве приложений баз данных:

    <xsl:stylesheet

     xmlns:sql="http://icl.com/saxon/extensions/com.icl.saxon.sql.SQLElementFactory"

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

     <xsl:param name="database" select="'jdbc:odbc:planets'"/>

     <xsl:param name="user"/>

     <xsl:param name="password"/>

     <xsl:template match="PLANETS">

      <sql:connect database="{$database}" user="{$user}"

       password="{$password}" driver="sun.jdbc.odbc.JdbcOdbcDriver"

       xsl:extension-element-prefixes="sql"/>

      <xsl:apply-templates select="PLANET"/>

     </xsl:template>

     .

     .

     .

    Затем я подключаюсь к источнику данных

    planets
    . Я хочу вставить в базу данных данные из каждого элемента
    <PLANET>
    , для чего я создаю новый шаблон, который выбирает элементы
    <PLANET>
    и вставляет данные в таблицу
    planets
    базы данных при помощи элемента Saxon
    <sql:insert>
    :

    <xsl:stylesheet

     xmlns:sql="http://icl.com/saxon/extensions/com.icl.saxon.sql.SQLElementFactory"

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

     .

     .

     .

     <xsl:template match="PLANETS">

      <sql:connect database="{$database}" user="{$user}"

       password="{$password}" driver="sun.jdbc.odbc.JdbcOdbcDriver"

       xsl:extension-element-prefixes="sql"/>

      <xsl:apply-templates select="PLANET"/>

     </xsl:template>


     <xsl:template match="PLANET">

      <sql:insert table="planets" xsl:extension-element-prefixes="sql">

       .

       .

       .

      </sql:insert>

     </xsl:template>

    </xsl:stylesheet>

    Элемент

    <sql:insert>
    вставляет в базу данных новую запись. Чтобы присвоить ее полям новые данные, используйте элемент
    <sql:column>
    , установив его атрибут name в имя столбца, в который вы хотите записать данные, и присвоив эти данные атрибуту
    select
    :

    <xsl:stylesheet

     xmlns:sql="http://icl.com/saxon/extensions/com.icl.saxon.sql.SQLElementFactory"

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

     .

     .

     .

     <xsl:template match="PLANET">

      <sql:insert table="planets" xsl:extension-element-prefixes="sql">

       <sql:column name="Name" select="NAME"/>

       <sql:column name="Mass" select="MASS"/>

       <sql:column name="Radius" select="RADIUS"/>

       <sql:column name="Day" select="DAY"/>

      </sql:insert>

     </xsl:template>

    </xsl:stylesheet>

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

    planets.xml
    , Земле, не будут отправлены в базу данных. Чтобы сбросить буферы данных, я явно вызываю шаблон
    <PLANET>
    как именованный шаблон, применяя
    <sql:insert>
    с данными-заглушкой (листинг 10.11).

    Листинг 10.11. Работа с реляционной базой данных

    <xsl:stylesheet

     xmlns:sql="http://icl.com/saxon/extensions/com.icl.saxon.sql.SQLElementFactory"

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

     <xsl:param name="database" select="'jdbc:odbc:planets'"/>

     <xsl:param name="user"/>

     <xsl:param name="password"/>

     <xsl:template match="PLANETS">

      <sql:connect database="{$database}" user="{$user}"

       password="{$password}" driver="sun.jdbc.odbc.JdbcOdbcDriver"

       xsl:extension-element-prefixes="sql"/>

      <xsl:apply-templates select="PLANET"/>

      <xsl:call-template name="writer"/>

     </xsl:template>


     <xsl:template match="PLANET" name="writer">

      <xsl:choose>

       <xsl:when test="NAME">

        <sql:insert table="planets"

         xsl:extension-element-prefixes="sql">

         <sql:column name="Name" select="NAME"/>

         <sql:column name="Mass" select="MASS"/>

         <sql:column name="Radius" select="RADIUS"/>

         <sql:column name="Day" select="DAY"/>

        </sql:insert>

       </xsl:when>

       <xsl:otherwise>

       <sql:insert table="planets"

        xsl:extension-element-prefixes="sql">

        <sql:column name="Name" select="' '"/>

        <sql:column name="Mass" select="' '"/>

        <sql:column name="Radius" select="' '"/>

        <sql:column name="Day" select="' '"/>

       </sql:insert>

      </xsl:otherwise>

     </xsl:choose>

    </xsl:template>

    </xsl:stylesheet>

    Эта таблица стилей правильно добавляет три записи в базу данных

    planets.mdb
    : по одной новой записи для каждой из планет. Как я говорил, здесь нельзя использовать готовый исполняемый файл
    saxon.exe
    , нужно применять класс Java
    com.icl.saxon.StyleSheet
    . Сначала нужно включить в
    classpath
    файл
    saxon.jar
    :

    C:\>set classpath=.;c:\saxon\saxon.jar

    После этого я могу передать в класс

    com.icl.saxon.StyleSheet
    файл
    planets.xml
    и таблицу стилей из листинга 10.11:

    C:\>java com.icl.saxon.StyleSheet planets.xml saxonsql.xsl

    Теперь все сделано — данные планет вставлены в

    planets.mdb
    . Результаты применения этой таблицы стилей показаны на рис. 10.4, где я открыл
    planets.mdb
    в Microsoft Access. Таким образом, мы рассмотрели преобразование из XML в реляционную базу данных.

    Рис. 10.4. Применение расширений SQL Saxon


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

    planets.xml
    при помощи
    planets.xsl
    с использованием активных серверных страниц (Active Server Pages, ASP) фирмы Microsoft, серверных страниц Java (Java Server Pages, JSP) фирмы Sun и сервлетов (servlet) Java, выполняющихся на web-серверах и возвращающих результирующий документ браузеру пользователя.

    За недостатком места мы не можем подробно рассмотреть эти технологии, и если вы с ними не знакомы, вы можете получить дополнительную информацию в Интернете (как всегда, URL могут измениться):

    • ASP. http://msdn.microsoft.com/workshop/c-frame.htm#/workshop/server/Default.asp (руководство и документация по ASP фирмы Microsoft);

    • JSP. http://java.sun.com/products/jsp/ (главная страница Sun, посвященная JSP);

    • Сервлеты. http://java.sun.com/products/servlet/ (главная страница Sun, посвященная сервлетам).

    Применение XSLT с активными серверными страницами

    Активные серверные страницы (Active Server Pages, ASP) выполняются на серверах Microsoft Windows NT или 2000, поэтому в ближайшем примере для преобразования

    planets.xml
    при помощи
    planets.xsl
    и возврата результата в виде документа HTML я воспользуюсь процессором Microsoft MSXML.

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

    text/html
    », поэтому он будет трактоваться как HTML:

    <%@LANGUAGE="VBScript"%>

    <%

     Response.ContentType = "text/html"

     .

     .

     .

    Затем, во многом аналогично предыдущим примерам в этой главе с JavaScript, я создаю два объекта документа MSXML, один для документа XML, а другой — для документа XSL:

    <%@LANGUAGE="VBScript"%>

    <%

     Response.ContentType = "text/html"

     Dim docXML

     Dim docXSL

     Set docXML = Server.CreateObject("MSXML2.DOMDocument.3.0")

     Set docXSL = Server.CreateObject("MSXML2.DOMDocument.3.0")

     .

     .

     .

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

    MapPath
    объекта Server. В данном случае я поместил
    planets.xml
    и
    planets.xsl
    в тот же каталог, что и сценарий ASP, поэтому документы загружаются так:

    <%@LANGUAGE="VBScript"%>

    <%

     Response.ContentType = "text/html"

     Dim docXML

     Dim docXSL

     Set docXML = Server.CreateObject("MSXML2.DOMDocument.3.0")

     Set docXSL = Server.CreateObject("MSXML2.DOMDocument.3.0")

     docXML.ValidateOnParse = True

     docXSL.ValidateOnParse = True

     docXML.load Server.MapPath("planets.xml")

     docXSL.load Server.MapPath("planets.xsl")

     .

     .

     .

    Теперь нам осталось только применить метод

    transformNode
    (как в примере с JavaScript раньше) для выполнения XSLT-преобразования и вывода результатов (листинг 10.12). 

    Листинг 10.12. XSLT на сервере с применением ASP

    <%@LANGUAGE="VBScript"%>

    <%

     Response.ContentType = "text/html"

     Dim docXML

     Dim docXSL

     Set docXML = Server.CreateObject("MSXML2.DOMDocument.3.0")

     Set docXSL = Server.CreateObject("MSXML2.DOMDocument.3.0")

     docXML.ValidateOnParse = True

     docXSL.ValidateOnParse = True

     docXML.load Server.MapPath("planets.xml")

     docXSL.load Server.MapPath("planets.xsl")

     strOutput = docXML.transformNode(docXSL)

     Response.Write strOutput

    %>

    Результат этого преобразовании ASP показан на рис. 10.5. Теперь вы научились выполнению XSLT-преобразований на web-серверах.

    Рис. 10.5. Применение XSLT с ASP


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

    http_user_agent
    чтобы определить, использует ли клиент Internet Explorer) следующим образом: 

    <%@LANGUAGE="VBScript"%>

    <%

     Response ContentType = "text/html"

     If instr(request,servervariables("http_user_agent"), "MSIE") = 0 then

      Response.Write "Sorry, not optimized for your device."

      Response.End

     End If

     .

     .

     .

    ОТДЕЛЕНИЕ ДАННЫХ ОТ ИХ ПРЕДСТАВЛЕНИЯ

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

    Применение XSLT с Java Server Pages

    Для работы с активными серверными страницами я использовал процессор MSXML фирмы Microsoft, но серверные страницы Java (Java Server Pages, JSP) не обязаны выполняться на серверах на платформе Windows, поэтому с JSP я не использую MSXML. Для выполнения XSLT-преобразования и отправки результатов в браузер клиента я воспользуюсь API процессора Xalan для работы с Java.

    Например, при помощи Xalan можно создать

    planets.html
    на сервере как временный документ (этот код предполагает, что
    planets.xml
    и
    planets.xsl
    расположены в том же каталоге, что и сценарий JSP) таким образом:

    <%@ page errorPage="error.jsp" language="java"

     contentType="text/html" import="org.apache.xalan.xslt.*;java.iо.*" %>

    <%

     try {

      XSLTProcessor processor = XSLTProcessorFactory.getProcessor();

      processor.process(new XSLTInputSource("planets.xml"),

       new XSLTInputSource("planets.xsl"),

       new XSLTResultTarget("planets.html"));

     } catch(Exception e) {}

     .

     .

     .

    Теперь все, что нужно сделать, — это открыть документ и отправить его обратно клиенту (листинг 10.13).

    Листинг 10.13. XSLT на сервере с применением JSP

    <%@ page errorPage="error.jsp" language="java"

     contentType="text/html" import="org.apache.xalan.xslt.*;java.iо.*" %>

    <%

     try {

      XSLTProcessor processor = XSLTProcessorFactory.getProcessor();

      processor.process(new XSLTInputSource("planets.xml"),

       new XSLTInputSource("planets.xsl"),

       new XSLTResultTarget("planets.html"));

     } catch(Exception e) {}

     FileReader filereader = new FileReader("planets.html");

     BufferedReader bufferedreader = new BufferedReader(filereader);

     String instring;

     while((instring = bufferedreader.readLine()) != null) { %>

      <%= instring %>

     <% } 

     filereader.close();

     pw.close();

    %>

    Теперь все готово. Результаты применения этого сценария JSP показаны на рис. 10.6.

    Рис. 10.6. Применение XSLT с JSP

    Применение XSLT с сервлетами Java

    Выполнять XSLT-преобразования на сервере можно также при помощи сервлетов (servlet) Java. Хотя многие процессоры XSLT предоставляют свои собственные версии сервлетов, я считаю, что гораздо проще самостоятельно выполнить преобразование при помощи Xalan или другого процессора XSLT и затем обработать результирующий документ и отправить его обратно клиенту.

    В следующем примере я при помощи Xalan преобразую

    planets.xml
    во временный файл
    planets.html
    , применяя
    planets.xsl
    в сервлете:

    import java.net.*;

    import java.sql.*;

    import java.awt.*;

    import java.awt.event.*;

    import java.io.*;

    import javax.servlet.*;

    import org.apache.xalan.xslt.*;


    public class xslservlet extends GenericServlet {

     public void service(ServletRequest request, ServletResponse response)

      throws ServletException, IOException {

      try {

       XSLTProcessor processor = XSLTProcessorFactory.getProcessor();

       processor.process(new XSLTInputSource("planets.xml"),

        new XSLTInputSource("planets.xsl"),

        new XSLTResultTarget("planets.html"));

      } catch(Exception e) {}

      .

      .

      .

    Все, что осталось, — отправить HTML-документ обратно клиенту (листинг 10.14).

    Листинг 10.14. Применение XSLT на сервере с сервлетами Java

    import java.net.*;

    import java.sql.*;

    import java.awt.*;

    import java.awt.event.*;

    import java.io.*;

    import javax.servlet.*;

    import org.apache.xalan.xslt.*;


    public class xslservlet extends GenericServlet {

     public void service(ServletRequest request, ServletResponse response)

      throws ServletException.IOException {

      response.setContentType("text/html");

      PrintWriter pw = response.getWriter();

      try {

       XSLTProcessor processor = XSLTProcessorFactory.getProcessor();

       processor.process(new XSLTInputSource("planets.xml"),

        new XSLTInputSource("planets.xsl"),

        new XSLTResultTarget("planets.html"));

      } catch(Exception e) {}

      FileReader filereader = new FileReader("planets.html");

      BufferedReader bufferedreader = new BufferedReader(filereader);

      String instring;

      while((instring = bufferedreader.readLine()) != null) {

       pw.println(instring);

      }

      filereader.close();

      pw.close();

     }

    }

    Теперь все сделано, результат показан на рис. 10.7 — HTML-документ, переданный из сервлета.

    Рис. 10.7. Применение XSLT с сервлетами Java


    На этом мы заканчиваем изучение работы с API процессоров XSLT в программном коде. Мы рассмотрели весьма объемный материал: как взаимодействовать с API процессоров XSLT из JavaScript и Java для процессоров MSXML, Xalan, XT, Saxon и Oracle, а также примеры выполнения XSLT-преобразований на web-серверах при помощи ASP, JSP и сервлетов Java.







     


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