Поиск…


замечания

XML Parsing - это интерпретация XML-документов, чтобы манипулировать их контентом с помощью разумных конструкций, будь то «узлы», «атрибуты», «документы», «пространства имен» или события, связанные с этими конструкциями.

Java имеет собственный API для обработки документов XML, называемый JAXP или Java API для обработки XML . JAXP и эталонная реализация были включены в каждую версию Java после Java 1.4 (JAXP v1.1) и с тех пор развиваются. Java 8 поставляется с JAXP версии 1.6.

API предоставляет различные способы взаимодействия с XML-документами, которые:

  • Интерфейс DOM (Document Object Model)
  • Интерфейс SAX (простой API для XML)
  • Интерфейс StAX (Streaming API для XML)

Принципы интерфейса DOM

Интерфейс DOM предназначен для предоставления W3C DOM- совместимого способа интерпретации XML. Различные версии JAXP поддерживают различные спецификации DOM (до уровня 3).

В интерфейсе Document Object Model документ XML представлен как дерево, начиная с «Элемента документа». Базовый типом API является Node типа, это позволяет перемещаться от Node к его родителям, его детям, или его братьям (хотя, не все Node с может иметь детей, например, Text узлы являются окончательными в дереве, и никогда не имеют детей). Теги XML представлены как Element s, которые значительно расширяют Node с помощью связанных с атрибутами методов.

Интерфейс DOM очень полезен, поскольку он позволяет «одну строку» анализировать XML-документы как деревья и позволяет легко модифицировать построенное дерево (добавление узла, подавление, копирование и т. Д.) И, наконец, его сериализацию (обратно на диск ) после изменений. Это происходит по цене, однако: дерево находится в памяти, поэтому деревья DOM не всегда практичны для огромных XML-документов. Кроме того, построение дерева не всегда является самым быстрым способом работы с XML-контентом, особенно если его не интересуют все части документа XML.

Принципы интерфейса SAX

SAX API - это ориентированный на события API для работы с документами XML. В рамках этой модели компоненты XML-документов интерпретируются как события (например, «открыт тег», «тег закрыт», «встречен текстовый узел», «был встречен комментарий»). ..

API SAX использует подход «синтаксический разбор», где SAX Parser отвечает за интерпретацию XML-документа и вызывает методы для делегата ( ContentHandler ) для обработки любого события, которое встречается в документе XML. Обычно один никогда не пишет парсер, но один обеспечивает обработчик для сбора всей необходимой информации из XML-документа.

Интерфейс SAX преодолевает ограничения интерфейса DOM, сохраняя только минимально необходимые данные на уровне анализатора (например, контексты пространств имен, состояние проверки), поэтому только информация, ContentHandler для которой вы, разработчик, несет ответственность, - это хранится в памяти. Компромисс заключается в том, что при таком подходе нет возможности «вернуться во времени / XML-документ»: в то время как DOM позволяет Node возвращаться к его родительскому объекту, такой возможности нет в SAX.

Принципы интерфейса StAX

API StAX использует аналогичный подход для обработки XML как API SAX (т. Е. Управляемый событиями), единственное очень существенное отличие состоит в том, что StAX является синтаксическим анализатором (где SAX был парсером push). В SAX Parser находится под контролем и использует обратные вызовы в ContentHandler . В Stax вы вызываете парсер и управляете, когда / если вы хотите получить следующее «событие» XML.

API начинается с XMLStreamReader (или XMLEventReader ), которые являются шлюзами, через которые разработчик может спросить nextEvent() в стиле итератора.

Анализ и перемещение документа с использованием DOM API

Учитывая следующий документ:

<?xml version='1.0' encoding='UTF-8' ?>
<library>
   <book id='1'>Effective Java</book>
   <book id='2'>Java Concurrency In Practice</book>
</library>

Для построения дерева DOM из String можно использовать следующий код:

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;

