Spec-Zone .ru
спецификации, руководства, описания, API
След: API Java для XML, Обрабатывающего (JAXP)
Урок: Потоковая передача API для XML
Пример кода
Домашняя страница > API Java для XML, Обрабатывающего (JAXP) > Потоковая передача API для XML

Пример кода

Этот раздел ступает через пример код StAX, включенный в ссылочный пакет реализации JAXP. Все каталоги в качестве примера, используемые в этом разделе, располагаются в каталоге INSTALL_DIR/jaxp-version/samples/stax.

Темы, затронутые в этом разделе, следующие:

Организация Примера кода

Каталог INSTALL_DIR/jaxp-version/samples/stax содержит шесть каталогов StAX в качестве примера:

Все примеры StAX за исключением примера Писателя используют XML-документ в качестве примера, BookCatalog.xml.

XML-документ в качестве примера

XML-документ в качестве примера, BookCatalog.xml, используемый большинством классов StAX в качестве примера, является простым книжным каталогом, основанным на общем пространстве имен BookCatalogue. Содержание BookCatalog.xml упоминается ниже:

<?xml version="1.0" encoding="UTF-8"?>
<BookCatalogue xmlns="http://www.publishing.org">
<Book>
    <Title>Yogasana Vijnana: the Science of Yoga</Title>
    <author>Dhirendra Brahmachari</Author>
    <Date>1966</Date>
    <ISBN>81-40-34319-4</ISBN>
    <Publisher>Dhirendra Yoga Publications</Publisher>
    <Cost currency="INR">11.50</Cost>
</Book>
<Book>
    <Title>The First and Last Freedom</Title>
    <Author>J. Krishnamurti</Author>
    <Date>1954</Date>
    <ISBN>0-06-064831-7</ISBN>
    <Publisher>Harper &amp; Row</Publisher>
    <Cost currency="USD">2.95</Cost>
</Book>
</BookCatalogue>

Пример курсора

Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/cursor/, CursorParse.java демонстрирует, как использовать API курсора StAX, чтобы считать XML-документ. В примере Курсора приложение дает синтаксическому анализатору команду читать следующее событие во входном потоке XML, вызывая next().

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

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

Продвижение через События

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

try {
    for (int i = 0 ; i < count ; i++) {
        // pass the file name.. all relative entity
        // references will be resolved against this 
        // as base URI.
        XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename,
                                   new FileInputStream(filename));

        // when XMLStreamReader is created, 
        // it is positioned at START_DOCUMENT event.
        int eventType = xmlr.getEventType();
        printEventType(eventType);
        printStartDocument(xmlr);

        // check if there are more events 
        // in the input stream
        while(xmlr.hasNext()) {
            eventType = xmlr.next();
            printEventType(eventType);

            // these functions print the information 
            // about the particular event by calling 
            // the relevant function
            printStartElement(xmlr);
            printEndElement(xmlr);
            printText(xmlr);
            printPIData(xmlr);
            printComment(xmlr);
        }
    }
}

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

Возврат Строковых Представлений

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

public final static String getEventTypeString(int eventType) {
    switch (eventType) {
        case XMLEvent.START_ELEMENT:
            return "START_ELEMENT";

        case XMLEvent.END_ELEMENT:
            return "END_ELEMENT";

        case XMLEvent.PROCESSING_INSTRUCTION:
            return "PROCESSING_INSTRUCTION";

        case XMLEvent.CHARACTERS:
            return "CHARACTERS";

        case XMLEvent.COMMENT:
            return "COMMENT";

        case XMLEvent.START_DOCUMENT:
            return "START_DOCUMENT";

        case XMLEvent.END_DOCUMENT:
            return "END_DOCUMENT";

        case XMLEvent.ENTITY_REFERENCE:
            return "ENTITY_REFERENCE";

        case XMLEvent.ATTRIBUTE:
            return "ATTRIBUTE";

        case XMLEvent.DTD:
            return "DTD";

        case XMLEvent.CDATA:
            return "CDATA";

        case XMLEvent.SPACE:
            return "SPACE";
    }
    return "UNKNOWN_EVENT_TYPE , " + eventType;
}

