Все о JAXP, Часть 1

Комплект инструментальных средств обработки XML облегчает синтаксический анализ и проверку корректности

JavaAPI for XML Processing (JAXP) позволяет производить проверку корректности, синтаксический анализ и трансформацию XML при помощи нескольких различных API. JAXP обеспечивает как простоту использования, так и независимость от производителя. В этой статье, одной из двух в серии, посвященной знакомству с JAXP, объясняется, как использовать преимущества синтаксического анализа и функциональных возможностей данного API. Во второй части рассмотрено использование JAXP в XSL-преобразованиях.

Brett McLaughlin, Автор и редактор, O'Reilly Media, Inc.

Бретт Маклафлин (Brett McLaughlin) работает с компьютерами со времен Logo (помните маленький треугольник?). За последние несколько лет он стал одним из наиболее известных авторов и программистов сообщества по технологиям Java и XML. Он работал в Nextel Communications над реализацией сложных корпоративных систем, в Lutris Technologies, фактически, над созданием сервера приложений, а с недавних пор работает в O'Reilly Media, Inc., где продолжает писать и редактировать книги по данной тематике. Его книга "Java 5.0 Tiger: Заметки разработчика" является первой доступной книгой по новейшей технологии Java, а его классическая "Java и XML" остается одной из наиболее авторитетных работ по использованию технологий XML в языке программирования Java.



17.05.2005

Технология Java и XML, возможно, наиболее важные разработки в программировании за последние пять лет. Следствием этого является быстрое распространение API для работы с XML в языке программирования Java. Два наиболее популярных API (Document Object Model (DOM) и Simple API for XML (SAX)) вызвали огромный интерес; за ними идут JDOM и API связывания данных (см. раздел "Ресурсы"). Освоение одного или обоих этих API является непростой задачей; использование их всех возводит вас в ранг гуру. Однако все большее и большее число Java-разработчиков обнаруживает, что уже нет необходимости в доскональном знании SAX или DOM, во многом благодаря набору инструментальных средств JAXP от Sun Microsystems. Java API for XML Processing (JAXP) делает XML управляемым даже для начинающих Java-программистов, обеспечивая в то же время превосходные возможности и для опытных разработчиков. То есть, даже опытные разработчики, использующие JAXP, часто даже не имеют полного представления о том API, которое используют.

В этой статье предполагается, что вы обладаете основными знаниями о SAX и DOM. Если вы новичок в синтаксическом анализе XML, вы, возможно, захотите прочитать сначала о SAX и DOM в различных источниках или просмотреть мою книгу (см. раздел "Ресурсы"). Вам не обязательно знать тонкости обратных вызовов или DOM Nodes, но вы должны, по крайней мере, знать о том, что SAX и DOM – это API синтаксического анализа. Желательно также иметь базовое представление об их отличиях. Эта статья будет иметь намного больше смысла после ознакомления с этими основами.

JAXP: API или абстракция?

Собственно говоря, JAXP - это API, но было бы точнее называть его уровнем абстракции. Он не предоставляет новое средство для синтаксического анализа XML, не добавляет его к SAX или DOM и не придает новые функциональные возможности языку Java и XML-обработке. (Если вы сейчас мне не верите, то значит читаете нужную статью). Вместо этого JAXP облегчает использование DOM или SAX для решения некоторых сложных задач. Он также делает возможным решение некоторых зависимых от производителя задач, с которыми вы можете столкнуться, работая с DOM или SAX API способом, нейтральным к производителю.

Становясь важным

В ранних версиях платформы Java JAXP можно было загрузить отдельно от основной платформы. В Java 5.0 JAXP стал ключевым элементом языка программирования Java. Если у вас есть последняя версия JDK (см. раздел "Ресурсы"), значит у вас уже есть JAXP.

Вы не можете выполнять синтаксический анализ XML без SAX, DOM или другого API XML-анализа. Я видел много просьб сделать сравнение SAX, DOM, JDOM и dom4j с JAXP, но это сделать не возможно, поскольку первые четыре API служат совершенно другим целям, чем JAXP. SAX, DOM, JDOM и dom4j производят синтаксический анализ XML. JAXP предоставляет средство для доступа к этим анализаторам и к предоставляемым ими данным и не предлагает нового способа анализа XML-документа. Понимание этой разницы является критичным для корректного использования JAXP. Это понимание, возможно, позволит вам на мили опередить многих ваших друзей, XML-разработчиков.

Если вы все еще сомневаетесь, проверьте, что у вас установлен JAXP (см. врезку "Становясь важным"). Запустите Web-браузер и загрузите документацию по JAXP API. Перейдите к анализирующей части API, расположенной в пакете javax.xml.parsers package. Вы неожиданно увидите только шесть классов. Насколько может быть трудным такой API? Все эти классы работают с существующим анализатором. И два из них предназначены только для обработки ошибок. JAXP намного проще, чем кажется. Так к чему все волнения?

Находясь на вершине мира

И JDOM и dom4j (см. раздел "Ресурсы"), так же как и JAXP, находятся на вершине других API синтаксического анализа. Хотя эти API обеспечивают различную модель доступа к данным из SAX или DOM, они внутренне (с некоторыми уловками и модификациями) используют SAX для доступа к данным, которые предоставляют пользователю.

JAXP и синтаксический анализатор фирмы Sun

Большое количество недоразумений по поводу связки анализатор/API возникают изза того, как Sun собирает в пакет JAXP и какой анализатор используется по умолчанию. В ранних версиях JAXP Sun включала в него JAXP API (c упомянутыми мною шестью классами и несколькими классами, используемыми для преобразования) и синтаксический анализатор, называемый Crimson. Crimson был частью пакета com.sun.xml. В более новых версиях JAXP, включенных в JDK, Sun перепаковала анализатор Apache Xerces (см. раздел "Ресурсы"). В обоих случаях, тем не менее, анализатор является частью JAXP-дистрибутива, но не частью JAXP API.

Представляйте себе это так: JDOM поставляется с анализатором Apache Xerces. Этот анализатор не является частью JDOM, но используется JDOM, поэтому включен в дистрибутив для гарантии нормального использования JDOM. Этот же принцип относится и к JASP, но он не так ясно задекларирован: JAXP поставляется с анализатором, поэтому может быть применен немедленно. Тем не менее, многие считают включенные в анализатор Sun классы частью самого JAXP API. Например, обычный вопрос в группах новостей: "Как я могу использовать класс XMLDocument, находящийся в JAXP? Каково его предназначение?" Ответ довольно сложен.

Что в названии (пакета)?

Когда я первый раз копался в исходном коде Java 1.5, то был удивлен тем, что увидел, вернее, тем, чего не увидел. Вместо того, чтобы разместить Xerces в нормальном пакете org.apache.xerces, Sun переместила классы Xerces в com.sun.org.apache.xerces.internal. (Я нашел это несколько неуважительным, но меня никто не спрашивал.) В любом случае, если вы ищете Xerces в JDK, то он находится именно там.

Прежде всего, класс com.sun.xml.tree.XMLDocument не является частью JAXP. Он – часть анализатора Crimson фирмы Sun, поставлявшегося в ранних версиях JAXP. Поэтому вопрос неверен в самой постановке. Во-вторых, главной целью JAXP является обеспечение независимости от производителя при работе с анализаторами. С JAXP вы можете использовать один и тот же код с XML-анализатором от Sun, XML-анализатором Xerces от Apache и XML-анализатором от Oracle. Следовательно, использование специфичных для Sun классов устраняет смысл применения JAXP. Вы начинаете понимать, как это запутывает предмет рассмотрения? Анализатор и API в дистрибутиве JAXP смешаны вместе, и некоторые разработчики ошибочно считают классы и функциональные возможности одного частью второго и наоборот.

Теперь, разобравшись с этой путаницей, вы готовы приступить к кодированию и теории.


Начинаем работать с SAX

SAXпредставляет собой управляемую событиями методологию обработки XML. Он состоит из множества функций обратного вызова (callback). Например, функция обратного вызова startElement() вызывается каждый раз, когда SAX-анализатор встречает открывающий тег элемента. Функция обратного вызова characters() вызывается для символьных данных, а endElement() вызывается при обработке конечного тега элемента. Большое количество функций обратного вызова предназначено для обработки документа, ошибок и других лексических структур. Вы поняли идею. Программист SAX реализует один из SAX-интерфейсов, определяющих эти функции обратного вызова. SAX также предоставляет класс под названием DefaultHandler (в пакете org.xml.sax.helpers), реализующий все эти функции обратного вызова и по умолчанию предоставляющий пустые реализации всех методов обратного вызова. (Вы увидите важность этого в моем обсуждении DOM в следующем разделе "Работаем с DOM".) SAX-разработчик должен только расширить этот класс, затем реализовать методы, требующие добавления специальной логики. Таким образом, сутью SAX является предоставление кода для различных функций обратного вызова, затем предоставление возможности анализатору вызывать каждую из них в соответствующее время. Вот общепринятая практика использования SAX:

  1. Создать экземпляр SAXParser при помощи зависящей от производителя реализации анализатора.
  2. Зарегистрировать реализации функций обратного вызова (например, при помощи класса, расширяющего DefaultHandler).
  3. Начать процесс синтаксического анализа и ждать вызова ваших реализаций функций обратного вызова.

SAX-компонент JAXP предоставляет простое средство для выполнения всей этой процедуры. Без JAXP экземпляр SAX-анализатора должен либо быть создан из класса производителя напрямую (например, org.apache.xerces.parsers.SAXParser), либо должен использовать вспомогательный (helper) класс SAX, называемый XMLReaderFactory (тоже из пакета org.xml.sax.helpers). Проблема с первой методологией очевидна: она зависит от производителя. Проблема со второй: конструктор требует в качестве аргумента название String используемого класса анализатора (это, опять же, класс Apache, org.apache.xerces.parsers.SAXParser). Вы можете изменить анализатор, передавая другой класс анализатора в виде String. При этом, если вы меняете название анализатора, вам не нужно изменять какие-либо операторы import, но вам все равно нужно перекомпилировать класс. Это, естественно, не лучшее решение. Намного проще было бы иметь возможность менять анализаторы без перекомпиляции класса.

JAXP предлагает эту лучшую альтернативу: он позволяет вам указывать анализатор как системное свойство Java. Конечно же, при загрузке дистрибутива от Sun вы получаете реализацию JAXP, использующую версию Xerces от Sun. Изменение анализатора (скажем, на анализатор Oracle) требует изменения настройки classpath, переходя с одной реализации анализатора на другую. При этом не требуется перекомпиляция кода. В этом и заключается магия (абстракция), которую предоставляет JAXP.

Коварные SAX-разработчики

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

Обзор конструктора SAX-анализатора

Класс JAXP SAXParserFactory является ключевым в обеспечении возможности легко менять реализации анализаторов. Вы должны создать новый экземпляр этого класса (который я вскоре рассмотрю). После создания нового экземпляра конструктор предоставляет метод для получения SAX-анализатора. JAXP-реализация берет на себя заботу о зависящем от производителя коде, сохраняя ваш код не загрязненным. Этот конструктор имеет также и некоторые другие хорошие возможности.

В дополнение к основной работе по созданию экземпляров SAX-анализаторов конструктор дает возможность устанавливать конфигурационные настройки. Эти настройки влияют на все экземпляры анализаторов, получаемых через конструктор. Наиболее часто используемыми настройками, доступными в JAXP 1.3, являются setNamespaceAware(boolean awareness) - установка информированности о пространстве имен, и setValidating(boolean validating) – включение проверки корректности DTD. Помните, что после установки, эти настройки будут влиять на все экземпляры, полученные из конструктора после вызова метода.

После настройки конструктора вызов newSAXParser() возвращает готовый к использованию экземпляр класса JAXP SAXParser. Этот класс работает поверх SAX-анализатора (экземпляр SAX-класса org.xml.sax.XMLReader). Он предохраняет вас тот применения каких-либо зависимых от производителя дополнений к классу анализатора. (Помните дискуссию о классе XmlDocument?) Этот класс позволяет не учитывать фактическое поведение анализатора. В листинге 1 показано, как создать, сконфигурировать и использовать SAX-конструктор:

Листинг 1. Использование SAXParserFactory
import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

// SAX
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class TestSAXParsing {
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestSAXParsing [filename]");
                System.exit (1);
            }
            // Получить SAX Parser Factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // Включить проверку корректности, выключить пространство имен
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            SAXParser parser = factory.newSAXParser();
            parser.parse(new File(args[0]), new MyHandler());
        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not support " +
                               " the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining SAX Parser Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyHandler extends DefaultHandler {
    // Реализации обратных вызовов SAX из ContentHandler, ErrorHandler и т.д..
}

Из листинга 1 ясно, что при использовании конструктора могут возникнуть две проблемы, специфические для SAX: невозможность получить или сконфигурировать SAX-конструктор и невозможность сконфигурировать SAX-анализатор. Первая проблема, представленная FactoryConfigurationError, обычно возникает, когда указанный в JAXP-реализации или системном свойстве анализатор не может быть получен. Вторая проблема, представленная ParserConfigurationException, возникает, когда запрашиваемая функциональность не доступна в используемом анализаторе. С обеими проблемами легко справиться, поэтому не должно возникнуть никаких трудностей при использовании JAXP. Фактически, вы, возможно, захотите написать код, который пытается установить несколько функций и при их недоступности с честью выйти из ситуации.

Экземпляр SAXParser создается сразу после получения конструктора, выключения поддержки пространства имен и включения проверки корректности; затем начинается синтаксический анализ. Метод SAX-анализатора parse() принимает экземпляр вспомогательного класса SAX HandlerBase, о котором я говорил раньше, расширяющий ваш специализированный класс обработчика. Для знакомства с реализацией этого класса и полным листингом на Java обратитесь к исходному коду дистрибутива (см. раздел "Загрузка"). Также вы передаете File для анализа. Однако класс SAXParser содержит намного больше, чем один этот метод.

Работа с SAX-анализатором

Получив экземпляр класса SAXParser, вы можете сделать гораздо больше, чем просто передать File для анализа. Из-за способа взаимодействия компонентов в больших приложениях не всегда безопасно предполагать, что создатель экземпляра объекта является его пользователем. Один компонент может создать экземпляр SAXParser, а другому компоненту (возможно созданному другим разработчиком) может понадобиться использовать этот же самый экземпляр. По этой причине JAXP предоставляет методы для определения настроек анализатора. Например, вы можете использовать isValidating() для определения того, будет ли анализатор выполнять проверку на корректность, и isNamespaceAware() для определения того, может ли анализатор обрабатывать пространства имен в XML-документе. Эти методы могут дать вам информацию о том, что может делать анализатор, но пользователи лишь экземпляра SAXParser (а не самого SAXParserFactory) не имеют средств для изменения этих функций. Вы должны делать это на уровне конструктора анализатора.

Вы также можете запрашивать анализ документа разными способами. Вместо простого приема параметров File и экземпляра SAX DefaultHandler метод SAXParser parse() может также принимать SAX InputSource, Java InputStream или URL в формате String вместе с экземпляром DefaultHandler. То есть, вы можете выполнять анализ документов, представленных в различной форме.

Наконец, вы можете получить сам SAX-анализатор (экземпляр org.xml.sax.XMLReader) и использовать его напрямую через метод SAXParser getXMLReader(). После получения этого экземпляра становятся доступными обычные SAX-методы. В листинге 2 приведены примеры различного использования класса SAXParser - основного класса JAXP для SAX-анализа:

Листинг 2. Использование класса JAXP SAXParser
// Получить экземпляр SAX Parser 
SAXParser saxParser = saxFactory.newSAXParser();
// Определить, поддерживается ли проверка корректности
boolean isValidating = saxParser.isValidating();
// Определить, поддерживаются ли пространства имен
boolean isNamespaceAware = saxParser.isNamespaceAware();
// Провести анализ различными способами
// Использовать файл и экземпляр SAX DefaultHandler
saxParser.parse(new File(args[0]), myDefaultHandlerInstance);
// Использовать SAX InputSource и экземпляр SAX DefaultHandler 
saxParser.parse(mySaxInputSource, myDefaultHandlerInstance);
// Использовать InputStream и экземпляр SAX DefaultHandler 
saxParser.parse(myInputStream, myDefaultHandlerInstance);
// Использовать URI и экземпляр SAX DefaultHandler 
saxParser.parse("http://www.newInstance.com/xml/doc.xml",
                myDefaultHandlerInstance);
// Получить базовый (wrapped) SAX-анализатор
org.xml.sax.XMLReader parser = saxParser.getXMLReader();
// Использовать базовый анализатор
parser.setContentHandler(myContentHandlerInstance);
parser.setErrorHandler(myErrorHandlerInstance);
parser.parse(new org.xml.sax.InputSource(args[0]));

До этого момента я много говорил о SAX, но не открыл ничего выдающегося или неожиданного. Добавленная JAXP функциональность довольно незначительна, особенно при использовании SAX. Эта минимальная функциональность делает ваш код более переносимым и позволяет его использование (свободное либо коммерческое) другими разработчиками с любым SAX-совместимым XML-анализатором. Это все. Больше ничего нет в использовании SAX с JAXP. Если вы уже знаете SAX, то значит вы прошли 98% пути. Необходимо всего лишь изучить два новых класса и пару исключительных ситуаций Java - и вы готовы к работе. Если вы никогда ранее не использовали SAX, достаточно просто сделать это сейчас.


Работа с DOM

Если вы думаете, что нужно передохнуть перед тем как бросить вызов DOM, вы ошибаетесь. Использование DOM с JAXP практически ничем не отличается от использования его с SAX; вам нужно только заменить два имени класса и тип возвращаемого результата, и почти все будет сделано. Если вы понимаете, как работает SAX и для чего предназначен DOM, то у вас не будет никаких проблем.

Основным отличием между DOM и SAX является структура самих API. SAX состоит из управляемого событиями набора функций обратного вызова, тогда как DOM имеет древовидную структуру. В SAX для работы нет никакой структуры данных (если разработчик сам ее не создал). SAX, таким образом, не предоставляет возможности модифицировать XML-документ. DOM предоставляет такую возможность. Класс org.w3c.dom.Document представляет XML-документ и сделан из DOM-узлов, представляющих элементы, атрибуты и другие конструкции XML. Следовательно, JAXP не должен вызывать функции обратного вызова SAX; он отвечает только за возврат объекта DOM Document из анализа.

Обзор конструктора DOM-анализатора

C этим пониманием основ DOM и различий между DOM и SAX вам не нужно знать больше. Код в листинге 3 выглядит практически таким же, как и SAX-код в листинге 1. Сначала получаем DocumentBuilderFactory (так же как и SAXParserFactory в листинге 1). Затем конструктор конфигурируется для обработки пространств имен и выполнения проверки корректности (так же как и в SAX). Затем из конструктора извлекается экземпляр DocumentBuilder, аналог SAXParser (так же как и... ну, вы поняли). Затем происходит синтаксический анализ и полученный в результате объект DOM Document передается в метод, распечатывающий дерево DOM:

Листинг 3. Использование DocumentBuilderFactory
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;

// DOM
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestDOMParsing {

    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestDOMParsing " +
                                    "[filename]");
                System.exit (1);
            }

            // Получить Document Builder Factory
            DocumentBuilderFactory factory = 
                DocumentBuilderFactory.newInstance();

            // Включить проверку корректности и выключить пространства имен
            factory.setValidating(true);
            factory.setNamespaceAware(false);

            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(args[0]));

            // Распечатать документ из древовидной структуры DOM 
            //   без начального отступа
            printNode(doc, "");

        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not " +
                               "support the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining Document " +
                               "Builder Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void printNode(Node node, String indent)  {
        // Распечатать дерево DOM 
    }

}

С этим кодом могут возникнуть две проблемы (как и с SAX в JAXP): FactoryConfigurationError и ParserConfigurationException. Причина их та же, что и в случае с SAX. Либо проблема представлена в классах реализации (вызывает FactoryConfigurationError), либо данный анализатор не поддерживает запрошенную функцию (вызывает ParserConfigurationException). Единственным различием между SAX и DOM в этом плане является то, что для DOM вы используете DocumentBuilderFactory вместо SAXParserFactory и DocumentBuilder вместо SAXParser. Все просто. (Вы можете просмотреть полный листинг, включая метод, используемый для распечатки DOM-дерева; см. раздел "Загрузка".)

Работа с DOM-анализатором

После создания конструктора DOM вы можете получить экземпляр DocumentBuilder. Методы, доступные в экземпляре DocumentBuilder, очень похожи на методы, доступные в его SAX-аналоге. Главное отличие - варианты метода parse() не принимают экземпляр класса SAX DefaultHandler. Вместо этого они возвращают экземпляр DOM Document, представляющий анализируемый XML–документ. Еще одним последним отличием является наличие двух методов, обеспечивающих SAX-подобную функциональность:

  • setErrorHandler() берет на себя реализацию SAX ErrorHandler для обработки возможных проблем, возникающих в процессе синтаксического анализа
  • setEntityResolver() берет на себя реализацию SAX EntityResolver для обработки распознавания сущностей

