Suche…


Bemerkungen

XML-Parsing ist die Interpretation von XML-Dokumenten, um ihren Inhalt mithilfe sinnvoller Konstrukte zu manipulieren, entweder "Knoten", "Attribute", "Dokumente", "Namespaces" oder Ereignisse, die sich auf diese Konstrukte beziehen.

Java verfügt über eine native API für die XML-Dokumentenverarbeitung, die als JAXP oder Java-API für die XML-Verarbeitung bezeichnet wird . JAXP und eine Referenzimplementierung sind seit Java 1.4 (JAXP v1.1) in jeder Java-Version enthalten und haben sich seitdem weiterentwickelt. Java 8 wird mit JAXP Version 1.6 ausgeliefert.

Die API bietet verschiedene Möglichkeiten für die Interaktion mit XML-Dokumenten.

  • Die DOM-Schnittstelle (Document Object Model)
  • Die SAX-Schnittstelle (Simple API for XML)
  • Die StAX-Schnittstelle (Streaming-API für XML)

Prinzipien der DOM-Schnittstelle

Die DOM-Schnittstelle soll eine W3C-DOM- kompatible Methode zur Interpretation von XML bieten. Verschiedene Versionen von JAXP haben verschiedene DOM-Spezifikationsebenen (bis zu Stufe 3) unterstützt.

Unter der Document Object Model-Schnittstelle wird ein XML-Dokument beginnend mit dem "Dokumentelement" als Baum dargestellt. Der Basistyp des API ist die Node - Typ, es von einem navigieren können Node zu seinem übergeordneten, seine Kinder oder seine Geschwister (obwohl nicht alle Node s Kinder haben kann, beispielsweise Text - Knoten endgültig in dem Baum sind, und niemals Kinder haben). XML-Tags werden als Element s dargestellt, wodurch der Node durch attributbezogene Methoden erweitert wird.

Die DOM-Schnittstelle ist sehr nützlich, da sie ein "einzeiliges" Parsing von XML-Dokumenten als Baumstrukturen ermöglicht und die einfache Modifizierung des erstellten Baums (Knotenzusatz, Unterdrückung, Kopieren, ...) und schließlich dessen Serialisierung (Back to Disk) ermöglicht ) nach Änderungen. Dies hat jedoch einen Preis: Der Baum befindet sich im Arbeitsspeicher. Daher sind DOM-Bäume für große XML-Dokumente nicht immer praktisch. Außerdem ist die Konstruktion des Baums nicht immer die schnellste Methode, um mit XML-Inhalten umzugehen, insbesondere wenn man nicht an allen Teilen des XML-Dokuments interessiert ist.

Prinzipien der SAX-Schnittstelle

Die SAX-API ist eine ereignisorientierte API für den Umgang mit XML-Dokumenten. Bei diesem Modell werden die Komponenten eines XML-Dokuments als Ereignisse interpretiert (z. B. "Ein Tag wurde geöffnet", "Ein Tag wurde geschlossen", "Ein Textknoten wurde gefunden", "Ein Kommentar wurde gefunden"). ..

Die SAX-API verwendet einen "Push-Parsing" -Ansatz, bei dem ein SAX- Parser für die Interpretation des XML-Dokuments verantwortlich ist und Methoden auf einem Delegaten (einem ContentHandler ) ContentHandler , um mit allen Ereignissen im XML-Dokument umzugehen. Normalerweise schreibt man nie einen Parser, aber man stellt einen Handler bereit, um alle benötigten Informationen aus dem XML-Dokument zu erhalten.

Die SAX-Schnittstelle überwindet die Einschränkungen der DOM-Schnittstelle, indem nur die minimal erforderlichen Daten auf Parser-Ebene (z. B. Namespaces-Kontexte, Validierungsstatus) beibehalten werden. Daher sind nur Informationen, die vom ContentHandler aufbewahrt werden ContentHandler für die Sie als Entwickler verantwortlich sind, verantwortlich in Erinnerung gehalten. Der Kompromiss besteht darin, dass es mit einem solchen Ansatz keine Möglichkeit gibt, "in der Zeit zurück zu gehen / das XML-Dokument": Während DOM einem Node erlaubt, zu seinem übergeordneten Element zurückzukehren, gibt es keine solche Möglichkeit in SAX.

Prinzipien der StAX-Schnittstelle

Die StAX-API verfolgt einen ähnlichen Ansatz für die Verarbeitung von XML wie die SAX-API (dh ereignisgesteuert). Der einzige sehr wichtige Unterschied besteht darin, dass StAX ein Pull-Parser ist (bei dem SAX ein Push-Parser war). In SAX hat der Parser Kontrolle und verwendet Callbacks für den ContentHandler . In Stax rufen Sie den Parser auf und steuern, wann das nächste XML-Ereignis abgerufen werden soll.

Die API beginnt mit XMLStreamReader (oder XMLEventReader ). Hierbei handelt es sich um die Gateways, über die der Entwickler nextEvent() in einer Iterator-Art fragen kann.

Analysieren und Navigieren eines Dokuments mithilfe der DOM-API

Betrachten Sie das folgende Dokument:

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

Man kann den folgenden Code verwenden, um aus einem String eine DOM-Struktur zu erstellen:

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");
}
}

Der Code ergibt Folgendes:

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

Analysieren eines Dokuments mit der StAX-API

Betrachten Sie das folgende Dokument:

<?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>

Sie können den folgenden Code verwenden, um ihn zu analysieren und eine Zuordnung der Buchtitel anhand der Buch-ID zu erstellen.

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);
}

Dies gibt aus:

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}

In diesem Beispiel muss man einige Dinge beachten:

  1. Die Verwendung von xmlStreamReader.getAttributeValue funktioniert, da wir zuerst überprüft haben, ob sich der Parser im START_ELEMENT . In allen anderen Zuständen (außer ATTRIBUTES ) muss der Parser IllegalStateException , da Attribute nur am Anfang von Elementen IllegalStateException werden können.

  2. Dasselbe gilt für xmlStreamReader.getTextContent() . Es funktioniert, weil wir uns bei START_ELEMENT und in diesem Dokument wissen, dass das <book> -Element keine START_ELEMENT Nicht-Text-Knoten enthält.

Für die Analyse komplexerer Dokumente (tiefere, verschachtelte Elemente, ...) BookParser es sich, den Parser an BookParser oder andere BookParser zu "delegieren", z vom START_ELEMENT bis zum END_ELEMENT des Buch-XML-Tags.

Man kann auch ein Stack Objekt verwenden, um wichtige Daten in der Struktur nach oben und unten zu halten.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow