Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis
Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 8 Die eXtensible Markup Language (XML)
Pfeil 8.1 Auszeichnungssprachen
Pfeil 8.1.1 Die Standard Generalized Markup Language (SGML)
Pfeil 8.1.2 Extensible Markup Language (XML)
Pfeil 8.2 Eigenschaften von XML-Dokumenten
Pfeil 8.2.1 Elemente und Attribute
Pfeil 8.2.2 Beschreibungssprache für den Aufbau von XML-Dokumenten
Pfeil 8.2.3 Schema – die moderne Alternative zu DTD
Pfeil 8.2.4 Namensraum (Namespace)
Pfeil 8.2.5 XML-Applikationen *
Pfeil 8.3 Die Java-APIs für XML
Pfeil 8.3.1 Das Document Object Model (DOM)
Pfeil 8.3.2 Simple API for XML Parsing (SAX)
Pfeil 8.3.3 Pull-API StAX
Pfeil 8.3.4 Java Document Object Model (JDOM)
Pfeil 8.3.5 JAXP als Java-Schnittstelle zu XML
Pfeil 8.3.6 DOM-Bäume einlesen mit JAXP *
Pfeil 8.4 Java Architecture for XML Binding (JAXB)
Pfeil 8.4.1 Bean für JAXB aufbauen
Pfeil 8.4.2 Utility-Klasse JAXB
Pfeil 8.4.3 Ganze Objektgraphen schreiben und lesen
Pfeil 8.4.4 JAXBContext und Marshaller/Unmarshaller nutzen
Pfeil 8.4.5 Validierung
Pfeil 8.4.6 Weitere JAXB-Annotationen *
Pfeil 8.4.7 Beans aus XML-Schema-Datei generieren
Pfeil 8.5 Serielle Verarbeitung mit StAX
Pfeil 8.5.1 Unterschiede der Verarbeitungsmodelle
Pfeil 8.5.2 XML-Dateien mit dem Cursor-Verfahren lesen
Pfeil 8.5.3 XML-Dateien mit dem Iterator-Verfahren verarbeiten *
Pfeil 8.5.4 Mit Filtern arbeiten *
Pfeil 8.5.5 XML-Dokumente schreiben
Pfeil 8.6 Serielle Verarbeitung von XML mit SAX *
Pfeil 8.6.1 Schnittstellen von SAX
Pfeil 8.6.2 SAX-Parser erzeugen
Pfeil 8.6.3 Operationen der Schnittstelle ContentHandler
Pfeil 8.6.4 ErrorHandler und EntityResolver
Pfeil 8.7 XML-Dateien mit JDOM verarbeiten
Pfeil 8.7.1 JDOM beziehen
Pfeil 8.7.2 Paketübersicht *
Pfeil 8.7.3 Die Document-Klasse
Pfeil 8.7.4 Eingaben aus der Datei lesen
Pfeil 8.7.5 Das Dokument im XML-Format ausgeben
Pfeil 8.7.6 Der Dokumenttyp *
Pfeil 8.7.7 Elemente
Pfeil 8.7.8 Zugriff auf Elementinhalte
Pfeil 8.7.9 Liste mit Unterelementen erzeugen *
Pfeil 8.7.10 Neue Elemente einfügen und ändern
Pfeil 8.7.11 Attributinhalte lesen und ändern
Pfeil 8.7.12 XPath
Pfeil 8.8 Transformationen mit XSLT *
Pfeil 8.8.1 Templates und XPath als Kernelemente von XSLT
Pfeil 8.8.2 Umwandlung von XML-Dateien mit JDOM und JAXP
Pfeil 8.9 XML-Schema-Validierung *
Pfeil 8.9.1 SchemaFactory und Schema
Pfeil 8.9.2 Validator
Pfeil 8.9.3 Validierung unterschiedlicher Datenquellen durchführen
Pfeil 8.10 Zum Weiterlesen
 
Zum Seitenanfang

8.5Serielle Verarbeitung mit StAX Zur vorigen ÜberschriftZur nächsten Überschrift

Mit der Pull-API StAX lassen sich XML-Dokumente sehr performant ablaufen, jedoch nicht ändern.