В листинге 4 показаны примеры этих методов в действии:

Листинг 4. Использование класса JAXP DocumentBuilder
// Получить экземпляр DocumentBuilder 
DocumentBuilder builder = builderFactory.newDocumentBuilder();
// Определить, поддерживается ли проверка корректности
boolean isValidating = builder.isValidating();
// Определить, поддерживаются ли пространства имен
boolean isNamespaceAware = builder.isNamespaceAware();
// Установить SAX ErrorHandler
builder.setErrorHandler(myErrorHandlerImpl);
// Установить SAX EntityResolver
builder.setEntityResolver(myEntityResolverImpl);
// Выполнить синтаксический анализ различными способами
// Использовать файл
Document doc = builder.parse(new File(args[0]));
// Использовать SAX InputSource
Document doc = builder.parse(mySaxInputSource);
// Использовать InputStream
Document doc = builder.parse(myInputStream, myDefaultHandlerInstance);
// Использовать URI 
Document doc = builder.parse("http://www.newInstance.com/xml/doc.xml");

Если вы немного устали читать этот раздел по DOM, то вы не одиноки - я немного устал его писать, поскольку применение ваших знаний о SAX в DOM является совершенно очевидным.


Выполнение проверки корректности

В Java 5.0 (и JAXP 1.3) JAXP представляет новый способ проверки корректности документов. Вместо простого использования метода setValidating() с конструктором SAX или DOM процесс проверки разбивается на несколько классов, находящихся в новом пакете javax.xml.validation. Для детального объяснения всех нюансов проверки корректности, включая W3C XML Schema, DTD, схемы RELAX NG и другие модели ограничений, мне понадобится в этой статье больше места, чем у меня есть. Но если вы уже имеете некоторые из них, использовать новую модель проверки и убедиться в соответствии с ними вашего документа довольно просто.

Избыточность хороша не всегда

Вещь, которую вы не должны делать - использовать setValidating(true) и пакет javax.xml.validation. Вы получите ряд неприятных ошибок, большинство из которых трудно исправить. Лучше взять за привычку никогда не вызывать setValidating() (значение по умолчанию false), а использовать вместо этого новую среду JAXP проверки корректности.

Прежде всего, преобразуйте вашу модель ограничений (предположительно в файл где-нибудь на диске) в формат, который может использовать JAXP. Загрузите файл в экземпляр Source. (Я рассмотрю Source более детально во второй части статьи; а сейчас просто знайте, что он представляет документ где-нибудь на диске как DOM Document, либо все что угодно.) Затем создайте SchemaFactory и загрузите схему при помощи SchemaFactory.newSchema(Source), который возвратит новый объект Schema. И, наконец, используя этот объект Schema, создайте новый объект Validator путем вызова Schema.newValidator(). Листинг 5 должен существенно прояснить все то, о чем я только что говорил:

Листинг 5. Использование среды JAXP для проверки корректности
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(args[0]));

// Подготовка к проверке
SchemaFactory constraintFactory = 
    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source constraints = new StreamSource(new File(args[1]));
Schema schema = constraintFactory.newSchema(constraints);
Validator validator = schema.newValidator();

// Проверить DOM-дерево
try {
    validator.validate(new DOMSource(doc));
    System.out.println("Document validates fine.");
} catch (org.xml.sax.SAXException e) {
    System.out.println("Validation error: " + e.getMessage());
}

Это все довольно просто, если вы поняли суть. Напишите этот код самостоятельно или проверьте полный листинг (см. раздел "Загрузка").


Замена анализатора

Сменить анализатор, используемый JAXP-классами конструктора, легко. Смена анализатора фактически означает смену конструктора анализатора, поскольку все экземпляры SAXParser и DocumentBuilder создаются этими конструкторами. Конструкторы определяют тип загруженного анализатора, то есть, это конструкторы, которые вы должны заменить. Для замены реализации интерфейса SAXParserFactory установите системное свойство Java javax.xml.parsers.SAXParserFactory. Если это свойство не определено, возвращается реализация по умолчанию (анализатор, который указал ваш поставщик). Аналогичный принцип применим и для используемой вами реализации DocumentBuilderFactory. В этом случае запрашивается системное свойство javax.xml.parsers.DocumentBuilderFactory.


Заключение

Во время чтения этой статьи вы увидели почти все возможности JAXP:

  • Обеспечение функций перехвата для SAX
  • Обеспечение функций перехвата для DOM
  • Обеспечение простой смены анализатора

Для понимания функций JAXP-анализа и проверки корректности вы пройдете через немного мудреный материал. Наиболее сложными моментами в работе с JAXP являются изменение системного свойства, установка проверки корректности через конструктор, а не через анализатор или компоновщик, и понимание того, для чего JAXP не предназначен. JAXP обеспечивает вспомогательный подключаемый слой над двумя популярными API Java и XML. Он делает ваш код независимым от производителя и позволяет менять анализатор даже без перекомпилирования вашего кода. Итак, загружайте JAXP и вперед! В части 2 мы рассмотрим применение JAXP для трансформирования XML-документов.


Загрузка

ОписаниеИмяРазмер
Sample code for All about JAXPx-jaxp-all-about.zip5 KB

Ресурсы

  • Оригинальная статья "All about JAXP, Part 1"
  • Посетите форум developerWorksXML and Java technology, который ведет Бретт Маклафлин (Brett McLaughlin), для получения дополнительной информации о работе с этими двумя технологиями.
  • Дополнительную информацию о JAXP можно найти на странице технологий Java и XML фирмы Sun.
  • Если вы новичок в программировании на языке Java, вы можете получить JAXP вместе с полным JDK, загрузив дистрибутив Java 5.0.
  • Прочитайте серию статей (состоящую из двух частей) "Что нового в JAXP 1.3?", содержащую подробный обзор новых функций в JAXP 1.3:
    • В части 1 (ноябрь 2004) предоставляется краткий обзор спецификации JAXP, детально рассматриваются изменения в пакете javax.xml.parsers и описывается схема кэширования и проверка корректности.
    • В части 2 (декабрь 2004) описываются инструменты, добавляющие поддержку определенных в спецификации Namespaces in XML концепций. В ней также описываются изменения в пакете javax.xml.transform.
  • Изучите подробнее API, с которыми работает JAXP. Начните с SAX 2 for Java на web-сайте SAX, а затем взгляните на DOM на Web-сайте W3C.
  • Загрузите анализатор Apache Xerces в реализации JDK 5.0.
  • В статье "Достижение независимости от поставщика при помощи SAX" (developerWorks, март 2001) приводится информация по использованию SAX и вспомогательных классов SAX для достижения независимости от поставщика в ваших основанных на SAX приложениях.
  • Изучите JDOM, набор инструментальных программ с открытым исходным кодом, обеспечивающий способ представления XML-документов в языке программирования Java для легкого и эффективного чтения, записи и обработки.
  • Информацию о том, как JDOM облегчает обработку XML-документов для Java-разработчиков, можно найти в статье "Упрощение XML-программирования при помощи JDOM" (developerWorks, май 2001).
  • Обратите внимание на dom4j - библиотеку с открытым исходным кодом для работы с XML, XPath и XSLT на платформе Java.
  • Прочитайте книгу Брета Маклафлина (Brett McLaughlin) "Java и XML"№(O'Reilly & Associates, 2001), в которой объясняется использование XML для создания корпоративных Web-приложений.
  • В учебнике Дуга Тидвела (Doug Tidwell) "XML-программирование в технологии Java, Часть 1" (developerWorks, январь 2004) рассмотрены основы обработки XML-документов с использованием технологии Java. Во второй части (июль 2004) рассмотрены более сложные темы, такие как работа с пространством имен, проверка корректности XML-документов, построение XML-структур без обычного XML-документа. Наконец, в третьей части (июль 2004) рассматриваются более сложные задачи, такие как генерирование структур XML-данных, обработка этих структур и интерфейс XML-анализаторов с источниками данных формата, отличного от XML.
  • Нужно более общее введение в XML? Попробуйте учебное пособие "Введение в XML" (developerWorks, август 2002) и другие образовательные материалы, рассматривающие наиболее фундаментальные темы.
  • На сайте developerWorks Developer Bookstore можно найти множество материалов по XML.
  • Узнайте, как стать IBM Certified Developer в XML и смежных технологиях.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Технология Java
ArticleID=96638
ArticleTitle=Все о JAXP, Часть 1
publish-date=05172005