public class DOMDemo {

public static void main(String[] args) throws Exception {
    String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
            + "<library>"
            + "<book id='1'>Effective Java</book>"
            + "<book id='2'>Java Concurrency In Practice</book>"
            + "</library>";

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    // This is useless here, because the XML does not have namespaces, but this option is usefull to know in cas
    documentBuilderFactory.setNamespaceAware(true);
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    // There are various options here, to read from an InputStream, from a file, ...
    Document document = documentBuilder.parse(new InputSource(new StringReader(xmlDocument)));

    // Root of the document
    System.out.println("Root of the XML Document: " + document.getDocumentElement().getLocalName());

    // Iterate the contents
    NodeList firstLevelChildren = document.getDocumentElement().getChildNodes();
    for (int i = 0; i < firstLevelChildren.getLength(); i++) {
        Node item = firstLevelChildren.item(i);
        System.out.println("First level child found, XML tag name is: " + item.getLocalName());
        System.out.println("\tid attribute of this tag is : " + item.getAttributes().getNamedItem("id").getTextContent());
    }

    // Another way would have been
    NodeList allBooks = document.getDocumentElement().getElementsByTagName("book");
}
}

Код дает следующее:

Root of the XML Document: library
First level child found, XML tag name is: book
id attribute of this tag is : 1
First level child found, XML tag name is: book
id attribute of this tag is : 2

Разбор документа с использованием API StAX

Учитывая следующий документ:

<?xml version='1.0' encoding='UTF-8' ?>
<library>
   <book id='1'>Effective Java</book>
   <book id='2'>Java Concurrency In Practice</book>
   <notABook id='3'>This is not a book element</notABook>
</library>

Можно использовать следующий код для его анализа и построения карты названий книг по идентификатору книги.

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

public class StaxDemo {

public static void main(String[] args) throws Exception {
    String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
            + "<library>"
                + "<book id='1'>Effective Java</book>"
                + "<book id='2'>Java Concurrency In Practice</book>"
                + "<notABook id='3'>This is not a book element </notABook>"
            + "</library>";

    XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
    // Various flavors are possible, e.g. from an InputStream, a Source, ...
    XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xmlDocument));

    Map<Integer, String> bookTitlesById = new HashMap<>();

    // We go through each event using a loop
    while (xmlStreamReader.hasNext()) {
        switch (xmlStreamReader.getEventType()) {
            case XMLStreamConstants.START_ELEMENT:
                System.out.println("Found start of element: " + xmlStreamReader.getLocalName());
                // Check if we are at the start of a <book> element
                if ("book".equals(xmlStreamReader.getLocalName())) {
                    int bookId = Integer.parseInt(xmlStreamReader.getAttributeValue("", "id"));
                    String bookTitle = xmlStreamReader.getElementText();
                    bookTitlesById.put(bookId, bookTitle);
                }
                break;
            // A bunch of other things are possible : comments, processing instructions, Whitespace...
            default:
                break;
        }
        xmlStreamReader.next();
    }

    System.out.println(bookTitlesById);
}

Эти результаты:

Found start of element: library
Found start of element: book
Found start of element: book
Found start of element: notABook
{1=Effective Java, 2=Java Concurrency In Practice}

В этом примере нужно позаботиться о нескольких вещах:

  1. Использование xmlStreamReader.getAttributeValue работает, потому что мы сначала отметили, что парсер находится в состоянии START_ELEMENT . В других состояниях (кроме ATTRIBUTES ) парсеру поручено IllegalStateException , поскольку атрибуты могут появляться только в начале элементов.

  2. xmlStreamReader.getTextContent() же самое касается xmlStreamReader.getTextContent() , он работает, потому что мы находимся в START_ELEMENT и мы знаем в этом документе, что элемент <book> не имеет дочерних узлов, не содержащих текст.

Для более сложных анализов документов (более глубокие, вложенные элементы, ...), хорошая практика «делегировать» парсер под-методам или другим объектам, например, иметь класс или метод BookParser и иметь дело с каждым элементом от START_ELEMENT до END_ELEMENT книги XML-тега.

Можно также использовать объект Stack для хранения важных данных вверх и вниз по дереву.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow