Spec-Zone .ru
спецификации, руководства, описания, API
|
Этот раздел ступает через пример код StAX, включенный в ссылочный пакет реализации JAXP. Все каталоги в качестве примера, используемые в этом разделе, располагаются в каталоге INSTALL_DIR/jaxp-version/samples/stax.
Темы, затронутые в этом разделе, следующие:
Каталог INSTALL_DIR/jaxp-version/samples/stax содержит шесть каталогов StAX в качестве примера:
Пример курсора: каталог cursor содержит CursorParse.java, который иллюстрирует, как использовать XMLStreamReader (курсор) API, чтобы считать XML-файл.
Пример курсора к событию: каталог cursor2event содержит CursorApproachEventObject.java, который иллюстрирует, как приложение может получить информацию как объект XMLEvent при использовании API курсора.
Пример события: каталог event содержит EventParse.java, который иллюстрирует, как использовать XMLEventReader (событие iterator) API, чтобы считать XML-файл.
Пример фильтра: каталог filter содержит MyStreamFilter.java, который иллюстрирует, как использовать Потоковые API Фильтра StAX. В этом примере фильтр принимает только события StartElement И EndElement, и отфильтровывает остаток от событий.
Пример чтения-и-записи: каталог readnwrite содержит EventProducerConsumer.java, который иллюстрирует, как механизм производителя/потребителя StAX может использоваться, чтобы одновременно читать и записать потоки XML.
Пример писателя: каталог writer содержит CursorWriter.java, который иллюстрирует, как использовать XMLStreamWriter, чтобы записать XML-файл programatically.
Все примеры StAX за исключением примера Писателя используют XML-документ в качестве примера, BookCatalog.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 & 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; }
javac stax/cursor/*.java
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 курсора.
Первый шаг должен создать новый 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:
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); }
javac -classpath ../lib/jaxp-ri.jar stax/cursor2event/*.java
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:
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 и значение возвращаются в открывающем тэге для события.
javac -classpath ../lib/jaxp-ri.jar stax/event/*.java
java stax/event/EventParse stax/data/BookCatalogue.xml
EventParse распечатает данные от всех элементов, определенных файлом BookCatalogue.xml.
Расположенный в каталоге INSTALL_DIR/jaxp-version/samples/stax/filter/, MyStreamFilter.java демонстрирует, как использовать потоковый API фильтра StAX, чтобы отфильтровать события, не необходимые Вашему приложению. В этом примере, фильтры-анализаторы все события кроме StartElement и EndElement.
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.
javac -classpath ../lib/jaxp-ri.jar stax/filter/*.java
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:
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, чтобы проанализировать поток:
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-документе В качестве примера.
javac -classpath ../lib/jaxp-ri.jar stax/readnwrite/*.java
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, но это - хорошая практика, когда заключительный контекст потока вывода не окончательно известен.
javac -classpath \ ../lib/jaxp-ri.jar stax/writer/*.java
java stax/writer/CursorWriter -f output_file
CursorWriter создаст выходной файл соответствующего имени, которое содержит данные, показанные в Возврате Вывода.