Die allgemeine Vorgehensweise zum Parsen eines XML-Dokuments ist folgende:

  1. Erzeuge eine XMLInputFactory.

  2. Erzeuge den passenden Parser.

  3. Wähle XMLStreamReader für die Cursor-Verarbeitung oder XMLEventReader für die Iterator-Verarbeitung.

  4. Erfrage mit next() die nächste Komponente des XML-Dokuments.

  5. Ermittle den Typ der Komponente, und verarbeite ihn.

 
Zum Seitenanfang

8.5.1Unterschiede der Verarbeitungsmodelle Zur vorigen ÜberschriftZur nächsten Überschrift

Die Unterschiede zwischen der Cursor- und der Iterator-Verarbeitung sind auf den ersten Blick nicht eindeutig. Beide Verarbeitungsmodelle bieten ähnliche Methoden, und die Verarbeitung der Inhalte ist auch sehr ähnlich. Der wesentliche Unterschied ist die Art und Weise, wie die Komponenten des XML-Dokuments geliefert werden:

  • Bei der Cursor-Verarbeitung wird die Komponente direkt mit dem Parser-Objekt verarbeitet. Hier ist die zentrale Klasse der XMLStreamReader, mit dem auch auf die Inhalte der XML-Datei zugegriffen wird. Da diese Klasse ebenso verwendet wird, um auf das nächste Element der XML-Datei zugreifen zu können, steht zu einem Zeitpunkt immer nur eine Komponente des XML-Dokuments zur Verfügung. Der Vorteil ist die hohe Effizienz, da bei der Verarbeitung keine neuen Objekte erzeugt werden. Ein XML-Parser ist ein Zustandsautomat, und Methoden führen den Automaten von einem Zustand in den nächsten.

  • Bei der Iterator-Verarbeitung wird ein XMLEvent-Objekt geliefert, das anderen Methoden übergeben und in einer Datenstruktur gespeichert werden kann.

XMLStreamReader-Objekte erzeugen Ereignisse.

Abbildung 8.2XMLStreamReader-Objekte erzeugen Ereignisse.

StAX ist eine symmetrische API, was bedeutet, dass es Klassen zum Lesen und auch zum Schreiben von XML-Dokumenten gibt. So wie es für das Lesen die Prinzipien Cursor und Iterator gibt, so bietet die StAX-API die Typen XMLStreamWriter und XMLEventWriter. Damit ist es möglich, Elemente, die über die Reader gelesen werden, an die Writer zu übergeben und damit Änderungen an den Inhalten zu schreiben.

 
Zum Seitenanfang

8.5.2XML-Dateien mit dem Cursor-Verfahren lesen Zur vorigen ÜberschriftZur nächsten Überschrift

Zunächst muss ein Parser erzeugt werden, der das XML-Dokument verarbeiten soll:

XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader parser = factory.createXMLStreamReader( input );

Der Parser iteriert über die XML-Datei mit einer Tiefensuche und liefert beim Verarbeiten eine Reihe von Events, die den Typ des XML-Elements anzeigen. Die Eventtypen sind ganzzahlige Werte und als Konstanten in der Klasse XMLStreamConstants festgelegt. Der Parser liefert die folgenden Elemente:

XMLStreamConstants-Konstante

Beschreibung

START_DOCUMENT

Zeigt den Beginn der XML-Datei an. Bei diesem Event können Eigenschaften wie das Encoding des Dokuments ermittelt werden.

END_DOCUMENT

Zeigt das Ende des Dokuments an. Hier steht nur die Methode close() zum Schließen der Eingabe zur Verfügung.

START_ELEMENT

Zeigt an, dass ein Element beginnt. Die Attribute und der Namensraum eines Elements können hier ausgewertet werden.

END_ELEMENT

Zeigt an, dass das Ende eines Elements erreicht ist.

CHARACTERS

Zeigt Text innerhalb von Elementen. Text kann auf Whitespace getestet werden.

ENTITY_REFERENCE

Zeigt Entitäten in der XML-Datei an. Üblicherweise werden Entitäten zuerst aufgelöst und dann als CHARACTERS-Event geliefert.

DTD

