Разработка веб-служб средствами Java. Ильдар ХабибуллинРазработкаWebслужбсредствами
Скачать 9.24 Mb.
|
Другие языки описания схем Даже из приведенного выше краткого описания языка XSD видно, что он получился весьма сложным и запутанным. Есть уже несколько книг, полно- стью посвященных этому языку. Их объем ничуть не меньше объема этой Есть и другие, более простые языки описания схемы документа XML. Наи- большее распространение получили следующие языки: • Schematron — • RELAX NG (Regular Language Description for XML, New Generation, ре- гулярный язык описания XML нового поколения) — http://www.oasis- open.org/committees/relax-ng/; этот язык возник как слияние языков Relax и TREX, • Relax — TREX (Tree Regular Expressions for XML, древовидные регулярные выра- жения для XML) — • DDML (Document Definition Markup Language, язык размет- ки определения документа), известный еще как — http://purl.oclc.org/NET/ddml/. Менее распространены языки DCD (Document Content Description, описа- ние содержания документа), SOX (One's Schema for Object-Oriented XML, схема для объектно-ориентированного XML), XDR (XML-Data Reduced, редуцированные Все эти языки позволяют более или менее полно описывать схему документа. Возможно, они вытеснят язык XSD, возможно, будут существовать совместно. Инструкции по обработке Упомянем еще одну конструкцию языка XML — инструкции по обработке (processing instructions). Инструкции по обработке позволяют передать ана- лизатору или другой программе-обработчику документа дополнительные сведения для обработки. Инструкция по обработке выглядит так: сведения для анализатора ?> 52 Разработка Web-служб средствами Java Первая часть пролога документа — первая строка XML-файла — это как раз инструкция по обработке. Она передает анализатору документа вер- сию языка XML и кодировку символов, которыми записан документ. Первая часть работы закончена. Документы XML и их схемы написаны. Те- перь надо подумать о том, каким образом они будут отображаться на экране дисплея, на листе бумаги, на экране сотового телефона, то есть, надо поду- мать о визуализации документа XML. Прежде всего, документ надо разобрать, проанализировать (parse) его структуру. Анализ документа На первом этапе разбора проводится лексический анализ (lexical parsing) до- кумента XML. Документ разбивается на отдельные неделимые элементы (tokens), которыми являются теги, служебные слова, разделители, текстовые константы. Проводится проверка полученных элементов и их связей между собой. Лексический анализ выполняют специальные программы — сканеры (scanners). Простейшие сканеры — это классы и java.io.streamTokenizer из стандартной поставки Java 2 SDK Standard Edition. Затем выполняется грамматический анализ (grammar parsing). При этом ана- лизируется логическая структура документа, составляются выражения, вы- ражения объединяются в блоки, блоки — в модули, которыми могут ся абзацы, параграфы, пункты, главы. Грамматический анализ проводят программы-анализаторы, так называемые парсеры (parsers). Создание сканеров и парсеров — любимое развлечение программистов. За недолгую историю написаны десятки, если не сотни XML-парсеров. Многие из них написаны на языке Java. Все парсеры можно разделить на две группы. В первую группу входят парсеры, проводящие анализ, основываясь на структуре дерева, отражающего вложенность элементов документа (tree- based parsing). Такие парсеры проще реализовать, но создание дерева тре- бует большого объема оперативной памяти, ведь размер документов XML не ограничен. Необходимость частого просмотра дерева замедляет работу парсера. Во вторую группу входят парсеры, проводящие анализ, основываясь на со- бытиях (event-based parsing). Событием считается появление какого-либо элемента XML: открывающего или закрывающего тега, текста, содержаще- гося в теле элемента. При возникновении события вызывается какой- нибудь метод его обработки: Глава 1. Обработка документов XML 53 Такие парсеры сложнее в реализации, зато они не строят дерево в опера- тивной памяти и могут анализировать не весь документ, а его отдельные элементы вместе с вложенными в них элементами. Фактическим стандартом здесь стал свободно распространяемый набор классов и интерфейсов SAX (Simple API for XML Parsing, простой API для анализа XML), созданный Давидом Меггинсоном (David Megginson). Основной сайт этого проекта http://www.saxproject.org/. Сейчас применяется второе поколение этого на- бора, называемое SAX2. Набор SAX2 входит во многие парсеры, например, Xerces2. В стандартную поставку Java 2 Standard Edition и Enterprise Edition вхо- дит JAXP — набор интерфейсов и классов для создания парсеров и пре- образования документов XML. С помощью одной из частей этого набо- ра, называемой DOM API (Document Object Model API, API объектной модели документов), можно создавать парсеры первого типа, создающие дерево объектов, а с помощью второй части набора JAXP, называемой API, можно создавать SAX-парсеры. Интерфейсы и классы SAX2 В пакеты Рассмотрим их подробнее. Анализ документов XML с помощью SAX2API Основу SAX2 составляет интерфейс ОПИСЫ- вающий методы обработки событий: начало документа, появление откры- вающего тега, появление тела элемента, появление закрывающего тега, окончание документа. При возникновении такого события SAX2 обращает- ся к методу-обработчику события, передавая ему аргументы, содержащие информацию о событии. Дело разработчика — реализовать эти методы, обеспечив правильный анализ документа. В начале обработки документа вызывается метод public void В нем можно задать начальные действия по обработке документа. При появлении символа начинающего открывающий тег, вызывается метод public void uri, String name, String Attributes attrs); В метод передается три имени, два из которых связаны с пространством имен: идентификатор пространства имен uri, имя тега без префикса name и расширенное имя с префиксом qname, а также атрибуты открывающего тега элемента a t t r s , если они есть. Если пространство имен не определено, то 54 Разработка Web-служб средствами Java значения первого и второго аргумента null. Если нет атрибутов, то переда- ется ссылка на пустой объект При появлении символов "", начинающих закрывающий тег, вызывается метод public void uri, String name, String При появлении строки символов вызывается метод public void int start, int length); В него передается массив символов индекс начала строки символов start в этом массиве и количество символов length. При появлении в тексте документа инструкции по обработке вызывается метод public void target, String data); В метод передается имя программы-обработчика target и дополнительные сведения data. При появлении пробельных символов, которые должны быть пропущены, вызывается метод public void ch, int start, int length); В него передается массив ch идущих подряд пробельных символов, индекс начала символов в массиве s t a r t и количество символов length. Интерфейс реализован org.xml.sax. В нем сделана пустая реализация всех методов. Разработчику остается реализовать только те методы, которые ему нужны. Применим методы SAX2 для обработки нашей адресной книжки. Запись документа на языке XML удобна для выявления структуры документа, но неудобна для работы с документом в объектно-ориентированной среде. По- этому чаще всего содержимое документа XML представляется в виде одного или нескольких объектов, называемых объектами данных JDO (Java Data Objects). Эта операция называется связыванием данных (data binding) с объек- тами Свяжем содержимое нашей адресной книжки с объектами Java. Для этого сначала опишем классы Java, которые представят содержимое адресной Листинг Класс, описывающий адрес public class Address) private String street, city, zip, type = "город"; Глава 1. Обработка документов XML 55 public {} public String getStreet(){ return street; } public void street){ = street; } public String getCity(){ return city; } public void city){ = city; } public String getZip(){ return zip; } public void zip){ = zip; } public String getType(){ return type; } public void type){ = type; } public String toString(){ return "Address: " + street + " " + city + " " + zip; Листинг 1.8. описывающий запись адресной книжки public class private String secondName, surname, birthday; private Vector address; private Vector private Vector public public firstName, String secondName, String surname){ = firstName; = secondName; surname; public String return firstName; } public void firstName){ Разработка Web-служб средствами Java = firstName; public String return } public void secondName){ = secondName; public String return surname; } public void = surname; public String return birthday; } public void birthday)) = birthday; public void addr){ if (address == null) address = new } public Vector return address; } public void addr){ if (address != null) public void phone){ if (workPhone == null) workPhone = new } public Vector return workPhone; } public void phone)( if (workPhone != null) Глава 1. Обработка документов XML 57 } public void phone)( if (homePhone = null) homePhone = new public Vector return homePhone; } public void phone){ if (homePhone != null) public String { return "Person: " + surname; После определения классов Java, в экземпляры которых будет занесено со- держимое адресной книжки, напишем программу, читающую адресную книжку и связывающую ее с объектами Java. В листинге 1.9 приведен пример класса-обработчика NotebookHandler для ад- ресной книжки, описанной в листинге 1.2. Методы класса NotebookHandler анализируют содержимое адресной книжки и помещают его в вектор, состав- ленный из объектов класса Person, описанного в листинге 1.8. Листинг 1.9. Класс-обработчик документа XML import import import import java.util.*; import j public class NotebookHandler extends DefaultHandler{ static final String = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; final String = Разработка Web-служб средствами Java "http://www.w3.org/2001/XMLSchema"; Person person; Address address; static Vector pers = new boolean inBirthday, inStreet, inCity, inZip, inWorkPhone, inHomePhone; public void uri, String name, String qname, Attributes attrs) throws SAXException{ if person = new , else if inBirthday = true; else if address = new else if inStreet = true; else if inCity = true; if (attrs null) }else if inZip = true; else if ) Глава 1. Обработка документов XML 59 = true; else if = true; } public void buf, int offset, int throws String s = new offset, len); if (inBirthday){ inBirthday = false; }else if (inStreet){ inStreet = false; }else if (inCity){ inCity = false; }else if (inZip){ inZip = false; }else if (inWorkPhone){ inWorkPhone = false; }else if (inHomePhone){ 60 Разработка Web-служб средствами Java inHomePhone = false; public void uri, String name, String throws SAXException{ if address = null; (else if person = null; public static void args){ if < 1){ Notebook ntb.xml"); } try{ NotebookHandler handler = new fact = SAXParserFactory.newInstance (); SAXParser saxParser = File f = new Глава 1. Обработка документов XML 61 handler); for (int к = 0; к < (); k++) x){ свойство: " + ex){ ; public void ex){ " + ex); " + + " col = " + public void ex){ " + ex); = " + + " col = " + public void ex){ error: " + ex); " + " col = " + 62 Разработка Web-служб средствами Java После того как класс-обработчик написан, проанализировать документ очень легко. Стандартные действия приведены в методе о программы листинга 1.9. Поскольку реализация парсера сильно зависит от его программного окру- жения, — объект класса SAXParser — создается не конструкто- ром, а фабричным методом () . Объект-фабрика, в свою очередь, создается методом (). После создания объекта-фабрики можно методом void setFeature(String name, boolean value) установить свойства парсеров, создаваемых этой фабрикой. Например, после парсеры, создаваемые фабрикой fact, будут учитывать префиксы имен те- гов и атрибутов. Список таких свойств можно посмотреть на сайте проекта SAX Следует учитывать, что не все парсеры выполня- ют эти свойства. Если к объекту-фабрике применить метод void setValidating(true), как это сделано в листинге 1.9, то она будет производить парсеры, проверяющие структуру документа. Если применить метод void setNamespaceAware(true), то объект-фабрика будет производить парсеры, учитывающие пространства имен. После того как объект-парсер создан, остается только применить метод parse о, передав ему имя анализируемого файла и экземпляр класса- обработчика событий. В SAXParser есть (). ме метода использованного в листинге 1.9, есть еще методы, позволяющие извлечь документ из входного потока класса объекта класса адреса URI или из специально созданного источника класса inputsource. Методом setProperty о можно задать различные свойства парсера. В лис- тинге 1.9 этот метод использован для того, чтобы парсер проверял правиль- ность документа с помощью схемы XSD. Эта возможность включена в JAXP, начиная с версии JAXP 1.2. Если парсер выполняет проверки, то есть, применен метод setvalidating(true), то имеет смысл сделать развернутые сообщения об ошибках. Это предусмотрено интерфейсом Он различает предупреждения, ошибки и фатальные ошибки и описывает три метода, ко- торые автоматически выполняются при появлении ошибки соответствующе- го вида: Глава 1. Обработка документов XML 63 public void ex); public void ex); public void ex); Класс делает пустую реализацию этого интерфейса. При расширении этого класса можно сделать реализацию одного или всех мето- дов интерфейса Пример такой реализации приведен в лис- тинге 1.9. Класс SAXParserException хранит номер строки и столбца прове- ряемого документа, в котором замечена ошибка. Их можно получить мето- дами () И (), сделано В листинге 1.9. Связывание данных XML с объектами Java В МЫ сами создали Address И Person, представляющие документ XML. Поскольку структура документа XML четко определена, можно разработать стандартные правила связывания данных XML с объектами Java и создать программные средства для их реализации. Фирма Sun Microsystems разрабатывает пакет интерфейсов и классов JAXB, облегчающих связывание данных. На время написания книги проект JAXB еще не вышел из стадии разработки, но уже выставлен по адресу Для работы с пакетом JAXB анализируемый документ XML обязательно должен быть снабжен описанием DTD. В то время, когда я знакомился с JAXB, он не мог работать со схемой XSD. Ви- димо, это одна из причин задержки выпуска пакета. В состав пакета JAXB входит компилятор xjc (XML-Java Compiler). Он про- сматривает описание DTD и строит по нему объекты Java в оперативной памяти, а также создает исходные файлы объектов Java. Например, после выполнения команды $ xjc -roots notebook ntb.dtd -d sources в которой ntb.dtd — файл листинга 1.3 — в каталоге sources (по умолчанию в текущем каталоге) будут созданы файлы Address.java, Notebook.java, Person.java, PhoneList.java с описаниями объектов Java. Флаг -roots показывает один или несколько корневых элементов, разде- ленных запятыми. Кроме описания DTD компилятору xjc можно дать дополнительное описа- ние схемы документа на специальном языке (binding language) — реализа- ции XML. Это язык, похожий на язык XSD, но с меньшими возможностя- ми. По-видимому, в окончательном выпуске пакета JAXB он будет расши- рен или заменен языком XSD. Если дополнительное описание записано в 64 Разработка Web-служб средствами Java файл ntb.xjs (XML-Java binding schema), то вызов компилятора будет выгля- деть следующим образом: xjc ntb.dtd ntb.xjs -d sources Созданные компилятором xjc исходные файлы обычным образом с помо- щью компилятора javac компилируются в классы Java. Получив объекты данных, можно перенести в них содержимое документа XML методом который создает дерево объектов, или, наобо- рот, записать объекты Java в документы XML методом marshal о. Эти ме- тоды уже записаны в созданный компилятором xjc класс корневого эле- мента, В ЭТО — Notebook. Объекты данных Задачу связывания данных естественно обобщить — связывать объекты Java не только с документами XML, но и с текстовыми файлами, реляционными или объектными базами данных, другими хранилищами данных. Фирма Sun Microsystems опубликовала спецификацию и разработала интерфейсы для работы с Их можно посмотреть по адресу http://www.jcp.org/jsr/detail/12.jsp или http://accessl.sun.com/jdo/. Спецификация рассматривает более широкую задачу связывания данных, полученных не только из документа XML, но и из любого источника данных, называемого информационной системой предприятия (Enterprise Information System). Спецификация описывает два набора классов и интерфейсов: • JDO (JDO Service Provider Interface) — вспомогательные классы и интерфейсы, которые следует реализовать в сервере приложений для об- ращения к источнику данных, создания объектов, обеспечения их со- хранности, выполнения транзакций, проверки прав доступа к объектам; эти классы и интерфейсы составляют пакет jdo.spi; • JDO API (JDO Application Programming Interface) — интерфейсы, предос- тавляемые пользователю для доступа к объектам, управления транзак- циями, создания и удаления объектов; эти интерфейсы собраны в пакет Несмотря на то, что спецификация уже опубликована, на время выпуска книги фирма Sun еще не реализовала весь проект. Это сделали другие фирмы. Фирма Prism Technologies, выпускает про- дукт OpenFusion JDO. Фирма SolarMetric, http://www.solarmetric.com/, выпускает свою реализацию спецификации под названием Kodo JDO. Ее можно встроить в серверы приложений WebLogic, WebSphere, JBoss. Глава 1. Обработка документов XML 65 Есть и другие разработки, их обзор можно посмотреть на сайте разработчи- ков http://www.jdocentral.com/. Некоторые фирмы, не дожидаясь выхода спецификации разработали свои реализации более или менее соответствующие спецификации. Наиболее известна свободно распространяемая разработка фирмы Exolab, названная Castor. Ее можно посмотреть по адресу С помощью Castor можно предельно упростить связывание данных. Напри- мер, создание объекта Java из простого документа если отвлечься от проверок и обработки исключительных ситуаций, выполняется одним дей- ствием: Person person = new Обратно, сохранение объекта Java в виде документа XML в самом простом случае выглядит так: new В более сложных случаях надо написать файл аналогичный схеме XSD, с указаниями по связыванию данных (mapping Анализ документов XML с помощью DOM API Как видно из предыдущих разделов, читает документ только один раз, отмечая появляющиеся по ходу чтения открывающие теги, содер- жимое элементов и закрывающие теги. Этого достаточно для связывания данных, но неудобно для редактирования документа. Консорциум W3C разработал спецификации и набор интерфейсов D0M, кото- рые можно посмотреть на сайте этого проекта http://www.w3.org/D0M/. Мето- дами этих интерфейсов документ XML можно загрузить в оперативную память в виде дерева объектов. Это позволяет не только анализировать документ ана- лизаторами, основанными на структуре дерева, но и менять дерево, добавляя или удаляя объекты из дерева. Кроме того, можно обращаться непосредственно к каждому объекту в дереве и не только читать, но и изменять информацию, хранящуюся в нем. Однако, все это требует большого объема оперативной па- мяти для загрузки большого дерева. Фирма Sun Microsystems реализовала интерфейсы D0M в пакетах javax. и входящих в состав пакета JAXP. Воспользо- ваться этой реализацией очень легко: fact = 3 Зак. 748 66 Разработка Web-служб средствами Java builder = Document doc = Метод parse () строит дерево объектов и возвращает ссылку на него в виде объекта типа Document. В классе DocumentBuilder есть несколько методов s e n , позволяющих загрузить файл с адреса из входного потока, как объект класса File или из источника класса Интерфейс Document, расширяющий интерфейс Node, описывает дерево объектов документа в целом. Интерфейс Node — основной интерфейс в описании структуры дерева — описывает узел дерева. У него есть еще один наследник — интерфейс Element, описывающий лист дерева, соот- ветствующий элементу документа XML. Как видно из структуры наследо- вания этих интерфейсов, и само дерево, и его лист считаются узлами де- рева. Каждый атрибут элемента дерева описывается интерфейсом Attr. Еще несколько интерфейсов — CDATASection, Comment, Text, Entity, Notation — описывают разные типы элементов XML. На рис. 1.2 показано начало дерева объектов, построенного по документу, приведенному в листинге 1.2. Обратите внимание на то, что текст, находя- щийся в теле элемента, хранится в отдельном узле дерева — потомке узла элемента. Для каждого атрибута открывающего тега тоже создается отдель- ный узел. Document DocType notebook Element notebook Element person Element person Element name Element birthday 17051969 Element address Element phone Element home-phone Text 2334455 a a \ : 1.2. Дерево объектов документа XML Глава 1. Обработка документов XML Интерфейс Node Интерфейс Node описывает тип узла одной из следующих констант: • — узел типа Attr, содержит атрибут элемента; • CDATA_SECTION_NODE — узел типа CDADASection, содержит данные типа CDATA; • — узел типа comment, содержит комментарий; • — В узле типа фрагмент документа; • — узел Document; • — узел Document; • — узел является листом дерева типа Element; • ENTITY_NODE — в узле типа Entity хранится сущность ENTITY; • — В ТИПа ССЫЛКа на сущность; — В ТИПа • — узел ТИПа СО- держит инструкцию по обработке; • TEXT_NODE — в узле типа Text хранится текст. Методы интерфейса Node описывают действия с узлом дерева. Узнать тип узла можно методом: public short Имя узла возвращает метод: public String Значение, хранящееся в узле, можно получить методом: public String Проверить, есть ли атрибуты у элемента XML, хранящегося в узле в виде объекта типа NamedNodeMap, если это узел типа Element, можно методом: public boolean Атрибуты возвращает метод: public NamedNodeMap Метод возвращает null, если у элемента нет атрибутов. Следующий метод проверяет, есть ли у данного узла узлы-потомки: Разработка Web-служб средствами Java public boolean Если они есть, то можно получить их список в виде объекта типа методом: public NodeList Первый и последний узлы в этом списке можно получить методами: public Node ; public Node Родительский узел можно получить методом: public Node а соседние узлы с тем же предком, что и данный узел — методами: public Node public Node Можно получить и ссылку на весь документ методом: public Document Следующие методы позволяют изменить дерево объектов. Добавить новый узел-потомок можно методом: public Node newChild); Вставить новый узел-потомок перед существующим потомком refchild можно методом: public Node newChild, Node refChild); Заменить один узел-потомок новым узлом newchild можно мето- дом: public Node newChild, Node oldChild); Наконец, удалить узел-потомок можно методом: public Node removeChild(Node c h i l d ) ; Интерфейс Document Интерфейс Document добавляет к своего предка Node методы рабо- ты с документом в целом. Метод public DocumentType возвращает общие сведения о документе в виде объекта типа DocumentType. Методы getEntitied (), getNotations () и другие методы ин- терфейса DocumentType возвращают конкретные сведения о документе. Глава 1. Обработка документов XML Метод public Element возвращает корневой элемент дерева объектов, а методы public NodeList public NodeList uri, String public Element id); возвращают все элементы с указанным именем tag без префикса или с пре- фиксом, а также элемент, определяемый значением атрибута с именем ID. Несколько методов позволяют изменить структуру и содержимое дерева объектов. Создать новый пустой элемент по его имени или по имени с префиксом можно методами public Element name); public Element uri, String name); Создать узел типа CDATA_SECTION_NODE МОЖНО методом public CDATASection name); Создать узел типа МОЖНО методом public EntityReference name); Создать узел типа МОЖНО методом public Создать узел типа TEXT_NODE МОЖНО методом public TextNode name); Создать узел-атрибут с именем name можно методом public Attr name); public Attr uri, String name); Узел-комментарий создается методом public Comment comment); Наконец, можно создать пустой документ — фрагмент данного документа с целью дальнейшего заполнения public Вставить созданный узел, а значит, и все поддерево, в дерево документа, можно методом public Node importedNode, boolean deep); Этим методом можно соединить два дерева объектов. Если второй аргумент равен true, то рекурсивно вставляется все поддерево. 70 Разработка Web-служб средствами Java Интерфейс Element Интерфейс Element добавляет к методам своего предка Node методы работы с атрибутами открывающего тега элемента и методы, позволяющие обратиться к вложенным элементам. Только один метод public String дает сведения о самом элементе, а именно, имя элемента. Прежде чем получить значение атрибута с именем name надо проверить его наличие методами public boolean name); public boolean uri, String name); Второй из этих методов учитывает пространство имен с именем uri, запи- санным в виде строки URI; имя name должно быть полным, с префиксом. Получить атрибут в виде объекта типа Attr или его значение в виде строки по имени name с учетом префикса или без него можно методами public Attr public Attr uri, String name); public String name); public String uri, String name); Удалить атрибут можно методами public Attr name); public void name); public void uri, String name); Установить значение атрибута можно методами public void name, String value); public void uri, String name, String value); Добавить атрибут в качестве потомка можно методами public Attr name); public Attr name); Два метода позволяют получить список узлов-потомков: public NodeList name); public NodeList uri, String name); Итак, методы перечисленных интерфейсов позволяют перемещаться по де- реву, менять структуру дерева, просматривать информацию, хранящуюся в узлах и листьях дерева и изменять ее. Глава 1. Обработка документов XML 71 Приведем пример работы с деревом объектов, построенным по документу XML. Добавим в адресную книжку листинга 1.2 новый рабочий или домаш- ний телефон Сидоровой. Это действие записано в листинге 1.10. Листинг Анализ адресной книжки с помощью DOM API import *; import import org.xml.sax.*; class ErrHand implements ErrorHandler{ public void ex){ " + ex); = " + + " col = " + public void ex){ " + ex); = " + + " col = " + public void ex){ e r r o r : " + ex); = " + + " col = " + public class static final String = "http://java.sun.com/xml/jaxp/properties/schemaLanguage" static final String = 72 Разработка Web-служб средствами Java "http://www.w3.org/2001/XMLSchema"; public static void args) throws Exception} if != 3){ " + " "); DocumentBuilderFactory fact = ; try{ x){ свойство: " + } builder = Document doc = NodeList list = int n = if (n == 0) { пуст."); Глава 1. Обработка документов XML } N o d e t h i s N o d e = n u l l ; for (int к = 0; к < n; k++){ thisNode = list.item(k); String = null; if instanceof Element){ elemName = if if отсутствуют " + elemName); } attrs = Node attr = if (attr instanceof Attr) if break; NodeList topics = Node if Разработка Web-служб средствами Java = else newNode = Text textNode = Дерево объектов можно вывести на экран дисплея, например, как дерево JTree — компонент графической библиотеки Swing [10]. Именно так сдела- но на рис. 1.2. Для вывода применена программа DomEcho из электронного учебника "Web Services Tutorial". Исходный текст программы слишком ве- лик, чтобы приводить здесь, но его можно посмотреть по адресу В состав Xerces в каче- стве примера анализа документа в раздел входит программа которая тоже показывает дерево объектов в виде дерева JTree библиотеки Swing. Другие DOM-парсеры Модель дерева объектов D0M была первоначально разработана группой OMG (Object Management Grou) в рамках языка (Interface Definition Language, язык определения интерфейса) без учета особенностей Java. Толь- ко потом она была переведена на Java консорциумом в виде интер- фейсов и классов, составивших пакет Этим объясняется, в ча- стности, широкое применение в DOM API интерфейсов и фабричных мето- дов вместо классов и конструкторов. Это неудобство привело к появлению других разработок. Участники общественного проекта не стали реализовать модель D0M, а разработали свою модель дерева объектов, получившую название JDOM Они выпускают одноименный свободно распространяемый про- граммный продукт, с которым можно ознакомиться на сайте проекта Этот продукт никак не может выйти из стадии разра- ботки, но уже широко используется для обработки документов XML средст- вами Java. Участники другого общественного проекта dom4j приняли модель D0M, но упростили и упорядочили DOM API. С их одноименным продук- том dom4j можно ознакомиться на сайте http://www.dom4j.org/. Глава 1. Обработка документов Фирма ТМЕ (The Mind Electric), выпус- кающая известные программные продукты GLUE и GAIA, поставляет в со- ставе GLUE или отдельно набор инструментальных средств EXML (Electric XML) и его расширение EXML+ (Electric XML+). Этот продукт полностью реализует весьма компактен, экономичен и быстр. Преобразование дерева объектов в XML Итак, дерево объектов D0M построено надлежащим образом. Теперь надо его преобразовать в документ XML, страничку HTML, документ PDF или объект другого типа. Средства для выполнения такого преобразования со- ставляют третью часть набора JAXP — пакеты которые представляют собой реализацию языка описания таблиц стилей для преобразований XSLT (XML Stylesheet Language for Transformations) средст- вами Java. Язык XSLT разработан консорциумом W3 как одна из трех частей, со- ставляющих язык записи таблиц стилей XSL (XML Stylesheet Language). Все материалы XSL можно посмотреть на сайте проекта http://www.w3.org/Style/XSL/. Интерфейсы и классы, входящие в пакеты *, управляют процессором XSLT, в качестве которого выбран процессор разработанный в рамках проекта Apache Software Foundation, Исходный объект преобразования должен иметь Интерфейс Source определяет всего два метода доступа к идентификатору объекта: public String ; public void id); У интерфейса source есть три реализации. Класс DOMSource подготавливает к преобразованию дерево объектов D0M, а классы SAXsource и streamSource подготавливают SAX-объект и простой поток данных. В кон- структоры этих классов заносится ссылка на исходный объект — для конст- руктора класса DOMSource это узел дерева, для конструктора класса SAXSource — ИМЯ ф а й л а , ДЛЯ КОНСТруКТОра Класса S t r e a m S o u r c e — поток. Методы этих классов позволяют задать дополнительные свойства ис- ходных объектов преобразования. Результат преобразования описывается интерфейсом Result. Он тоже опре- деляет точно такие же методы доступа к идентификатору объекта-результата, как и интерфейс У тоже есть три реализации — классы DOMResult, SAXResult И S t r e a m R e s u l t . В КОНСТруКТОрЫ ЭТИХ Разработка Web-служб средствами Java ся ссылка на выходной объект. В первом случае это узел дерева, во вто- ром — объект типа в третьем — файл, в который будет за- несен результат преобразования, или выходной поток. Само преобразование выполняется объектом класса Transformer. Вот стан- дартная схема преобразования дерева объектов в документ за- писываемый в файл. transFactory = Transformer transformer = DOMSource source = new File = new FileOutputStream fos = new result = new r e s u l t ) ; Вначале методом newlnstance о создается экземпляр transFactory фабри- ки объектов-преобразователей. Методом public void name, String value); класса Trans formerFactory можно установить некоторые атрибуты экземпляра. Имена и значения атрибутов зависят от реализации фабрики. С помощью фабрики преобразователей создается объект-преобразователь класса Transformer. При создании этого объекта в него можно занести объ- ект, содержащий правила преобразования, например, таблицу стилей XSL. В созданный объект класса Transformer методом public void name, String value); можно занести параметры преобразования, а методами public void out); public void name, String value); можно определить свойства преобразованного объекта. Имена свойств name задаются константами, которые собраны в специально определенный класс outputKeys, содержащий только эти константы. Вот их список: • — список имен секций CDATA через пробел. • — открытый идентификатор PUBLIC преобразованного документа. Глава 1. Обработка документов XML 77 • DOCTYPE_SYSTEM — системный идентификатор SYSTEM преобразованного документа. • ENCODING — кодировка символов преобразованного документа, значение атрибута encoding объявления XML. • INDENT — делать ли отступы в тексте преобразованного документа. Зна- чения этого свойства "yes" или "по". • MEDIATYPE — МШЕ-тип содержимого преобразованного документа. • METHOD — метод вывода, одно из значений "html" "text". OMIT_XML_DECLARATION — не включать объявление XML. Значения "yes" • STANDALONE — отдельный или вложенный документ, значение атрибута standalone объявления XML. Значения "yes" или "по". • VERSION — номер версии XML для атрибута version объявления XML. Например, можно задать кодировку символов преобразованного документа следующим методом: Затем в приведенном примере по дереву объектов document типа Node соз- дается объект класса DOMSource — упаковка дерева объектов для последую- щего преобразования. По типу аргумента конструктора видно, что можно преобразовать не все дерево, а какое-либо его поддерево, записав в конст- рукторе класса DOMSource корневой узел поддерева. Наконец, определяется результирующий объект result, связанный с фай- лом и выполняется преобразование методом transform о . Более сложные преобразования выполняются с помощью таблицы стилей XSL. Таблицы стилей XSL В документах HTML часто применяются таблицы стилей CSS, задающие общие правила оформления документов HTML: цвет, шрифт, заголовки. Выполнение этих правил придает документам единый стиль оформления. Для документов XML, в которых вообще не определяются правила визуа- лизации, идея применить таблицы стилей оказалась весьма плодотворной. Таблицы стилей для документов XML записываются на специально сде- ланной реализации языка XML, названной XSL (XML Stylesheet Language). Все теги документов XSL относятся к пространству имен Обычно они записываются с пре- Разработка Web-служб средствами Java фиксом Если принят этот префикс, то корневой элемент таблицы стилей XSL будет называться Простейшая таблица стилей выглядит так, как записано в листинге Листинг Простейшая таблица стилей XSL method="text" encoding="CP866"/> Здесь только определяется префикс пространства имен и правила выво- да, а именно, выводится плоский текст, на что показывает значение text (другие значения — html и в кодировке СР8 66. Такая кодировка вы- брана для вывода кириллицы на консоль MS Windows. Объект класса Transformer, руководствуясь таблицей стилей листинга 1.11, просто выво- дит тела элементов так, как они записаны в документе XML, то есть просто удаляет теги вместе с атрибутами, оставляя их содержимое. таблицу стилей записываем в файл, например, Ссылку на таблицу стилей можно поместить в документ XML как одну из инструкций по обработке: После этого если он, кроме того, является XSLT- процессором, выполнит преобразование, заданное в файле simple.xsl. Другой путь — использовать таблицу стилей при создании объекта- преобразователя, например, так, как записано в листинге 1.12. [ Листинг Консольная программа преобразования документа import j import j *; public class SimpleTransform{ Глава 1. Обработка документов XML 79 public static void args) throws if != 2){ " + File = new File xsltFile = new Source = new ; Source xsltSource = new Result result = new TransformerFactory transFact = Transformer trans = result); После компиляции набираем в командной строке SimpleTransform ntb.xml и получаем на экране дисплея содержимое тегов документа ntb.xml. В более сложных случаях просто изменяем таблицу стилей. Например, если мы хотим получить содержимое документа на консоли, то таблицу стилей для объекта-преобразователя класса Transformer надо записать так, как по- казано в листинге 1.13. Листинг Таблица стилей для показа адресной книжки 80 Разработка Web-служб средствами Java method="text" encoding="CP866" /> match="person"> match="name"> select="work-phone" /> Мы не будем в этой книге заниматься языком XSL — одно описание языка будет толще всей этой книги. На русский язык переведена "библия" XSLT [5]. Ее автор Майкл (Michael H. создал Глава 1. Обработка документов XML 81 и свободно распространяет популярный XSLT-процессор Saxon, http://users.iclway.co.uk/mhkay/saxon/index.html. Хорошее изложение XSLT сделал Алексей Валиков его книгой вы можете воспользо- ваться для дальнейшего изучения XSLT. В этой книге вы найдете опи- сание XSLT-процессоров и их сравнение. Надо заметить, что язык XSL, в котором выделяются правила преобразова- ния XSLT (XSL Transform), правила форматирования XSL FO (XSL Formatting Objects) и язык описания путей к различным частям документов XPath (XML Path Language), бурно развивается, и сделать полное его описа- ние сейчас просто невозможно. Преобразование документа XML в HTML С помощью языка XSL и методов класса Transformer можно легко преоб- разовать документ XML в документ HTML. Достаточно написать соответст- вующую таблицу стилей. В листинге 1.14 показано, как это можно сделать для адресной книжки листинга 1.2. Листинг 1.14. Таблица стилей для преобразования в HTML ! version="1.0" match="/"> адреса и Разработка Web-служб средствами Java select="city" /> Рабочий: /> Домашний: Эту таблицу стилей можно записать в файл, например, ntb.xsl, и сослаться на него в документе XML, описывающем адресную книжку: < ! — Содержание адресной книжки —> После этого любой браузер, "понимающий" XML и XSLT, например, Mozilla или Internet Explorer, покажет содержимое адресной книжки как предписано листингом 1.14. Если набрать в командной строке $ SimpleTransform ntb.xml ntb.xsl > то в текущем каталоге будет записан преобразованный HTML-файл. |