|
||||
|
Глава 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 и 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() { . . . }
(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 находятся в classpathJava. Мы уже рассматривали, как работать с файлами 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 большинства этих процессоров может само занять отдельную книгу, потому наше обсуждение вынужденно представляет собой лишь краткий обзор.
Взаимодействие 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 с Javaimport 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.
Взаимодействие 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
В этом примере мы работали с 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 в реляционную базу данных.
В примере я передам данные 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"));
. . . Теперь все, что нужно сделать, — это открыть документ и отправить его обратно клиенту (листинг 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"));
. . . Все, что осталось, — отправить HTML-документ обратно клиенту (листинг 10.14). Листинг 10.14. Применение XSLT на сервере с сервлетами Javaimport 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 | Добавить материал | Нашёл ошибку | Наверх |
||||
|