Zeigt die DTD als String, sodass es möglich wird, auf Teile der DTD zuzugreifen.

COMMENT

Zeigt Kommentare in der XML-Datei an.

PROCESSING_INSTRUCTION

Zeigt Verarbeitungsanweisungen wie Stylesheet-Angaben.

Tabelle 8.14Event-Typen und was sie bedeuten

Die Events ATTRIBUTE und NAMESPACE liefert der Parser nur in Ausnahmefällen. Inhalte von Attributen sowie die Namensraumdaten lassen sich beim Event START_ELEMENT erfragen.

Passend zum Event sind verschiedene Methodenaufrufe gültig, etwa getAttributeCount() im Fall eines Elements, das die Anzahl der Attribute liefert. Mit einer Schleife und einer switch-Anweisung lassen sich die Inhalte der XML-Datei dann einfach auswerten:

Listing 8.19com/tutego/insel/xml/stax/XMLStreamReaderDemo.java, main() Ausschnitt

try ( Reader in = Files.newBufferedReader( Paths.get( "party.xml" ), StandardCharsets.UTF_8 ) ) {
XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader( in );
StringBuilder spacer = new StringBuilder();

while ( parser.hasNext() ) {
System.out.println( "Event: " + parser.getEventType() );

switch ( parser.getEventType() ) {
case XMLStreamConstants.START_DOCUMENT:
System.out.println( "START_DOCUMENT: " + parser.getVersion() );
break;

case XMLStreamConstants.END_DOCUMENT:
System.out.println( "END_DOCUMENT: " );
parser.close();
break;

case XMLStreamConstants.NAMESPACE:
System.out.println( "NAMESPACE: " + parser.getNamespaceURI() );
break;

case XMLStreamConstants.START_ELEMENT:
spacer.append( " " );
System.out.println( spacer + "START_ELEMENT: " + parser.getLocalName() );

// Der Event XMLStreamConstants.ATTRIBUTE wird nicht geliefert!
for ( int i = 0; i < parser.getAttributeCount(); i++ )
System.out.println( spacer + " Attribut: "
+ parser.getAttributeLocalName( i )
+ " Wert: " + parser.getAttributeValue( i ) );
break;

case XMLStreamConstants.CHARACTERS:
if ( ! parser.isWhiteSpace() )
System.out.println( spacer + " CHARACTERS: " + parser.getText() );
break;

case XMLStreamConstants.END_ELEMENT:
System.out.println( spacer + "END_ELEMENT: " + parser.getLocalName() );
spacer.delete( (spacer.length() – 2), spacer.length() );
break;

default:
break;
}
parser.next();
}
parser.close();
}
catch ( IOException | XMLStreamException e ) {
e.printStackTrace();
}

Dieses Beispiel demonstriert das Lesen einer XML-Datei mit dem Cursor-Verfahren. Der folgende Abschnitt 8.5.3 zeigt die Verarbeitung mit dem Iterator-Verfahren.

[»]Hinweis

Der XMLStreamReader liefert beim Parsen keinen Typ XMLStreamConstants.ATTRIBUTE. Dieses Event kann nur im Zusammenhang mit XPath auftreten, wenn der Ausdruck ein Attribut als Rückgabe liefert. Beim Parsen von XML-Dokumenten werden Attribute über ihre Elemente geliefert.

abstract class javax.xml.stream.XMLInputFactory
  • static XMLInputFactory newInstance()
    Liefert ein Exemplar der Fabrik XMLInputFactory. Aus dem Objekt erfolgt als Nächstes üblicherweise ein Aufruf von createXMLEventReader(…).

  • abstract XMLStreamReader createXMLStreamReader(InputStream stream)

  • abstract XMLStreamReader createXMLStreamReader(InputStream stream, String encoding)

  • abstract XMLStreamReader createXMLStreamReader(Reader reader)

  • abstract createXMLStreamReader(Source source)
    Liefert einen XMLStreamReader, der aus unterschiedlichen Quellen liest.

interface javax.xml.stream.XMLStreamReader
extends XMLStreamConstants
  • boolean hasNext()
    Sagt, ob es noch ein neues Parse-Event gibt.

  • int getEventType()
    Liefert den Typ des Parse-Events, so wie in XMLStreamConstants deklariert. Die Schnittstelle XMLStreamReader erweitert XMLStreamConstants.

  • int next()
    Parst das nächste Element und liefert das nächste Parse-Event.

  • Die Javadoc listet die getXXX()-Methoden auf, die alle Eigenschaften wie Namensraum, Attribute usw. des Elements liefert. Die nächste Tabelle zeigt, welche Methoden auf welchen Zuständen erlaubt sind:

Event-Typ

Erlaubte Methoden

auf allen Zuständen

hasNext(), require(), close(), getNamespaceURI(), isStartElement(), isEndElement(), isCharacters(), isWhiteSpace(), getNamespaceContext(), getEventType(), getLocation(), hasText(), hasName(), getProperty()

START_ELEMENT

next(), getName(), getLocalName(), hasName(), getPrefix(), -getAttributeXXX(), isAttributeSpecified(), getNamespaceXXX(), getElementText(), nextTag()

ATTRIBUTE

next(), nextTag(), getAttributeXXX(), isAttributeSpecified()

NAMESPACE

next(), nextTag(), getNamespaceXXX()

END_ELEMENT

next(), getName(), getLocalName(), hasName(), getPrefix(), -getNamespaceXXX(), nextTag()

CHARACTERS, CDATA, COMMENT, SPACE

next(), getTextXXX(), nextTag()

START_DOCUMENT

next(), getEncoding(), getVersion(), isStandalone(), -standaloneSet(), getCharacterEncodingScheme(), nextTag()

PROCESSING_INSTRUCTION

next(), getPITarget(), getPIData(), nextTag()

ENTITY_REFERENCE

next(), getLocalName(), getText(), nextTag()

DTD

next(), getText(), nextTag()

END_DOCUMENT

close()

Tabelle 8.15Erlaubte Methoden der Event-Typen

 
Zum Seitenanfang

8.5.3XML-Dateien mit dem Iterator-Verfahren verarbeiten * Zur vorigen ÜberschriftZur nächsten Überschrift

Die Verarbeitung mit der Iterator-Variante der StAX-API ist ein wenig komplizierter, aber auch viel flexibler. Es wird nicht direkt mit dem allgemeinen Parser-Objekt auf die Daten zugegriffen, sondern es wird bei jeder Iteration ein XMLEvent-Objekt erzeugt. Mit diesem Objekt kann der Typ des Events ermittelt und ganz ähnlich wie bei der Cursor-API ausgewertet werden.

Klassendiagramm für XMLEventReader und erzeugte Events

Abbildung 8.3Klassendiagramm für XMLEventReader und erzeugte Events

Am Anfang wird ein Parser vom Typ XMLEventReader erzeugt, und in einer Schleife werden die einzelnen Komponenten ausgewertet:

Listing 8.20com/tutego/insel/xml/stax/XMLEventReaderDemo.java, main()

try ( Reader in = Files.newBufferedReader( Paths.get( "party.xml" ),
StandardCharsets.UTF_8 ) ) {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader parser = factory.createXMLEventReader( in );

StringBuilder spacer = new StringBuilder();
while ( parser.hasNext() ) {
XMLEvent event = parser.nextEvent();

switch ( event.getEventType() ) {
case XMLStreamConstants.START_DOCUMENT:
System.out.println( "START_DOCUMENT:" );
break;
case XMLStreamConstants.END_DOCUMENT:
System.out.println( "END_DOCUMENT:" );
parser.close();
break;
case XMLStreamConstants.START_ELEMENT:
StartElement element = event.asStartElement();
System.out.println( spacer.append(" ")
+ "START_ELEMENT: "
+ element.getName() );
for ( Iterator<?> attributes = element.getAttributes();
attributes.hasNext(); ) {
Attribute attribute = (Attribute) attributes.next();
System.out.println( spacer + " Attribut: "
+ attribute.getName() + " Wert: "
+ attribute.getValue() );
}
break;
case XMLStreamConstants.CHARACTERS:
Characters characters = event.asCharacters();
if ( ! characters.isWhiteSpace() )
System.out.println( spacer
+ " CHARACTERS: "
+ characters.getData() );
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println( spacer
+ "END_ELEMENT: "
+ event.asEndElement().getName() );
spacer.delete( (spacer.length() – 2), spacer.length() );
break;
case XMLStreamConstants.ATTRIBUTE:
break;

default :
break;
}
}
parser.close();
}
catch ( IOException | XMLStreamException e ) {
e.printStackTrace();
}

Diese Form der Verarbeitung sieht auf den ersten Blick komplizierter aus, bietet aber zusätzliche Möglichkeiten, weil die erzeugten Objekte für die weitere Verarbeitung zur Verfügung stehen.

abstract class javax.xml.stream.XMLInputFactory
  • abstract XMLEventReader createXMLEventReader(InputStream stream)

  • abstract XMLEventReader createXMLEventReader(InputStream stream, String encoding)

  • abstract XMLEventReader createXMLEventReader(Reader reader)

  • abstract XMLEventReader createXMLEventReader(Source source)

  • abstract XMLEventReader createXMLEventReader(XMLStreamReader reader)
    Liefert XMLEventReader, der die Eingabe aus unterschiedlichen Quellen liest.

Der XMLEventReader implementiert nicht AutoCloseable, bietet aber eine close()-Methode. Unüblicherweise schließt sie aber nicht die Ressource, auf der sie arbeitet. Explizit schließt in unserem Beispiel das try mit Ressourcen die Datei.

 
Zum Seitenanfang

8.5.4Mit Filtern arbeiten * Zur vorigen ÜberschriftZur nächsten Überschrift

Mithilfe von Filtern gibt es die Möglichkeit, nur Teile eines XML-Dokuments zu parsen. Diese Filter werden durch die Implementierung einer der Schnittstellen javax.xml.stream.EventFilter (für die XML-Events) oder javax.xml.stream.StreamFilter (für die XMLStreamReader) programmiert. Es muss lediglich die Methode accept(XMLEvent) implementiert und ein boolean-Wert zurückgegeben werden. Als Parameter erwartet diese Methode entweder einen javax.xml. stream.events.XMLEvent bei der Iterator-Variante oder einen XMLStreamReader bei der Cursor-Variante. Dazu ein Beispiel: Ein Filter soll für die Iterator-Variante die schließenden Tags auslassen:

Listing 8.21com/tutego/insel/xml/stax/PartyEventFilter.java

package com.tutego.insel.xml.stax;

import javax.xml.stream.EventFilter;
import javax.xml.stream.events.XMLEvent;

public class PartyEventFilter implements EventFilter {
@Override public boolean accept( XMLEvent event ) {
return ! event.isEndElement();
}
}

Der Filter wird beim Erzeugen des Parsers mit der XMLInputFactory und dem vorhandenen XMLEventReader erzeugt. Dazu ein Beispiel zur Erzeugung des Parsers mit dem Event-Filter:

XMLEventReader filteredParser = factory.createFilteredReader(
parser, new PartyEventFilter() );

Dieses Verfahren der Dekoration wird in ähnlicher Form bei Streams verwendet.

Das Erzeugen eines Parsers mit einem Filter für die Cursor-Variante funktioniert analog. Mit Filtern bietet die API eine einfache Lösung, wenn nur bestimmte Teile des XML-Dokuments verarbeitet werden sollen.

abstract class javax.xml.stream.XMLInputFactory
  • abstract XMLEventReader createFilteredReader(XMLEventReader reader, EventFilter filter)

  • abstract XMLStreamReader createFilteredReader(XMLStreamReader reader, StreamFilter filter)
    Liefert XMLEventReader oder XMLStreamReader mit einem Filter.

interface javax.xml.stream.EventFilter
  • boolean accept(XMLEvent event)
    Liefert true, wenn das Ereignis in den Ergebnisstrom soll.

interface javax.xml.stream.StreamFilter
  • boolean accept(XMLStreamReader reader)
    Liefert false, wenn der XMLStreamReader in einem Zustand ist, bei dem das Element ignoriert werden soll.

 
Zum Seitenanfang

8.5.5XML-Dokumente schreiben Zur vorigen ÜberschriftZur nächsten Überschrift

Im Gegensatz zu DOM-orientierten APIs, bei denen das gesamte Dokument im Speicher vorliegt und verändert werden kann, ist es bei StAX nicht möglich, die vorhandene XML-Datei zu verändern. Es ist aber trotzdem möglich, XML zu schreiben. Auch hier wird zwischen der Cursor- und der Iterator-Variante unterschieden. Bei der Iterator-Variante werden Event-Objekte geschrieben, die entweder aus einem gelesenen XML-Dokument stammen oder mit einer XMLEventFactory erzeugt werden. Bei der Cursor-Variante wird mit einem XMLStreamWriter die XML-Komponente direkt erzeugt und geschrieben. In beiden Fällen wird über die XMLOutputFactory ein passender Writer erzeugt. Die Reihenfolge, in der die Komponenten geschrieben werden, entscheidet über den Aufbau des zu erzeugenden XML-Dokuments.

XMLStreamWriter

Zuerst zeigen wir, wie mit der Cursor-Variante eine XML-Datei geschrieben werden kann. Dazu erzeugen wir mit der XMLOutputFactory einen XMLStreamWriter, der die Elemente und Attribute direkt in eine XML-Datei schreibt:

Listing 8.22com/tutego/insel/xml/stax/XMLStreamWriterDemo.java, Ausschnitt main()

XMLOutputFactory factory = XMLOutputFactory.newInstance();
try ( OutputStream stream =
Files.newOutputStream( Paths.get( "writenParty.xml" ) ) ) {
XMLStreamWriter writer = factory.createXMLStreamWriter( stream );
// Der XML-Header wird erzeugt
writer.writeStartDocument();
// Zuerst wird das Wurzelelement mit Attribut geschrieben
writer.writeStartElement( "party" );
writer.writeAttribute( "datum", "31.12.2012" );
// Unter diesem Element das Element gast mit einem Attribut erzeugen
writer.writeStartElement( "gast" );
writer.writeAttribute( "name", "Albert Angsthase" );
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.close();
}

Beim Schreiben werden zuvor keine speziellen Objekte in einem XML-Baum erzeugt, sondern die Elemente werden direkt geschrieben. Der große Vorteil ist, dass das Schreiben sehr performant ist und die Größe der XML-Ausgabe beliebig sein kann.

XMLEventWriter *

Das Schreiben von XML-Dokumenten mit dem XMLEventWriter erfolgt in drei Stufen:

  1. Von der XMLOutputFactory wird ein Objekt vom Typ XMLEventWriter erfragt. In den XMLEventWriter werden dann die Ereignisobjekte geschrieben.

  2. Für das Erzeugen der Event-Objekte wird eine XMLEventFactory benötigt. Mit ihr lassen sich neue XMLEvent-Objekte erzeugen und irgendwo speichern.

  3. Die XMLEvent-Objekte werden geschrieben.

Der zentrale Unterschied zwischen dem XMLStreamWriter und XMLEventWriter ist also, dass beim XMLEventWriter erst die XMLEvent-Objekte erzeugt werden – in beliebiger Reihenfolge – und dass sie dann in den XMLEventWriter kommen; die Reihenfolge beim Erzeugen hat keinen Einfluss auf die Reihenfolge in der späteren Ausgabe:

Listing 8.23com/tutego/insel/xml/stax/XMLEventWriterDemo.java, main() Teil 1