Выполнять Пример Курсора

  1. Чтобы скомпилировать и выполнить пример курсора, в окне терминала, идут в каталог INSTALL_DIR/jaxp-version/samples/ и вводят следующее:
    javac stax/cursor/*.java
    
  2. Выполните выборку CursorParse на файле BookCatalogue.xml со следующей командой.

    CursorParse распечатает каждый элемент файла BookCatalogue.xml.

java stax/event/CursorParse stax/data/BookCatalogue.xml

Пример курсора к событию

Расположенный в каталоге работы-install/javaeetutorial5/examples/stax/cursor2event/, CursorApproachEventObject.java демонстрирует, как получить информацию, возвращенную объектом XMLEvent, используя API курсора.

Идея здесь состоит в том, что API курсора, XMLStreamReader возвращает целочисленные константы, соответствующие определенным событиям, в то время как событие iterator XMLEventReader API возвращает неизменные и персистентные объекты-события. XMLStreamReader более эффективен, но XMLEventReader легче использовать, потому что вся информация, связанная с определенным событием, инкапсулируется в возвращенном объекте XMLEvent. Однако, недостаток подхода события является дополнительными издержками создания объектов для каждого события, которое использует и время и память.

С этим умом XMLEventAllocator может использоваться, чтобы получить информацию о событии как объект XMLEvent, используя API курсора.

Инстанцирование XMLEventAllocator

Первый шаг должен создать новый XMLInputFactory и инстанцировать XMLEventAllocator:

XMLInputFactory xmlif = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + xmlif);
xmlif.setEventAllocator(new XMLEventAllocatorImpl());
allocator = xmlif.getEventAllocator();
XMLStreamReader xmlr = xmlif.createXMLStreamReader(filename,
                           new FileInputStream(filename));

Создание События Iterator

Следующий шаг должен создать событие iterator:

int eventType = xmlr.getEventType();

while (xmlr.hasNext()) {
    eventType = xmlr.next();
    // Get all "Book" elements as XMLEvent object
    if (eventType == XMLStreamConstants.START_ELEMENT 
        && xmlr.getLocalName().equals("Book")) {
        // get immutable XMLEvent
        StartElement event = getXMLEvent(xmlr).asStartElement();
        System.out.println ("EVENT: " + event.toString());
    }
}

Создание Метода Средства выделения

Заключительный шаг должен создать метод XMLEventAllocator:

private static XMLEvent getXMLEvent(XMLStreamReader reader)
    throws XMLStreamException {
    return allocator.allocate(reader);
}

Выполнять Пример Курсора к событию

  1. Чтобы скомпилировать и выполнить курсор — к — пример события, в окне терминала, идет в каталог INSTALL_DIR/jaxp-version/samples/ и вводит следующее:
    javac -classpath ../lib/jaxp-ri.jar stax/cursor2event/*.java
    
  2. Выполните выборку CursorApproachEventObject на файле BookCatalogue.xml со следующей командой.
    java stax/cursor2event/CursorApproachEventObject stax/data/BookCatalogue.xml
    

    CursorApproachEventObject распечатает список событий, определенных файлом BookCatalogue.xml.

Пример события

Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/event/, EventParse.java демонстрирует, как использовать API события StAX, чтобы считать XML-документ.

Создание Входной Фабрики

Первый шаг должен создать новый экземпляр XMLInputFactory:

XMLInputFactory factory = XMLInputFactory.newInstance();
System.out.println("FACTORY: " + factory);

Создание Читателя События

Следующий шаг должен создать экземпляр XMLEventReader:

XMLEventReader r = factory.createXMLEventReader
                       (filename, new FileInputStream(filename));

Создание События Iterator

Третий шаг должен создать событие iterator:

XMLEventReader r = factory.createXMLEventReader
                       (filename, new FileInputStream(filename));
while (r.hasNext()) {
    XMLEvent e = r.nextEvent();
    System.out.println(e.toString());
}

Получение Потока событий

Заключительный шаг должен получить базовый поток событий:

public final static String getEventTypeString(int eventType) {
    switch (eventType) {
        case XMLEvent.START_ELEMENT:
            return "START_ELEMENT";

        case XMLEvent.END_ELEMENT:
            return "END_ELEMENT";

        case XMLEvent.PROCESSING_INSTRUCTION:
            return "PROCESSING_INSTRUCTION";

        case XMLEvent.CHARACTERS:
            return "CHARACTERS";

        case XMLEvent.COMMENT:
            return "COMMENT";

        case XMLEvent.START_DOCUMENT:
            return "START_DOCUMENT";

        case XMLEvent.END_DOCUMENT:
            return "END_DOCUMENT";

        case XMLEvent.ENTITY_REFERENCE:
            return "ENTITY_REFERENCE";

        case XMLEvent.ATTRIBUTE:
            return "ATTRIBUTE";

        case XMLEvent.DTD:
            return "DTD";

        case XMLEvent.CDATA:
            return "CDATA";

        case XMLEvent.SPACE:
            return "SPACE";
    }
    return "UNKNOWN_EVENT_TYPE," + eventType;
}

Возврат Вывода

Когда Вы выполняете пример События, EventParse, class компилируется, и поток XML анализируется как события и возвращается к STDOUT. Например, экземпляр элемента Author возвращается как:

<[’http://www.publishing.org’]::Author>
    Dhirendra Brahmachari
</[’http://www.publishing.org’]::Author>

Отметьте в этом примере, что событие включает открывающий и закрывающий тэг, оба из которых включают пространство имен. Контент элемента возвращается как строка в пределах тегов.

Точно так же экземпляр элемента Cost возвращается как:

<[’http://www.publishing.org’]::Cost currency=’INR’>
    11.50
</[’http://www.publishing.org’]::Cost

В этом случае атрибут currency и значение возвращаются в открывающем тэге для события.

Выполнять Пример События

  1. Чтобы скомпилировать и выполнить пример события, в окне терминала, идут в каталог INSTALL_DIR/jaxp-version/samples/ и вводят следующее:
    javac -classpath ../lib/jaxp-ri.jar stax/event/*.java
    
  2. Выполните выборку EventParse на файле BookCatalogue.xml со следующей командой.
    java stax/event/EventParse stax/data/BookCatalogue.xml
    

    EventParse распечатает данные от всех элементов, определенных файлом BookCatalogue.xml.

Пример фильтра

Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/filter/, MyStreamFilter.java демонстрирует, как использовать потоковый API фильтра StAX, чтобы отфильтровать события, не необходимые Вашему приложению. В этом примере, фильтры-анализаторы все события кроме StartElement и EndElement.

Реализация Класса StreamFilter

MyStreamFilter class реализует javax.xml.stream.StreamFilter:

public class MyStreamFilter implements javax.xml.stream.StreamFilter {
    // ...
}

Создание Входной Фабрики

Следующий шаг должен создать экземпляр XMLInputFactory. В этом случае различные свойства также устанавливаются на фабрике:

XMLInputFactory xmlif = null ;

try {
    xmlif = XMLInputFactory.newInstance();
    xmlif.setProperty(
        XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,
        Boolean.TRUE);

    xmlif.setProperty(
        XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
        Boolean.FALSE);

    xmlif.setProperty(
        XMLInputFactory.IS_NAMESPACE_AWARE,
        Boolean.TRUE);

    xmlif.setProperty(
        XMLInputFactory.IS_COALESCING,
        Boolean.TRUE);
} 
catch (Exception ex) {
    ex.printStackTrace();
}

System.out.println("FACTORY: " + xmlif);
System.out.println("filename = "+ filename);

Создание Фильтра

Следующий шаг должен инстанцировать входного потока файла и создать потоковый фильтр:

FileInputStream fis = new FileInputStream(filename);
XMLStreamReader xmlr = xmlif.createFilteredReader(
                           xmlif.createXMLStreamReader(fis), 
                           new MyStreamFilter());

int eventType = xmlr.getEventType();
printEventType(eventType);

while (xmlr.hasNext()) {
    eventType = xmlr.next();
    printEventType(eventType);
    printName(xmlr,eventType);
    printText(xmlr);

    if (xmlr.isStartElement()) {
        printAttributes(xmlr);
    }
    printPIData(xmlr);
    System.out.println("-----------------------");
}

Получение Потока событий

Следующий шаг должен получить поток событий. Это приканчивается в основном тот же самый путь как в конечном счете пример.

Фильтрация Потока

Заключительный шаг должен фильтровать поток:

public boolean accept(XMLStreamReader reader) {
    if (!reader.isStartElement() && !reader.isEndElement())
        return false;
    else
        return true;
}

Возврат Вывода

Когда Вы выполняете пример Фильтра, MyStreamFilter, class компилируется, и поток XML анализируется как события и возвращается к STDOUT. Например, событие Author возвращается следующим образом:

EVENT TYPE(1):START_ELEMENT
HAS NAME: Author
HAS NO TEXT
HAS NO ATTRIBUTES
-----------------------------
EVENT TYPE(2):END_ELEMENT
HAS NAME: Author
HAS NO TEXT
-----------------------------

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

EVENT TYPE(1):START_ELEMENT
HAS NAME: Cost
HAS NO TEXT

HAS ATTRIBUTES:
 ATTRIBUTE-PREFIX:
 ATTRIBUTE-NAMESP: null
ATTRIBUTE-NAME:   currency
ATTRIBUTE-VALUE: USD
ATTRIBUTE-TYPE:  CDATA

-----------------------------
EVENT TYPE(2):END_ELEMENT
HAS NAME: Cost
HAS NO TEXT
-----------------------------

См. API Iterator и Чтение XML Потоки для более детального обсуждения парсинга события StAX.

Выполнять Пример Фильтра

  1. Чтобы скомпилировать и выполнить пример Фильтра, в окне терминала, идут в каталог INSTALL_DIR/jaxp-version/samples/ и вводят следующее:
    javac -classpath ../lib/jaxp-ri.jar stax/filter/*.java
    
  2. Выполните выборку MyStreamFilter на файле BookCatalogue.xml со следующей командой. Этот пример требует, чтобы системное свойство java.endorsed.dirs было подано, указало на каталог samples/lib.
    java -Djava.endorsed.dirs=../lib stax/filter/MyStreamFilter -f stax/data/BookCatalogue.xml
    

    MyStreamFilter распечатает события, определенные файлом BookCatalogue.xml как поток XML.

Пример чтения-и-записи

Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/readnwrite/, EventProducerConsumer.java демонстрирует, как использовать синтаксический анализатор StAX одновременно и в качестве производителя и в качестве потребителя.

StAX API XMLEventWriter расширяется от интерфейса XMLEventConsumer, и упоминается как потребитель события. В отличие от этого, XMLEventReader является производителем события. StAX поддерживает одновременное чтение и запись, так, что возможно читать из одного потока XML последовательно и одновременно записать в другой поток.

Пример Чтения-и-записи показывает, как механизм производителя/потребителя StAX может использоваться, чтобы читать и записать одновременно. Этот пример также показывает, как поток может быть изменен и как новые события могут быть добавлены динамически и затем записаны различному потоку.

Создание События, Producer/Consumer

Первый шаг должен инстанцировать фабрики события и затем создать экземпляр события, producer/consumer:

XMLEventFactory m_eventFactory = XMLEventFactory.newInstance();

public EventProducerConsumer() {
    // ...
    try {
        EventProducerConsumer ms = new EventProducerConsumer();
    
        XMLEventReader reader = XMLInputFactory.newInstance().
        createXMLEventReader(new java.io.FileInputStream(args[0]));
    
        XMLEventWriter writer = 
            XMLOutputFactory.newInstance().createXMLEventWriter(System.out);
    }
    // ...
}

Создание Iterator

Следующий шаг должен создать iterator, чтобы проанализировать поток:

while (reader.hasNext()) {
    XMLEvent event = (XMLEvent)reader.next();
    if (event.getEventType() == event.CHARACTERS) {
        writer.add(ms.getNewCharactersEvent(event.asCharacters()));
    }
    else {
        writer.add(event);
    }
}
writer.flush();

Создание Писателя

Заключительный шаг должен создать потокового писателя в форме нового события Character:

Characters getNewCharactersEvent(Characters event) {
    if (event.getData().equalsIgnoreCase("Name1")) {
        return m_eventFactory.createCharacters(
                   Calendar.getInstance().getTime().toString());
    }
    // else return the same event
    else {
        return event;
    }
}

Возврат Вывода

Когда Вы выполняете пример Чтения-и-записи, EventProducerConsumer, class компилируется, и поток XML анализируется как события и записывается обратно к STDOUT. Вывод является содержанием файла BookCatalog.xml, описанного в XML-документе В качестве примера.

Выполнять Пример Чтения-и-записи

  1. Чтобы скомпилировать и выполнить Рида — и — пример Записи, в окне терминала, идет в каталог INSTALL_DIR/jaxp-version/samples/ и вводит следующее:
    javac -classpath ../lib/jaxp-ri.jar stax/readnwrite/*.java
    
  2. Выполните выборку EventProducerConsumer на файле BookCatalogue.xml со следующей командой.
    java stax/readnwrite/EventProducerConsumer stax/data/BookCatalogue.xml
    

    EventProducerConsumer распечатает контент файла BookCatalogue.xml.

Пример писателя

Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/writer/, CursorWriter.java демонстрирует, как использовать API курсора StAX, чтобы записать поток XML.

Создание Выходной Фабрики

Первый шаг должен создать экземпляр XMLOutputFactory:

XMLOutputFactory xof =  XMLOutputFactory.newInstance();

Создание Потокового Писателя

Следующий шаг должен создать экземпляр XMLStreamWriter:

XMLStreamWriter xtw = null;

Запись Потока

Заключительный шаг должен записать поток XML. Отметьте, что поток сбрасывается и закрывается после того, как заключительный EndDocument пишется:

xtw = xof.createXMLStreamWriter(new FileWriter(fileName));

xtw.writeComment("all elements here are explicitly in the HTML namespace");
xtw.writeStartDocument("utf-8","1.0");
xtw.setPrefix("html", "http://www.w3.org/TR/REC-html40");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40","html");
xtw.writeNamespace("html", "http://www.w3.org/TR/REC-html40");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40", "head");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40", "title");
xtw.writeCharacters("Frobnostication");
xtw.writeEndElement();
xtw.writeEndElement();

xtw.writeStartElement("http://www.w3.org/TR/REC-html40", "body");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40", "p");
xtw.writeCharacters("Moved to");
xtw.writeStartElement("http://www.w3.org/TR/REC-html40", "a");
xtw.writeAttribute("href","http://frob.com");
xtw.writeCharacters("here");
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndElement();
xtw.writeEndDocument();

xtw.flush();
xtw.close();

Возврат Вывода

Когда Вы выполняете пример Писателя, CursorWriter, class компилируется, и поток XML анализируется как события и пишется файлу под названием dist/CursorWriter-Output:

<!--all elements here are explicitly in the HTML namespace-->
<?xml version="1.0" encoding="utf-8"?>
<html:html xmlns:html="http://www.w3.org/TR/REC-html40">
<html:head>
<html:title>Frobnostication</html:title></html:head>
<html:body>
<html:p>Moved to <html:a href="http://frob.com">here</html:a>
</html:p>
</html:body>
</html:html>

В фактическом файле dist/CursorWriter-Output этот поток пишется без любых разрывов строки; повреждения были добавлены здесь, чтобы сделать перечисление легче читать. В этом примере, как с объектным потоком в конечном счете пример, префикс пространства имен добавляется и к открытию и к закрытию HTML-тэгов. Добавление этого префикса не требуется спецификацией StAX, но это - хорошая практика, когда заключительный контекст потока вывода не окончательно известен.

Выполнять Пример Писателя

  1. Чтобы скомпилировать и выполнить пример Писателя, в окне терминала, идут в каталог INSTALL_DIR/jaxp-version/samples/ и вводят следующее:
    javac -classpath \
        ../lib/jaxp-ri.jar stax/writer/*.java
    
  2. Выполните выборку CursorWriter, определяя имя файла, которому должен быть записан вывод.
    java stax/writer/CursorWriter -f output_file
    

    CursorWriter создаст выходной файл соответствующего имени, которое содержит данные, показанные в Возврате Вывода.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Реализация Синтаксического анализатора XML Потоковой передачи Oracle
Следующая страница: Дополнительная информация