Java Language
XML-Analyse mit den JAXP-APIs
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:
Die Verwendung von
xmlStreamReader.getAttributeValue
funktioniert, da wir zuerst überprüft haben, ob sich der Parser imSTART_ELEMENT
. In allen anderen Zuständen (außerATTRIBUTES
) muss der ParserIllegalStateException
, da Attribute nur am Anfang von ElementenIllegalStateException
werden können.Dasselbe gilt für
xmlStreamReader.getTextContent()
. Es funktioniert, weil wir uns beiSTART_ELEMENT
und in diesem Dokument wissen, dass das<book>
-Element keineSTART_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.