try ( Writer out = Files.newBufferedWriter( Paths.get( "writenParty.xml" ), StandardCharsets.UTF_8 ) ) {
XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter( out );
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLEvent header = eventFactory.createStartDocument();
XMLEvent startRoot = eventFactory.createStartElement( "", "", "party" );
XMLEvent datumAttribut = eventFactory.createAttribute( "datum", "31.12.2012" );
XMLEvent endRoot = eventFactory.createEndElement( "", "", "party" );

XMLEvent startGast = eventFactory.createStartElement( "", "", "gast" );
XMLEvent name = eventFactory.createAttribute( "name", "Albert Angsthase" );
XMLEvent endGast = eventFactory.createEndElement( "", "", "gast" );
XMLEvent endDocument = eventFactory.createEndDocument();

Zuerst werden für das Wurzelelement das öffnende und schließende Tag sowie das Attribut datum erzeugt. Hierfür wird die Methode createStartElement(…) verwendet.

Um die Elemente zu schreiben, werden sie dem XMLEventWriter übergeben. Hier entscheidet die Reihenfolge über den Aufbau der XML-Datei:

Listing 8.24com/tutego/insel/xml/stax/XMLEventWriterDemo.java, main() Teil 2

writer.add( header );
writer.add( startRoot );
writer.add( datumAttribut );
writer.add( startGast );
writer.add( name );
writer.add( endGast );
writer.add( endRoot );
writer.add( endDocument );
writer.close();
}
catch ( IOException | XMLStreamException e ) {
e.printStackTrace();
}

In diesem Beispiel wurde gezeigt, wie Events erzeugt werden können und wie sie geschrieben werden. Der Strom muss explizit mit close() vom XMLEventWriter geschlossen werden, wobei XMLEventWriter nicht AutoCloseable ist. Die Ressource selbst (also der Writer in unserem Fall) muss ebenfalls geschlossen werden, was aber unser try mit Ressourcen übernimmt.

Das Schreiben von Elementen aus einer Eingabe funktioniert analog. Falls sich Elemente wiederholen oder aus einer anderen Quelle stammen (etwa ein XMLEvent, das serialisiert vom Netzwerk kommt), können sie direkt in den XMLEventWriter geschrieben werden. In dem Fall ist die Iterator-Variante flexibler als die Cursor-Variante. Diese Flexibilität wird durch einen etwas höheren Aufwand erkauft.

[»]Hinweis

Die Ausgabe ist weder beim XMLStreamWriter noch beim XMLEventWriter formatiert oder eingerückt, und die XML-Elemente stehen einfach hintereinander:

<?xml version="1.0" ?><party datum="31.12.2012"><gast name="Albert Angsthase">
<getraenk>Wein</getraenk><getraenk>Bier</getraenk><zustand ledig="true"
nuechtern="true"/></gast></party>

Besteht die Anforderung, dass die XML-Ausgabe eingerückt ist, kann Java SE standardmäßig nichts machen, und es muss auf externe Hilfsklassen zurückgegriffen werden. Die StAX-Utility-Sammlung unter https://java.net/projects/stax-utils/pages/Utilities bietet den javanet.staxutils.IndentingXMLEventWriter bzw. IndentingXMLStreamWriter, dessen Nutzung so aussieht:

XMLStreamWriter writer =
XMLOutputFactory.newInstance().createXMLStreamWriter( out );
writer = new IndentingXMLStreamWriter( writer );
writer.writeStartDocument();

Der IndentingXMLStreamWriter realisiert das Dekorator-Pattern.

Zusammenfassung

Wir haben gesehen, wie mit der StAX-API XML gelesen und geschrieben werden kann, welche Unterschiede zwischen der Cursor- und der Iterator-Variante bestehen und welche Filter für die Eingabe zur Verfügung stehen. Grundsätzlich ist die Iterator-Variante die flexiblere Lösung und in den meisten Fällen performant genug. Sie ist in jedem Fall performanter als eine DOM-basierte Lösung, wenn nicht die gesamte XML-Struktur im Speicher benötigt wird. Die Cursor-Variante sollte gewählt werden, wenn hohe Verarbeitungsgeschwindigkeit und geringer Speicherverbrauch Priorität haben. Diese Variante ist insbesondere für Endgeräte mit wenig Speicher und geringer Rechenleistung die bessere Wahl.

Die Anwendungsgebiete der StAX-API sind die gleichen wie die der SAX-API, weil die Vorteile beider Verfahren gute Performance und geringer Speicherverbrauch sind. Für die meisten Programmierer ist diese Form der Verarbeitung einfacher als die SAX-Variante, weil der XML-Inhalt direkt gelesen wird. SAX hat den Vorteil, dass es weit verbreitet ist und in vielen Programmiersprachen zur Verfügung steht. Wir stellen SAX im folgenden Abschnitt kurz vor.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern