XML, JAXP, StAX, SAX, DOM und JDOM mit Java

+ andere TechDocs
+ XSD (Schema)
+ JAXB (Binding)
+ XSL, XSLT, XSL-FO
+




Inhalt

  1. Begriffe und APIs zu XML, unabhängig von Java
    1. XML, PI, CDATA, Namespaces, DTD, XML Schema, XSD, XPath, XSL, XSLT, XSL-FO, DOM, SAX, StAX, SOAP Web Services
  2. Begriffe und Komponenten zu XML mit Java
    1. JWSDP, JAX-WS, JAXP, JAXB, Xerces, JDOM, dom4j
  3. Einfache Programmierbeispiele mit JAXP
    1. Beispiel-XML-Datei
    2. 1. StAX-Programmierbeispiel: XML einlesen und Dateninhalte im XPath-Format ausgeben
    3. 2. StAX-Programmierbeispiel: XML einlesen und Parse-Events ausgeben
    4. 3. StAX-Programmierbeispiel: XML einlesen und bestimmtes einzelnes Datenelement auslesen
    5. 1. SAX-Programmierbeispiel: XML einlesen und Elemente, Attribute und Textinhalte ausgeben
    6. 2. SAX-Programmierbeispiel: XML einlesen und bestimmtes einzelnes Datenelement auslesen
    7. 1. DOM-Programmierbeispiel: XML einlesen und Ergebnis einiger DOM-Node-Abfragemethoden anzeigen
    8. 2. DOM-Programmierbeispiel: XML einlesen, Element hinzufügen und neue XML-Datei erzeugen
    9. Weitere JAXP-Programmierbeispiele
  4. Einfache Programmierbeispiele mit JDOM
    1. Voraussetzungen
    2. 1. JDOM-Programmierbeispiel: XML einlesen und schön formatiert ausgeben
    3. 2. JDOM-Programmierbeispiel: XML einlesen, Element hinzufügen und neue XML-Datei erzeugen
    4. 3. JDOM-Programmierbeispiel: XML einlesen, Element mit Attribut suchen, Attribut ergänzen, XML speichern


Begriffe und APIs zu XML, unabhängig von Java

Doku und Tools

Außer unter den im Folgenden genannten spezifischen Links finden Sie weitere Erläuterungen auch unter:
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc

Möglicherweise interessante Bücher:
Einstieg in XML (Aktuelle Standards, XML Schema, XSL, XLink), Helmut Vonhoegen, 2009, ISBN 3836213672
Java und XML (Grundlagen, Einsatz, Referenz), Michael Scholz und Stephan Niedermeier, 2009, ISBN 3836213087

Bekannte Tools:
Altova XMLSpy, Stylus Studio und Liquid XML Studio

XML (Extensible Markup Language),
PI (Processing Instruction),
Element, Attribut, Inhalt,
CDATA (Character Data)

XML definiert, wie Daten strukturiert in Textdateien gespeichert werden. XML-Datenstrukturen sind auch für andere als die ursprüngliche Anwendung verständlich. Daten können plattformunabhängig zwischen verschiedenen Anwendungen ausgetauscht werden. XML ist als Metasprache erweiterbar und ist ebenso wie HTML und XHTML eine Untermenge von SGML. XML 1.0 wurde Anfang 1998 vom W3C als Standard verabschiedet.

Eine einfache XML-Datei kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<MeinRootElement>
  <MeinErstesUnterElement MeinAttribut="Attributwert">
     Elementinhalt
  </MeinErstesUnterElement>
  <MeinLeeresUnterElement/>
</MeinRootElement>

XML-Dateien beginnen normalerweise mit einer oder mehreren durch "<?" gekennzeichneten "PI" (Processing Instruction), die Hinweise zur Verarbeitung enthält.

Es kann mehrere Unterelemente geben, aber nur genau ein Root-Element. Die Elemente können Attribute und/oder Inhalte enthalten. Ist der Inhalt (auch Rumpf genannt) leer, ist auch die bei "<MeinLeeresUnterElement/>" gezeigte verkürzte Schreibweise möglich.

Es gibt fünf reservierte Zeichen, die in Attributen und Inhalten normalerweise nicht verwendet werden dürfen, sondern als Entity-Referenz ausgedrückt werden müssen: & = &amp;, < = &lt;, > = &gt;, " = &quot;, ' = &apos;.
Nicht im angegebenen Encoding enthaltene Sonderzeichen können als Unicode-Zeichenreferenz angegeben werden, zum Beispiel "&#x20AC;" für "€".
Nicht vom XML-Parser zu interpretierender Text muss mit "<![CDATA[ ... ]]>" als "Character Data" eingeschlossen werden.

Siehe auch:
http://www.w3.org/XML, http://www.w3.org/TR/xml und http://www.w3.org/TR/xml11

xmlns (XML-Namespaces)

XML-Namespaces ("xmlns") sind Namensräume, vergleichbar in etwa mit den Packages in Java. Damit bestimmte Bezeichner in verschiedenen Zusammenhängen mit unterschiedlicher Bedeutung benutzt werden können, macht XML ausgiebig Gebrauch vom Konzept der Namespaces.

Als Konvention gilt, dass als Bezeichner des Namespaces ein Text in Form einer URL verwendet wird. Dabei bedeutet diese URL nicht, dass es eine entsprechende Webseite gibt.

Eine einfache XML-Datei mit Namespaces kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<mns:MeinRootElement xmlns:mns="http://meinnamespace.meinefirma.de">
  <mns:MeinUnterElement mns:MeinAttribut="Attributwert">
     Elementinhalt
  </mns:MeinUnterElement>
</mns:MeinRootElement>

Siehe auch:
http://www.w3.org/TR/xml-names
http://www.w3.org/TR/xml-names11

DTD (Document Type Definition)

Definition der Dokumentenart und der Bedeutung der Tags bei HTML- und XML-Dokumenten. Auf die DTD wird per DOCTYPE-Anweisung verwiesen. DTD wird zunehmend durch das leistungsfähigere XML Schema ersetzt.

Siehe auch:
http://www.w3.org/TR/REC-xml

XML Schema,
XSD (XML Schema Definition),
XSI (XML Schema Instanz)

XML Schema definiert Art und Struktur von XML-Dokumenten und den enthaltenen Elementen und ermöglicht eine Validierung. Ein XML Schema wird als XML Schema Definition in einer XML-Datei mit der Dateiendung .xsd gespeichert. XML Schemas sind wesentlich leistungsfähiger als DTDs und ersetzen diese zunehmend.

Eine einfaches XSD-Schema kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://meinnamespace.meinefirma.de"
            xmlns="http://meinnamespace.meinefirma.de"
            elementFormDefault="qualified">
  <xsd:element name="MeinRootElement">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="MeinUnterElement" type="xsd:string" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Der xmlns:xsd-Namensraum muss für XSD immer wie angegeben definiert werden. Der Bezeichner xsd könnte auch anders gewählt werden (z.B. xs).
Der targetNamespace muss dem im Ziel-Instanzdokument verwendeten Namespace entsprechen.
xmlns definiert den Default-Namespace dieser XSD-Schema-Datei (ein Default-Namespace gilt nur für Elemente und nicht für Attribute).
In einfachen Fällen können die targetNamespace- und xmlns-Angaben auch entfallen.

Ein einfaches dieses Schema verwendendes XML-Dokument (eine so genannte "Instanz") kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="ISO-8859-1"?>
<MeinRootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://meinnamespace.meinefirma.de
                                     http://www.meinefirma.de/MeinSchema.xsd"
                 xmlns="http://meinnamespace.meinefirma.de">
  <MeinUnterElement>
     Elementinhalt
  </MeinUnterElement>
</MeinRootElement>

Der xmlns:xsi-Namensraum muss für XSI immer wie angegeben definiert werden.
xsi:schemaLocation enthält zwei durch Leerzeichen getrennte Teile: Zuerst wird der im XSD-Schema definierte targetNamespace angegeben und dann die Datei des XSD-Schemas, entweder als Datei im lokalen Dateisystem oder alternativ wie hier im Beispiel als URL (die in diesem Fall natürlich auf eine tatsächlich vorhandene und verfügbare Datei verweisen muss).
xmlns definiert den Default-Namespace der Elemente in dieser XML-Datei (ein Default-Namespace gilt nur für Elemente und nicht für Attribute).

Falls Sie die Validierung zum Beispiel mit Eclipse testen wollen: Speichern Sie das XSD-Schema in MeinSchema.xsd und das XML-Instanzdokument in MeinDokument.xml, ändern Sie in MeinDokument.xml die Schema-Location von http://www.meinefirma.de/MeinSchema.xsd zu MeinSchema.xsd und wählen Sie in Eclipse "Validate", indem Sie mit der rechten Maustaste entweder auf den Verzeichnisnamen oder in das XML-Instanzdokument klicken.

Wenn Sie innerhalb eines Java-Programms validieren möchten, können Sie beispielsweise DocumentBuilderFactory.setSchema(), SAXParserFactory.setSchema() oder Validator.validate() verwenden.

Ausführlichere Beispiele finden Sie unter XSD (XML Schema Definition) und Validierung.

Eine erste Einführung zum XML Schema finden Sie unter http://de.wikipedia.org/wiki/XML_Schema. Genaueres finden Sie im englischen Original in der W3C XML Schema Specification unter http://www.w3.org/XML/Schema oder ins deutsche übersetzt unter Einführung, Strukturen und Datentypen.

Java-Klassen hierzu finden Sie in http://docs.oracle.com/javase/7/docs/api/javax/xml/validation/package-summary.html

XPath (XML Path Language),
XSL (Extensible Stylesheet Language),
XSLT (XSL Transformations),
XSL-FO (XSL Formatting Objects),
FOP (Formatting Objects Processor),
TrAX (Transformation API for XML)

Die XSL-Spezifikation des W3C enthält die drei Unterspezifikationen XPath, XSLT und XSL-FO.

XPath bietet eine Syntax für Lokalisierungspfade zur Identifikation von Elementen und Attributen in XML-Dokumenten. XPath wird zum Beispiel bei XML Schema, XSLT, XPointer und XForms verwendet.

XSL definiert eine Sprache für Umwandlungsregeln.

XSLT beschreibt, wie XML-Dokumente in andere Formate transformiert werden können.

XSL-FO spezifiziert, wie die grafische Aufbereitung von XML-Dokumenten beschrieben wird und enthält Anweisungen zur Formatierung und Präsentation der Daten.

Apache FOP ist eine Implementierung von XSL-FO und erstellt aus XSL-FO-Layout-Beschreibungen verschiedene Ausgabeformate, zum Beispiel PDF, Java2D/AWT, AFP, PCL, MIF, PS, RTF, TIFF, PNG, SVG und TXT.

TrAX wird manchmal als Oberbegriff für die Transformations-APIs verwendet.

Ein einfaches XSL-Stylesheet kann zum Beispiel so aussehen:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" indent="yes" encoding="ISO-8859-1" />
  <xsl:template match="MeinRootElement">
    <MeinNeuesRootElement>
      <MeinNeuesUnterElement><xsl:value-of select="MeinUnterElement"/></MeinNeuesUnterElement>
    </MeinNeuesRootElement>
  </xsl:template>
</xsl:stylesheet>

Auch wenn man es in diesem einfachen Beispiel nicht erkennen kann: Bei "<xsl:value-of select="..."/>" ist ein XPath-Ausdruck eingesetzt.

Für einen einfachen Test speichern Sie das XSL-Stylesheet in MeinStylesheet.xsl und erzeugen folgende Input.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<MeinRootElement>
  <MeinUnterElement>Elementinhalt</MeinUnterElement>
</MeinRootElement>

Die XSL-Transformation kann mit beliebigen XSLT-Transformationstools erfolgen, beispielsweise:

Transformation mit Eclipse: Klicken Sie in Eclipse mit der rechten Maustaste auf MeinStylesheet.xsl, wählen Sie 'Run As' | 'XSL Transformation' und wählen Sie als 'XML Input File' über die Schaltflächen die XML-Datei Input.xml.

Transformation mit Xalan: Downloaden Sie Xalan, kopieren Sie xalan.jar und serializer.jar zu den beiden XML-Dateien und rufen Sie auf:

java -cp xalan.jar;serializer.jar org.apache.xalan.xslt.Process -XSL MeinStylesheet.xsl -IN Input.xml -OUT Result.xml

Transformation unter Windows mit MSXML: Downloaden Sie den Microsoft-MSXML-Wrapper msxsl.exe und rufen Sie auf:

msxsl Input.xml MeinStylesheet.xsl -o Result.xml

Ausführlichere Beispiele finden Sie unter XSL, XSLT, XSL-FO, FOP.

Siehe auch:
http://www.w3schools.com, http://xml.klute-thiemann.de, http://www.w3.org/Style/XSL, http://www.w3.org/TR/xsl, http://www.w3.org/TR/xslt, http://docs.oracle.com/javase/7/docs/api/javax/xml/transform/package-summary.html und http://docs.oracle.com/javase/7/docs/api/javax/xml/xpath/package-summary.html

DOM (Document Object Model)

DOM ist ein W3C-Standard für eine Programmierschnittstelle für verschiedene Programmiersprachen zur XML-Verarbeitung. DOM konkurriert mit SAX und StAX. Anders als bei SAX und StAX erfolgt bei DOM der XML-Zugriff über einen Objektbaum, was komfortabler ist, aber nicht für große Dokumente geeignet ist. Per DOM können XML-Dokumente sowohl gelesen als auch erzeugt werden.

Siehe auch:
http://www.w3.org/DOM und http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/package-summary.html

SAX (Simple API for XML)

SAX ist eine Programmierschnittstelle für verschiedene Programmiersprachen zur XML-Verarbeitung. SAX konkurriert mit StAX und DOM. Anders als bei DOM wird bei SAX das XML-Dokument sequentiell durchlaufen, so dass auch sehr große Dokumente bearbeitet werden können. Ereignisgesteuert werden bei bestimmten Inhalten vorher (per DocumentHandler-Schnittstelle) registrierte Callbackfunktionen aufgerufen (event-based Parser, "Push-Parsing"). Anders als bei DOM können mit SAX XML-Dokumente nur gelesen aber nicht erzeugt werden.

Siehe auch:
http://www.saxproject.org und http://docs.oracle.com/javase/7/docs/api/org/xml/sax/package-summary.html

StAX (Streaming API for XML)

StAX ist eine Programmierschnittstelle für verschiedene Programmiersprachen zur XML-Verarbeitung. StAX konkurriert mit SAX und DOM. Ähnlich wie bei SAX wird auch bei StAX das XML-Dokument sequentiell durchlaufen, so dass auch sehr große Dokumente bearbeitet werden können. Während bei SAX registrierte Callbackfunktionen aufgerufen werden, also der Parser das Anwendungsprogramm aufruft ("Push-Parsing"), wird bei StAX "andersherum" verfahren: Das Anwendungsprogramm ruft iterativ den Parser auf ("Pull-Parsing"). Dies hat den Vorteil, dass nicht wie bei SAX mühsam der Zusammenhang zwischen den isolierten Callbackfunktionen zum Beispiel über State Machines hergestellt werden muss, sondern die Kontrolle beim Entwickler bleibt und einfachere iterative Schleifen programmiert werden können. Anders als bei SAX können mit StAX XML-Dokumente sowohl gelesen als auch erzeugt werden.

Siehe auch:
http://jcp.org/en/jsr/detail?id=173, http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/StAX2.html, http://docs.oracle.com/javase/7/docs/api/javax/xml/stream/package-summary.html.

SOAP Web Services

Web Services ermöglichen Abwicklungen von Dienstleistungen und Geschäften über das Internet. Web Services im engeren technischen Sinn meint automatisierte Kommunikation zwischen Applikationen über Netzwerke, beispielsweise übers Internet. Es werden also nicht HTML-Seiten zu einem Webbrowser geschickt, die von einem Menschen betrachtet werden, sondern Programme tauschen Daten und starten auf entfernten Rechnern Funktionen (Remote Procedure Call). Web Services basieren meistens auf den Standards SOAP, WSDL und UDDI.

Siehe auch:
http://www.w3.org/2002/ws, http://www.w3.org/TR/soap und techdocs/soap.htm



Begriffe und Komponenten zu XML mit Java

Java WSDP (Java Web Services Developer Pack)

Java WSDP schnürte ursprünglich die Module JAXP, JAX-RPC, JAXR, JSTL, Java WSDP Registry Server, Web Application Deployment Tool, Ant Build Tool und den Apache Tomcat Container zu einem Paket zusammen.

Seit Java WSDP 2.0 enthält der "integrated Stack" die "Key Components" JAX-WS (Java API for XML Web Services), JAXB (Java API for XML Binding), SAAJ (SOAP with Attachments API for Java) und XWSS (XML Web Services Security).

Auch wenn man keine Web Services implementieren will, sondern nur XML behandeln will, lohnt sich ein Blick in die entsprechenden Kapitel des im Folgenden und auch an anderen Stellen in diesem Dokument aufgeführten 'Java Web Services Tutorials' von Sun, welches sowohl als HTML-Online-Doku, als PDF-Datei und als Buch erhältlich ist.

Siehe auch:
http://www.oracle.com/technetwork/java/index-jsp-137004.html
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JavaWSTutorialTOC.html

JAX-WS (Java API for XML Web Services),
WSIT (Web Services Interoperability Technologies)

Seit Java SE 6 und Java EE 5 sind die wichtigsten XML-APIs bereits enthalten.

Programmierbeispiele finden Sie unter SOAP Web Services mit JAX-WS.

Siehe auch:
http://jax-ws.java.net
http://www.ws-i.org/Profiles/BasicProfile-1.1.html
http://wsit.java.net
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/jaxws/index.html
http://jax-ws.java.net/nonav/2.1.1/docs/api/index.html

JAXP (Java API for XML Processing)

Einheitliches API, um unter Java auf XML zuzugreifen. Umfasst DOM, SAX, StAX, Validierung, XSLT und XPath und kann verschiedene XML-Parser einbinden (über einen 'pluggability Layer'). JAXP ist seit J2SE 1.4 enthalten, aber erst in Java SE 6 zum Beispiel mit StAX vervollständigt.

Siehe auch:
http://jaxp.java.net
http://java.net/projects/jaxp-sources
http://java.sun.com/developer/codesamples/xml.html
http://people.apache.org/~edwingo/jaxp-ri-1.2.0-fcs/docs/samples.html

JAXB (Java Architecture for XML Binding)

XML-Binding abstrahiert von der dokumentnahen Verarbeitung von XML-Dateien. Stattdessen werden XML-Strukturen auf Java-Klassenstrukturen gemappt (ähnlich wie beim Datenbank-O/R-Mapping).

Dazu gehören folgende vier Schwerpunkte:

JAXB ist oft das optimale Hilfsmittel zur Kommunikation per XML. Allerdings gibt es eine wichtige Einschränkung: Bei "normaler" Anwendung lädt JAXB das gesammte XML-Dokument in den Hauptspeicher, was bei großen Datenmengen zur Beeinträchtigung anderer Prozesse oder sogar zum OutOfMemoryError führen kann. In solchen Fällen kann es empfehlenswert sein, JAXB mit StAX zu kombinieren.

JAXB 2.0 ist ab Java SE 6 und ab Java EE 5 enthalten.

Siehe auch:
http://jaxb.java.net
http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/package-summary.html
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBWorks.html
http://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing.html
Vergleich von JAXB mit Apache XMLBeans, ADB und JiBX
Phillip Ghadir zu XML und JAXB

Xerces

Xerces ist ein XML-Parser, der zum Beispiel über JAXP verwendet werden kann. Wenn keine besonderen Anforderungen vorliegen, kann einfach das JAXP-API mit dem bereits im JAXP enthaltenen Default-Parser verwendet werden, ohne dass man wissen muss, welcher Parser zu Grunde liegt.

Infos zu Xerces2 finden Sie unter:
http://xerces.apache.org/xerces2-j

Um die von Ihrer Java-Version verwendete Version von Xerces2-J zu ermitteln, rufen Sie auf:

java com.sun.org.apache.xerces.internal.impl.Version

Falls Sie weitere Infos benötigen, rufen Sie auf:

java com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck

Sie können Ihr Java auch mit einem anderen XML-Parser/Builder verwenden. Hierzu setzen Sie entweder eine Environment-Variable, beispielsweise so ähnlich wie:

-Djavax.xml.parsers.SAXParserFactory=MeineKlasse

Oder alternativ per "Endorsed Standards Override Mechanism", indem Sie im <java-home>/lib/endorsed-Verzeichnis Ihre gewünschten Versionen von xalan.jar, serializer.jar, xercesImpl.jar und xml-apis.jar ablegen.

JDOM (Java DOM),
dom4j (DOM for Java)

JDOM ist eine Open-Source-Java-Bibliothek, die eine an Java angepasste Programmierschnittstelle bietet und einen an Java angepassten Objekt-Tree aus dem XML-Dokument erstellt.

dom4j ist ebenfalls Open-Source und eine Alternative, die besonders viele Features beinhaltet.

Siehe auch:
http://www.jdom.org
http://www.servlets.com/speaking/jdom-javaone.pdf
http://www.cafeconleche.org/books/xmljava/chapters/ch14.html
http://www.javaworld.com/javaworld/jw-05-2000/jw-0518-jdom.html
http://www.jdom.org/docs/apidocs
JSR 102
http://www.dom4j.org



Einfache Programmierbeispiele mit JAXP

Beispiel-XML-Datei

Speichern Sie das folgende XML-Dokument unter dem Namen: 'MyXmlFile.xml':

<?xml version='1.0' encoding='UTF-8'?>

<!-- MyXmlFile.xml -->

<GUI-Description>

   <Button size="normal" x="70" y="80">
      <Title>Mein erster Button</Title>
      <Action>call Fct1</Action>
      <Comment/>
   </Button>

   <Button size="small">
      <Title>Mein zweiter Button</Title>
      <Action>call Fct2</Action>
   </Button>

   <Button size="big">
      <Action>call Fct3</Action>
      <Title>Mein dritter Button</Title>
      <Comment>Dies ist <b>HTML</b>-<i>Text</i>.</Comment>
   </Button>

</GUI-Description>

1. StAX-Programmierbeispiel:
XML einlesen und Dateninhalte im XPath-Format ausgeben (Iterator-API-Beispiel)

Wie oben bereits erläutert wurde, ist StAX eine Programmierschnittstelle zur XML-Verarbeitung. Anders als bei SAX können mit StAX XML-Dokumente sowohl gelesen als auch erzeugt werden. Wie bei SAX wird auch bei StAX das XML-Dokument sequentiell durchlaufen. Anders als bei SAX ruft der Programmierer iterativ den Parser auf ("Pull-Parsing").

Im selben Verzeichnis, in dem sich obige Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie für das erste StAX-Beispiel den folgenden Java-Sourcecode unter dem Namen 'StaxToXPathProperties.java':

// StaxToXPathProperties.java

import java.util.*;
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import javax.xml.transform.stream.StreamSource;

public class StaxToXPathProperties
{
   @SuppressWarnings("unchecked")
   public static void main( String[] args ) throws XMLStreamException
   {
      if( args.length != 1 ) {
         System.err.println( "Bitte XML-Datei angeben, beispielsweise:" );
         System.err.println( "  java StaxToXPathProperties MyXmlFile.xml" );
         return;
      }
      XMLInputFactory inputFactory = XMLInputFactory.newInstance();
      XMLEventReader  evRd = inputFactory.createXMLEventReader( new StreamSource( args[0] ) );
      Stack<String>   stck = new Stack<String>();
      while( evRd.hasNext() ) {
         XMLEvent ev = evRd.nextEvent();
         if( ev.isStartElement() ) {
            stck.push( ev.asStartElement().getName().getLocalPart() );
            Iterator<Attribute> iter = ev.asStartElement().getAttributes();
            while( iter.hasNext() ) {
               Attribute a = iter.next();
               System.out.println( buildXPathString(
                     stck, "/@" + a.getName().getLocalPart() + "=\"" + a.getValue() + "\"" ) );
            }
         }
         if( ev.isCharacters() ) {
            String s = ev.asCharacters().getData();
            if( s.trim().length() > 0 )
               System.out.println( buildXPathString( stck, "=\"" + s + "\"" ) );
         }
         if( ev.isEndElement() ) stck.pop();
      }
   }

   private static String buildXPathString( Stack<String> stck, String postfix )
   {
      StringBuffer sb = new StringBuffer();
      for( String s : stck ) sb.append( "/" ).append( s );
      sb.append( postfix );
      return sb.toString();
   }
}

Öffnen Sie ein Kommandozeilenfenster ('Windows-Taste' + 'R', 'cmd'), wechseln Sie in Ihr Projektverzeichnis und testen Sie das Programm mit einer beliebigen XML-Datei:

javac StaxToXPathProperties.java

java StaxToXPathProperties MyXmlFile.xml

Sie erhalten u.a.:

/GUI-Description/Button/@y="80"
/GUI-Description/Button/@x="70"
/GUI-Description/Button/@size="normal"
/GUI-Description/Button/Title="Mein erster Button"
/GUI-Description/Button/Action="call Fct1"
/GUI-Description/Button/@size="small"
/GUI-Description/Button/Title="Mein zweiter Button"
/GUI-Description/Button/Action="call Fct2"
...

Eine Einführung zu StAX finden Sie im StAX-Tutorial. Das Programm verwendet das so genannte "Iterator API" von StAX. Alternativ gibt es noch das "Cursor API" (siehe folgendes Beispiel):

2. StAX-Programmierbeispiel:
XML einlesen und Parse-Events ausgeben (Cursor-API-Beispiel)

Im selben Verzeichnis, in dem sich obige Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'StaxParseEvents.java':

// StaxParseEvents.java

import java.util.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
import static javax.xml.stream.XMLStreamConstants.*;

public class StaxParseEvents
{
   public static void main( String[] args ) throws XMLStreamException
   {
      if( args.length != 1 ) {
         System.err.println( "Bitte XML-Datei angeben, beispielsweise:" );
         System.err.println( "      java StaxParseEvents MyXmlFile.xml" );
         return;
      }
      XMLInputFactory inputFactory = XMLInputFactory.newInstance();
      XMLStreamReader stax = inputFactory.createXMLStreamReader( new StreamSource( args[0] ) );
      Map<Integer,String> pem = (new StaxEventNames()).map;
      while( true ) {
         int pe = stax.getEventType();
         System.out.print( pe + "-" + pem.get( new Integer( pe ) ) );
         if( stax.hasName() ) {
            String s = ": ";
            if( stax.isEndElement() ) s += "/";
            s += stax.getName();
            if( stax.isStartElement() ) s += ":";
            System.out.print( s );
         }
         if( (pe == ATTRIBUTE || pe == START_ELEMENT) && stax.getAttributeCount() > 0 ) {
            for( int i = 0; i < stax.getAttributeCount(); i++ ) {
               System.out.print( " " + stax.getAttributeLocalName(i) + "=\""
                                     + stax.getAttributeValue(i) + "\"" );
            }
         }
         if( stax.hasText() ) System.out.print( ": " + stax.getText().trim() );
         System.out.println( "" );
         if( !stax.hasNext() ) break;
         stax.next();
      }
   }
}

class StaxEventNames
{
   public final Map<Integer,String> map;

   public StaxEventNames()
   {
      Map<Integer,String> pem = new HashMap<Integer,String>();
      pem.put( new Integer( ATTRIBUTE ),              "ATTRIBUTE     " );
      pem.put( new Integer( CDATA ),                  "CDATA         " );
      pem.put( new Integer( CHARACTERS ),             "CHARACTERS    " );
      pem.put( new Integer( COMMENT ),                "COMMENT       " );
      pem.put( new Integer( DTD ),                    "DTD           " );
      pem.put( new Integer( END_DOCUMENT ),           "END_DOCUMENT  " );
      pem.put( new Integer( END_ELEMENT ),            "END_ELEMENT   " );
      pem.put( new Integer( NAMESPACE ),              "NAMESPACE     " );
      pem.put( new Integer( SPACE ),                  "SPACE         " );
      pem.put( new Integer( START_DOCUMENT ),         "START_DOCUMENT" );
      pem.put( new Integer( START_ELEMENT ),          "START_ELEMENT " );
      pem.put( new Integer( ENTITY_DECLARATION ),     "ENTITY_DECLARATION    " );
      pem.put( new Integer( ENTITY_REFERENCE ),       "ENTITY_REFERENCE      " );
      pem.put( new Integer( NOTATION_DECLARATION ),   "NOTATION_DECLARATION  " );
      pem.put( new Integer( PROCESSING_INSTRUCTION ), "PROCESSING_INSTRUCTION" );
      map = Collections.unmodifiableMap( pem );
   }
}

Öffnen Sie ein Kommandozeilenfenster ('Windows-Taste' + 'R', 'cmd'), wechseln Sie in Ihr Projektverzeichnis und testen Sie das Programm mit einer beliebigen XML-Datei:

javac StaxParseEvents.java

java StaxParseEvents MyXmlFile.xml

Sie erhalten u.a.:

7-START_DOCUMENT
5-COMMENT       : MyXmlFile.xml
1-START_ELEMENT : GUI-Description:
4-CHARACTERS    :
1-START_ELEMENT : Button: size="normal" x="70" y="80"
4-CHARACTERS    :
1-START_ELEMENT : Title:
4-CHARACTERS    : Mein erster Button
2-END_ELEMENT   : /Title
4-CHARACTERS    :
1-START_ELEMENT : Action:
4-CHARACTERS    : call Fct1
2-END_ELEMENT   : /Action
...
8-END_DOCUMENT

Das Programm verwendet das so genannte "Cursor API" von StAX. Alternativ gibt es noch das "Iterator API" (zum Unterschied siehe oben).

Bitte beachten Sie, dass (anders als beim Iterator API) das stax.next()-Kommando am Ende der Schleife stehen muss, damit Sie auch das erste START_DOCUMENT-Event sehen.

Doku zu StAX und zum XMLStreamReader finden Sie unter: StAX-Tutorial, javax.xml.stream und XMLStreamReader.

3. StAX-Programmierbeispiel:
XML einlesen und bestimmtes einzelnes Datenelement auslesen

Im selben Verzeichnis, in dem sich obige Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleStaxGetData.java':

// ExampleStaxGetData.java

import java.io.File;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class ExampleStaxGetData
{
   public static void main( String[] args ) throws XMLStreamException
   {
      if( args.length != 5 ) {
         System.err.println( "Usage:" );
         System.err.println( "java ExampleStaxGetData <XmlFile> "
                           + "<ParentElem> <ChildElem> <FindText> <DataElem>" );
         System.err.println( "Example:" );
         System.err.println( "java ExampleStaxGetData MyXmlFile.xml "
                           + "Button Title \"Mein dritter Button\" Comment" );
         return;
      }
      XMLInputFactory inputFactory = XMLInputFactory.newInstance();
      XMLStreamReader stax = inputFactory.createXMLStreamReader( new StreamSource( new File( args[0] ) ) );
      StringBuffer    sb = new StringBuffer();
      int             state = 0;
      while( stax.hasNext() ) {
         stax.next();
         String  name = ( stax.hasName() ) ? stax.getName().getLocalPart().trim() : null;
         String  text = ( stax.hasText() ) ? stax.getText().trim() : null;
         boolean b1 = stax.hasName() && name.equals( args[1].trim() );   // <ParentElem>
         boolean b2 = stax.hasName() && name.equals( args[2].trim() );   // <ChildElem>
         boolean b3 = stax.hasText() && text.equals( args[3].trim() );   // <FindText>
         boolean b4 = stax.hasName() && name.equals( args[4].trim() );   // <DataElem>
         if( b1 && stax.isStartElement() ) state = 1;                    // <ParentElem>
         if( b1 && stax.isEndElement()   ) state = 0;
         if( state == 1 && b2 && stax.isStartElement() ) state = 2;      // <ChildElem>
         if( state == 2 && b2 && stax.isEndElement()   ) state = 1;
         if( state == 2 && b3 ) state = 3;                               // <FindText>
         if( state == 3 && b4 && stax.isStartElement() ) state = 4;      // <DataElem>
         if( state == 4 && b4 && stax.isEndElement()   ) break;
         if( state == 4 && stax.hasText() ) sb.append( stax.getText() ); // gesuchtes Ergebnis
      }
      System.out.println( sb );
   }
}

Öffnen Sie ein Kommandozeilenfenster, wechseln Sie in Ihr Projektverzeichnis und testen Sie das Programm:

javac ExampleStaxGetData.java

java ExampleStaxGetData

java ExampleStaxGetData MyXmlFile.xml Button Title "Mein dritter Button" Comment

Falls Ihr Webbrowser ein Kommando auf zwei Zeilen umgebrochen hat: Bitte geben Sie diese als eine einzige Kommandozeile ein.

Die Kommandozeilenparameter haben folgende Bedeutung:

ParameterBeispielBedeutung
<XmlFile>MyXmlFile.xml In dieser XML-Datei wird gesucht
<ParentElem>Button Elemente mit diesem Tag-Namen werden untersucht
<ChildElem>Title Das gesuchte Element muss ein Child-Element mit diesem Tag-Namen haben
<FindText>"Mein dritter Button" Das Child-Element muss diesen Text als Inhalt haben
<DataElem>Comment Der Textinhalt dieses Elements wird ausgelesen

Mit der Beispiel-XML-Datei 'MyXmlFile.xml' und den angegebenen Beispielparametern wird das dritte <Button>-Element gefunden, da dessen <Title>-Text mit der Suchvorgabe <FindText>="Mein dritter Button" übereinstimmt. Der Inhalt des durch <DataElem> vorgegebenen <Comment>-Elements wird ausgelesen und im Kommandozeilenfenster ausgegeben. Sie erhalten als Ergebnis:

Dies ist HTML-Text.

1. SAX-Programmierbeispiel:
XML einlesen und Elemente, Attribute und Textinhalte ausgeben

Im selben Verzeichnis, wo sich die Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleSaxEcho.java' und kompilieren und führen ihn im Kommandozeilenfenster aus mit:

javac ExampleSaxEcho.java

java ExampleSaxEcho MyXmlFile.xml

Dokumentation zu den JAXP-Klassen und Methoden finden Sie unter: http://java.net/projects/jaxp-sources.


// ExampleSaxEcho.java

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

public class ExampleSaxEcho extends DefaultHandler
{
  static final   String       sNEWLINE   = System.getProperty( "line.separator" );
  static private Writer       out        = null;
  private        StringBuffer textBuffer = null;

  // ---- main ----

  public static void main( String[] argv )
  {
    if( argv.length != 1 )
    {
      System.err.println( "Usage: java ExampleSaxEcho MyXmlFile.xml" );
      System.exit( 1 );
    }
    try {
      // Use an instance of ourselves as the SAX event handler
      DefaultHandler handler = new ExampleSaxEcho();
      // Parse the input with the default (non-validating) parser
      SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
      saxParser.parse( new File( argv[0] ), handler );
      System.exit( 0 );
    } catch( Throwable t ) {
      t.printStackTrace();
      System.exit( 2 );
    }
  }

  // ---- SAX DefaultHandler methods ----

  @Override public void startDocument() throws SAXException
  {
    echoString( sNEWLINE + "<?xml ...?>" + sNEWLINE + sNEWLINE );
  }

  @Override public void endDocument() throws SAXException
  {
    echoString( sNEWLINE );
  }

  @Override
  public void startElement( String namespaceURI,
                            String localName,   // local name
                            String qName,       // qualified name
                            Attributes attrs )
  throws SAXException
  {
    echoTextBuffer();
    String eName = ( "".equals( localName ) ) ? qName : localName;
    echoString( "<" + eName );                  // element name
    if( attrs != null )
    {
      for( int i=0; i<attrs.getLength(); i++ )
      {
        String aName = attrs.getLocalName( i ); // Attr name
        if( "".equals( aName ) )  aName = attrs.getQName( i );
        echoString( " " + aName + "=\"" + attrs.getValue( i ) + "\"" );
      }
    }
    echoString( ">" );
  }

  @Override
  public void endElement( String namespaceURI,
                          String localName,     // local name
                          String qName )        // qualified name
  throws SAXException
  {
    echoTextBuffer();
    String eName = ( "".equals( localName ) ) ? qName : localName;
    echoString( "</" + eName + ">" );           // element name
  }

  @Override
  public void characters( char[] buf, int offset, int len )
  throws SAXException
  {
    String s = new String( buf, offset, len );
    if( textBuffer == null )
      textBuffer = new StringBuffer( s );
    else
      textBuffer.append( s );
  }

  // ---- Helper methods ----

  // Display text accumulated in the character buffer
  private void echoTextBuffer()
  throws SAXException
  {
    if( textBuffer == null )  return;
    echoString( textBuffer.toString() );
    textBuffer = null;
  }

  // Wrap I/O exceptions in SAX exceptions, to
  // suit handler signature requirements
  private void echoString( String s )
  throws SAXException
  {
    try {
      if( null == out )
        out = new OutputStreamWriter( System.out, "UTF8" );
      out.write( s );
      out.flush();
    } catch( IOException ex ) {
      throw new SAXException( "I/O error", ex );
    }
  }
}

2. SAX-Programmierbeispiel:
XML einlesen und bestimmtes einzelnes Datenelement auslesen

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleSaxGetData.java' und kompilieren und führen ihn aus mit:

javac ExampleSaxGetData.java

java ExampleSaxGetData MyXmlFile.xml Button Title "Mein dritter Button" Comment

Falls Ihr Webbrowser die mit "java" beginnende Zeile auf zwei Zeilen umgebrochen hat: Bitte geben Sie diese als eine einzige Kommandozeile ein.

Die Kommandozeilenparameter haben folgende Bedeutung:

ParameterBeispielBedeutung
<XmlFile>MyXmlFile.xml In dieser XML-Datei wird gesucht
<ParentElem>Button Elemente mit diesem Tag-Namen werden untersucht
<ChildElem>Title Das gesuchte Element muss ein Child-Element mit diesem Tag-Namen haben
<FindText>"Mein dritter Button" Das Child-Element muss diesen Text als Inhalt haben
<DataElem>Comment Der komplette Inhalt dieses Child-Elements wird ausgelesen, auch inklusive Unterelementen (z.B. HTML-Tags)

Mit der Beispiel-XML-Datei 'MyXmlFile.xml' und den angegebenen Beispielparametern wird das dritte <Button>-Element gefunden, da dessen <Title>-Text mit der Suchvorgabe <FindText>="Mein dritter Button" übereinstimmt. Der Inhalt des durch <DataElem> vorgegebenen <Comment>-Elements wird ausgelesen und im Kommandozeilenfenster ausgegeben.

Die Variable 'iState' dient als Statusspeicher. Etwas unübersichtlich wird der Status dadurch, dass das gesuchte Element inklusive seiner Unterelemente ausgelesen werden soll (im Beispiel der String 'Dies ist <b>HTML</b>-<i>Text</i>.').

Das Programm funktioniert nur mit einfachen XML-Dateien und ohne Unterstützung von Namespaces.


// ExampleSaxGetData.java

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

public class ExampleSaxGetData
{
  public static void main( String[] args )
  {
    if( args.length != 5 )
    {
      System.err.println( "Usage:" );
      System.err.println( "java ExampleSaxGetData <XmlFile> "
                        + "<ParentElem> <ChildElem> <FindText> <DataElem>" );
      System.err.println( "Example:" );
      System.err.println( "java ExampleSaxGetData MyXmlFile.xml "
                        + "Button Title \"Mein dritter Button\" Comment" );
      System.exit( 1 );
    }
    try {
      MyDefaultHandlerImpl handler = new MyDefaultHandlerImpl();
      handler.args = args;
      SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
      saxParser.parse( new File( args[0] ), handler );
      if( 0 < handler.sbResult.length() )
      {
        System.out.println( "Result string in child element '<"
                            + args[4] + ">':" );
        System.out.println( handler.sbResult );
        System.exit( 0 );
      }
      else
      {
        System.out.println( "No fitting element found." );
        System.exit( 2 );
      }
    } catch( Throwable t ) {
      t.printStackTrace();
      System.exit( 3 );
    }
  }
}

// ---- SAX DefaultHandler ----
class MyDefaultHandlerImpl extends DefaultHandler
{
  public  String[]     args;
  public  StringBuffer sbResult = new StringBuffer();
  private int          iState   = 0;

  @Override
  public void startElement( String namespaceURI,
                            String localName,
                            String qName,
                            Attributes attrs )
  throws SAXException
  {
    if( 5 <= iState )  return;
    String eName = ( "".equals( localName ) ) ? qName : localName;
    if( null != eName )
    {
      if( eName.equals( args[1] ) )                 // <ParentElem>
        iState = 1;
      if( 1 == iState && eName.equals( args[2] ) )  // <ChildElem>
        iState = 2;
      if( 4 == iState )
        sbResult.append( "<" + eName + ">" );
      if( 3 == iState && eName.equals( args[4] ) )  // <DataElem>
        iState = 4;
    }
  }

  @Override
  public void endElement( String namespaceURI,
                          String localName,
                          String qName )
  throws SAXException
  {
    if( 5 <= iState )  return;
    String eName = ( "".equals( localName ) ) ? qName : localName;
    if( null != eName )
    {
      if( eName.equals( args[1] ) )                 // <ParentElem>
        iState = 0;
      if( 2 == iState && eName.equals( args[2] ) )  // <ChildElem>
        iState = 1;
      if( 4 == iState && eName.equals( args[4] ) )  // <DataElem>
        iState = 5;
      if( 4 == iState )
        sbResult.append( "</" + eName + ">" );
    }
  }

  @Override
  public void characters( char[] buf, int offset, int len )
  throws SAXException
  {
    if( 5 <= iState )  return;
    String s = new String( buf, offset, len );
    if( 2 == iState && s.equals( args[3] ) )        // <FindText>
      iState = 3;
    if( 4 == iState )
      sbResult.append( s );
  }
}

1. DOM-Programmierbeispiel:
XML einlesen und Ergebnis einiger DOM-Node-Abfragemethoden anzeigen

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleDomShowNodes.java' und kompilieren und führen ihn im Kommandozeilenfenster aus mit:

javac ExampleDomShowNodes.java

java ExampleDomShowNodes MyXmlFile.xml Button

Dokumentation zu den JAXP-Klassen und Methoden finden Sie unter: http://java.net/projects/jaxp-sources.


// ExampleDomShowNodes.java

import java.io.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;

public class ExampleDomShowNodes
{
  public static void main( String[] argv )
  {
    if( argv.length != 2 )
    {
      System.err.println( "Usage:   java ExampleDomShowNodes <XmlFile> <TagName>" );
      System.err.println( "Example: java ExampleDomShowNodes MyXmlFile.xml Button" );
      System.exit( 1 );
    }
    try {
      // ---- Parse XML file ----
      DocumentBuilderFactory factory  = DocumentBuilderFactory.newInstance();
      DocumentBuilder        builder  = factory.newDocumentBuilder();
      Document               document = builder.parse( new File( argv[0] ) );
      // ---- Get list of nodes to given element tag name ----
      NodeList ndList = document.getElementsByTagName( argv[1] );
      printNodesFromList( ndList );  // printNodesFromList see below
      // ---- Error handling ----
    } catch( SAXParseException spe ) {
        System.out.println( "\n** Parsing error, line " + spe.getLineNumber()
                                            + ", uri "  + spe.getSystemId() );
        System.out.println( "   " + spe.getMessage() );
        Exception e = ( spe.getException() != null ) ? spe.getException() : spe;
        e.printStackTrace();
    } catch( SAXException sxe ) {
        Exception e = ( sxe.getException() != null ) ? sxe.getException() : sxe;
        e.printStackTrace();
    } catch( ParserConfigurationException pce ) {
        pce.printStackTrace();
    } catch( IOException ioe ) {
        ioe.printStackTrace();
    }
  }

  // ---- Helper methods ----

  private static void printObjIfVisible( String sValName, Object obj )
  {
    if( null == obj )  return;
    String s = obj.toString();
    if( null != s && 0 < s.trim().length() && !s.trim().equals( "\n" ) )
      System.out.println( sValName + s );
  }

  public static void printNodeInfos( String sNodeName, Node node )
  {
    System.out.println(  "\n---------------------- " + sNodeName );
    if( null != node )
    {
      printObjIfVisible(   "getNodeType()        = ", "" + node.getNodeType() );
      printObjIfVisible(   "getNodeName()        = ", node.getNodeName() );
      printObjIfVisible(   "getLocalName()       = ", node.getLocalName() );
      printObjIfVisible(   "getNodeValue()       = ", node.getNodeValue() );
      if( node.hasAttributes() )
        printObjIfVisible( "getAttributes()      = ", node.getAttributes() );
      if( node.hasChildNodes() ) {
        printObjIfVisible( "getChildNodes()      = ", node.getChildNodes() );
        printObjIfVisible( "getFirstChild()      = ", node.getFirstChild() );
      }
      printObjIfVisible(   "getPreviousSibling() = ", node.getPreviousSibling() );
      printObjIfVisible(   "getNextSibling()     = ", node.getNextSibling() );
    }
    System.out.println(    "----------------------\n" );
  }

  public static void printNodesFromList( NodeList ndList )
  {
    for( int i=0; i<ndList.getLength(); i++ )
      printNodeInfos( "ndList.item("+i+")", ndList.item(i) );
  }
}

2. DOM-Programmierbeispiel:
XML einlesen, Element hinzufügen und neue XML-Datei erzeugen

Dieses Programmierbeispiel erfüllt die gleichen Anforderungen mit JAXP-DOM, wie das weiter unten folgende Programmierbeispiel 'ExampleJdomAddWrite.java' mit JDOM erfüllt, um den unterschiedlichen Programmieraufwand einschätzen zu können.

In einer XML-Datei wird ein bestimmtes Element gesucht, dessen Childelement einen bestimmten Text enthält. Vor dieses Element wird ein neues Element plaziert und das Ergebnis in eine neue XML-Datei gespeichert.

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleDomAddWrite.java' und kompilieren und führen ihn aus mit:

javac ExampleDomAddWrite.java

java ExampleDomAddWrite MyXmlFile.xml NewXmlFile.xml Button Title "Mein dritter Button" "Mein neuer Button"

Falls Ihr Webbrowser die mit "java" beginnende Zeile auf zwei Zeilen umgebrochen hat: Bitte geben Sie diese als eine einzige Kommandozeile ein.

Die Kommandozeilenparameter haben folgende Bedeutung:

ParameterBeispielBedeutung
<XmlFile>MyXmlFile.xml Diese XML-Datei wird zu Beginn gelesen
<NewFile>NewXmlFile.xml In diese XML-Datei wird das Ergebnis geschrieben (falls die Suchbedingungen erfüllt werden)
<ParentElem>Button Es werden Elemente mit diesem Tag-Namen gesucht
<Child>Title Das gesuchte Element muss ein Child-Element mit diesem Tag-Namen haben
<FindText>"Mein dritter Button" Das Child-Element muss diesen Text als Inhalt haben
<New>"Mein neuer Button" Nur wenn die vorhergehenden Suchbedingungen erfüllt sind, wird ein neues Element mit diesem Child-Element-Inhalt vor das gefundene Element eingefügt

Mit der Beispiel-XML-Datei 'MyXmlFile.xml' und den angegebenen Beispielparametern wird das dritte <Button>-Element gefunden, da dessen <Title>-Text mit der Suchvorgabe <FindText>="Mein dritter Button" übereinstimmt. Vor dieses <Button>-Element wird ein neues <Button>-Element mit dem angegebenen <Title>-Text <New>="Mein neuer Button" eingefügt. Das Ergebnis wird in die Datei 'NewXmlFile.xml' gespeichert, allerdings in wenig schöner Formatierung. Eine schönere Formatierung ist leicht mit JDOM realisierbar, wie die weiter unten gezeigten 'JDOM-Programmierbeispiele' demonstrieren.

Wenn Sie aus dem vorherigen Beispiel die Hilfsmethode 'printNodesFromList()' zu diesem Beispiel hinzufügen, können Sie an zwei Stellen die Kommentarzeichen '//' vor diesen Methodenaufrufen entfernen. Dann bekommen Sie die Knotenstruktur vor und nach der Änderung direkt im Kommandozeilenfenster angezeigt.

Das Beispielprogramm funktioniert für einfache XML-Dateien ohne Namespaces.


// ExampleDomAddWrite.java

import java.io.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class ExampleDomAddWrite
{
  public static void main( String[] argv )
  {
    if( argv.length != 6 )
    {
      System.err.println( "Usage:" );
      System.err.println( "java ExampleDomAddWrite <XmlFile> <NewFile>"
                            + " <ParentElem> <Child> <FindText> <New>" );
      System.err.println( "Example:" );
      System.err.println( "java ExampleDomAddWrite MyXmlFile.xml NewXmlFile.xml"
                            + " Button Title \"Mein dritter Button\""
                            +                " \"Mein neuer Button\"" );
      System.exit( 1 );
    }

    try {
      // ---- Parse XML file ----
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      // factory.setNamespaceAware( true );
      DocumentBuilder builder  = factory.newDocumentBuilder();
      Document        document = builder.parse( new File( argv[0] ) );
      Node            rootNode = document.getDocumentElement();

      // ---- Get list of nodes to given tag ----
      NodeList ndList = document.getElementsByTagName( argv[2] );
      // System.out.println( "\nNode list at the beginning:" );
      // printNodesFromList( ndList );

      // ---- Loop through the list of main nodes ----
      for( int i=0; i<ndList.getLength(); i++ )
      {
        Node     nodeMain     = ndList.item( i );
        Node     nodeChild    = null;
        NodeList ndListChilds = nodeMain.getChildNodes();
        boolean  bChildFound  = false;
        if( null == ndListChilds )  continue;
        // Loop through the list of child nodes
        for( int j=0; j<ndListChilds.getLength(); j++ )
        {
          nodeChild = ndListChilds.item( j );
          if( null == nodeChild )  continue;
          String sNodeName = nodeChild.getNodeName();
          if( null == sNodeName )  continue;
          if( sNodeName.equals( argv[3] ) )
          {
            bChildFound = true;
            break;
          }
        }
        if( !bChildFound || nodeChild == null )  continue;
        Node nodeData = nodeChild.getFirstChild();
        if( null == nodeData ||
            !(nodeData instanceof org.w3c.dom.Text) )  continue;
        String sData = nodeData.getNodeValue();
        if( null == sData ||
            !sData.equals( argv[4] ) )  continue;

        // ---- Create a new node element and insert it ----
        Node newMainNode  = document.createElement(  argv[2] );
        Node newChildNode = document.createElement(  argv[3] );
        Text newTextNode  = document.createTextNode( argv[5] );
        newChildNode.appendChild( newTextNode );
        newMainNode.appendChild( newChildNode );
        rootNode.insertBefore( newMainNode, nodeMain );
        rootNode.normalize();
        // System.out.println( "Node list after modification:" );
        // printNodesFromList( ndList );
        break;
      }

      // ---- Use a XSLT transformer for writing the new XML file ----
      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      DOMSource        source = new DOMSource( document );
      FileOutputStream os     = new FileOutputStream( new File( argv[1] ) );
      StreamResult     result = new StreamResult( os );
      transformer.transform( source, result );

      // ---- Error handling ----
    } catch( TransformerConfigurationException tce ) {
        System.out.println( "\n** Transformer Factory error" );
        System.out.println( "   " + tce.getMessage() );
        Throwable e = ( tce.getException() != null ) ? tce.getException() : tce;
        e.printStackTrace();
    } catch( TransformerException tfe ) {
        System.out.println( "\n** Transformation error" );
        System.out.println( "   " + tfe.getMessage() );
        Throwable e = ( tfe.getException() != null ) ? tfe.getException() : tfe;
        e.printStackTrace();
    } catch( SAXParseException spe ) {
        System.out.println( "\n** Parsing error, line " + spe.getLineNumber()
                                            + ", uri "  + spe.getSystemId() );
        System.out.println( "   " + spe.getMessage() );
        Exception e = ( spe.getException() != null ) ? spe.getException() : spe;
        e.printStackTrace();
    } catch( SAXException sxe ) {
        Exception e = ( sxe.getException() != null ) ? sxe.getException() : sxe;
        e.printStackTrace();
    } catch( ParserConfigurationException pce ) {
        pce.printStackTrace();
    } catch( IOException ioe ) {
        ioe.printStackTrace();
    }
  }
}

Weitere JAXP-Programmierbeispiele

Weitere JAXP-Programmierbeispiele finden Sie unter:
http://java.sun.com/developer/codesamples/xml.html
http://people.apache.org/~edwingo/jaxp-ri-1.2.0-fcs/docs/samples.html



Einfache Programmierbeispiele mit JDOM

Voraussetzungen

  1. Installieren Sie ein aktuelles Java SE JDK wie zum Beispiel beschrieben unter:
    techdocs/java-install.htm#InstallationUnterWindows.
  2. Stellen Sie sicher, dass die Environment-Settings für 'JAVA_HOME' und 'Path' korrekt sind, zum Beispiel so:

    set JAVA_HOME=C:\Program Files\Java\jdk1.6

    set Path=%JAVA_HOME%\bin;%Path%

  3. Downloaden Sie das aktuelle JDOM-Paket (z.B. 'jdom-1.0.zip') von http://www.jdom.org/dist/binary in ein beliebiges temporäres Verzeichnis und entzippen Sie die Datei. Suchen Sie in dem entzippten Verzeichnisbaum nach der Datei 'jdom.jar' (z.B. im Unterverzeichnis 'jdom-1.0/build'). Kopieren Sie 'jdom.jar' in das von Ihnen bevorzugte Verzeichnis für Java-Zusatzbibliotheken, zum Beispiel nach '$JAVA_HOME/jre/lib/ext' bzw. 'C:\Program Files\Java\jdk1.6\jre\lib\ext'.
  4. Die JDOM-Bibliothek 'jdom.jar' muss im 'CLASSPATH' eingetragen sein. Dafür gibt es mehrere Möglichkeiten:
    a) Entweder Sie fügen 'jdom.jar' im 'CLASSPATH' in Ihren generellen Environment-Settings im Betriebssystem hinzu, zum Beispiel analog zu:

    set CLASSPATH=.;C:\Program Files\Java\jdk1.6\jre\lib\ext\jdom.jar

    b) Oder Sie starten Ihr Programm über eine Batchdatei, in der Sie die genannte Zeile einfügen.
    c) Oder Sie geben den Pfad zu 'jdom.jar' beim Aufruf Ihres Java-Programms an, wie auch in den folgenden Programmierbeispielen gezeigt wird, zum Beispiel so:

    java -classpath .;C:\Program Files\Java\jdk1.6\jre\lib\ext\jdom.jar MeinJavaProgr

    Bei allen Alternativen ist wichtig, dass Sie im 'CLASSPATH' immer auch das aktuelle Verzeichnis mit angeben, der 'CLASSPATH' sollte also mit '.;' beginnen.
  5. Lesen Sie zur Einführung folgende Tutorials:
    http://www.servlets.com/speaking/jdom-javaone.pdf
    http://www.cafeconleche.org/books/xmljava/chapters/ch14.html
    http://www.javaworld.com/javaworld/jw-05-2000/jw-0518-jdom.html
  6. Das JDOM-API ist dokumentiert unter:
    http://www.jdom.org/docs/apidocs

1. JDOM-Programmierbeispiel:
XML einlesen und schön formatiert ausgeben

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleJdomWrite.java' und kompilieren und führen ihn im Kommandozeilenfenster aus mit:

javac -classpath .;jdom.jar ExampleJdomWrite.java

java -classpath .;jdom.jar ExampleJdomWrite MyXmlFile.xml

Falls Sie 'jdom.jar' bereits im globalen 'CLASSPATH' eingetragen haben, können Sie den Teil '-classpath .;jdom.jar' in beiden Kommandos weglassen. Die gezeigte Schreibweise der Kommandos benötigt keinen vorher speziell gesetzten 'CLASSPATH', aber setzt voraus, dass die Datei 'jdom.jar' im selben Verzeichnis wie das Java-Programm gespeichert ist. Falls 'jdom.jar' woanders gespeichert ist, müssen Sie den Pfad voranstellen.

Dokumentation zu den JDOM-Klassen und Methoden finden Sie unter: http://www.jdom.org/docs/apidocs.

Anders als im oben gezeigtem DOM-Programmierbeispiel 'ExampleDomAddWrite.java' erfolgt hier die Ausgabe in schön formatierter Form.

Beachtenswert ist, dass zum Lesen ein SAX-Parser eingesetzt wird, damit kein zweiter DOM-Baum aufgebaut wird, der nur Speicherplatz verbrauchen würde. Trotzdem erfolgt die weitere Bearbeitung der XML-Daten über die JDOM-Baumstruktur.


// ExampleJdomWrite.java

import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class ExampleJdomWrite
{
  public static void main( String[] args )
  {
    if( args.length != 1 )
    {
      System.err.println( "Usage: java ExampleJdomWrite MyXmlFile.xml" );
      System.exit( 1 );
    }
    try {
      // ---- Read XML file ----
      SAXBuilder builder = new SAXBuilder();
      Document doc = builder.build( new File( args[0] ) );
      // ---- Modify XML data ----
      //  ... do anything with XML data
      // ---- Write XML file ----
      XMLOutputter fmt = new XMLOutputter();
      fmt.setFormat( Format.getPrettyFormat() );  // only for nicer formatting
      fmt.output( doc, System.out );
    } catch( Exception ex ) {
      ex.printStackTrace();
    }
  }
}

2. JDOM-Programmierbeispiel:
XML einlesen, Element hinzufügen und neue XML-Datei erzeugen

Dieses Programmierbeispiel erfüllt die gleichen Anforderungen mit JDOM, wie das oben aufgeführte Programmierbeispiel 'ExampleDomAddWrite.java' mit JAXP-DOM erfüllt hat. Das JDOM-Beispiel erzeugt eine schön formatierte Ausgabe und ist kürzer und einfacher.

In einer XML-Datei wird ein bestimmtes Element gesucht, dessen Childelement einen bestimmten Text enthält. Vor dieses Element wird ein neues Element plaziert und das Ergebnis in eine neue XML-Datei gespeichert.

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleJdomAddWrite.java' und kompilieren und führen ihn aus mit:

javac -classpath .;jdom.jar ExampleJdomAddWrite.java

java -classpath .;jdom.jar ExampleJdomAddWrite MyXmlFile.xml NewXmlFile.xml Button Title "Mein dritter Button" "Mein neuer Button"

Bezüglich des Kommandozeilenteils '-classpath .;jdom.jar' beachten Sie bitte die Hinweise unter 'JDOM-Voraussetzungen' und '1. JDOM-Programmierbeispiel'.

Falls Ihr Webbrowser die mit "java" beginnende Zeile auf zwei Zeilen umgebrochen hat: Bitte geben Sie diese als eine einzige Kommandozeile ein.

Die Kommandozeilenparameter haben folgende Bedeutung:

ParameterBeispielBedeutung
<XmlFile>MyXmlFile.xml Diese XML-Datei wird zu Beginn gelesen
<NewFile>NewXmlFile.xml In diese XML-Datei wird das Ergebnis geschrieben (falls die Suchbedingungen erfüllt werden)
<ParentElem>Button Es werden Elemente mit diesem Tag-Namen gesucht
<Child>Title Das gesuchte Element muss ein Child-Element mit diesem Tag-Namen haben
<FindText>"Mein dritter Button" Das Child-Element muss diesen Text als Inhalt haben
<New>"Mein neuer Button" Nur wenn die vorhergehenden Suchbedingungen erfüllt sind, wird ein neues Element mit diesem Child-Element-Inhalt vor das gefundene Element eingefügt

Mit der Beispiel-XML-Datei 'MyXmlFile.xml' und den angegebenen Beispielparametern wird das dritte <Button>-Element gefunden, da dessen <Title>-Text mit der Suchvorgabe <FindText>="Mein dritter Button" übereinstimmt. Vor dieses <Button>-Element wird ein neues <Button>-Element mit dem angegebenen <Title>-Text <New>="Mein neuer Button" eingefügt. Das Ergebnis wird in die Datei 'NewXmlFile.xml' gespeichert.


// ExampleJdomAddWrite.java

import java.util.*;
import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class ExampleJdomAddWrite
{
  public static void main( String[] args )
  {
    if( args.length != 6 )
    {
      System.err.println( "Attention:" );
      System.err.println( "jdom.jar must be added to classpath." );
      System.err.println( "Usage:" );
      System.err.println( "java ExampleJdomAddWrite <XmlFile> <NewFile>"
                            + " <ParentElem> <Child> <FindText> <New>" );
      System.err.println( "Example:" );
      System.err.println( "java -classpath .;jdom.jar ExampleJdomAddWrite"
                            + " MyXmlFile.xml NewXmlFile.xml Button Title"
                            + " \"Mein dritter Button\" \"Mein neuer Button\"" );
      System.exit( 1 );
    }
    try {
      // ---- Read XML file ----
      SAXBuilder builder = new SAXBuilder();
      Document doc = builder.build( new File( args[0] ) );
      // ---- Modify XML data ----
      Element root = doc.getRootElement();
      List listParentElements = root.getChildren( args[2] );  // <ParentElem>
      for( int i=0; i<listParentElements.size(); i++ )
      {
        // Find searched element with given text:
        Element elMain  = (Element)(listParentElements.get( i ));
        if( null == elMain )  continue;
        Element elChild = elMain.getChild( args[3] );       // <Child>
        if( null == elChild )  continue;
        String s = elChild.getTextTrim();
        if( null == s || !s.equals( args[4] ) )  continue;  // <FindText>
        // Add new element at correct position:
        Element elNew = new Element( args[2] );             // <ParentElem>
        elNew.addContent( (new Element( args[3] )).addContent( args[5] ) );
        listParentElements.add( i, elNew );                   // <New>
        // ---- Write XML file ----
        XMLOutputter outp = new XMLOutputter();
        outp.setFormat( Format.getPrettyFormat() );
        outp.output( doc, new FileOutputStream( new File( args[1] ) ) );
        break;                                              // <NewFile>
      }
    } catch( Exception ex ) {
      ex.printStackTrace();
    }
  }
}

3. JDOM-Programmierbeispiel:
XML einlesen, Element mit Attribut suchen, Attribut ergänzen, XML speichern

In einer XML-Datei wird ein bestimmtes Element gesucht, dessen Attribut einen bestimmten Wert hat. Diesem Element wird ein neues Attribut hinzugefügt und das Ergebnis in eine neue XML-Datei gespeichert.

Im selben Verzeichnis, wo sich die oben gezeigte Beispiel-XML-Datei 'MyXmlFile.xml' befindet, speichern Sie den folgenden Java-Sourcecode unter dem Namen 'ExampleJdomAttr.java' und kompilieren und führen ihn aus mit:

javac -classpath .;jdom.jar ExampleJdomAttr.java

java -classpath .;jdom.jar ExampleJdomAttr MyXmlFile.xml NewXmlFile.xml Button size small col blue

Bezüglich des Kommandozeilenteils '-classpath .;jdom.jar' beachten Sie bitte die Hinweise unter 'JDOM-Voraussetzungen' und '1. JDOM-Programmierbeispiel'.

Falls Ihr Webbrowser die mit "java" beginnende Zeile auf zwei Zeilen umgebrochen hat: Bitte geben Sie diese als eine einzige Kommandozeile ein.

Die Kommandozeilenparameter haben folgende Bedeutung:

ParameterBeispielBedeutung
<XmlFile>MyXmlFile.xml Diese XML-Datei wird zu Beginn gelesen
<NewFile>NewXmlFile.xml In diese XML-Datei wird das Ergebnis geschrieben (falls die Suchbedingungen erfüllt werden)
<Elem>Button Es werden Elemente mit diesem Tag-Namen gesucht
<AttrS>size Das gesuchte Element muss ein Attribut mit diesem Namen haben
<ValS>small Das Attribut muss diesen Wert haben
<AttrNew>col Nur wenn die vorhergehenden Suchbedingungen erfüllt sind, wird ein neues Attribut mit diesem Namen hinzugefügt
<ValN>blue Das neue Attribut erhält diesen Wert

Mit der Beispiel-XML-Datei 'MyXmlFile.xml' und den angegebenen Beispielparametern wird das zweite <Button>-Element gefunden, da dessen size-Attribut den gesuchten Wert <ValS>="small" hat. Diesem <Button>-Element wird ein neues Attribut mit dem angegebenen Namen <AttrNew>=col und dem Wert <ValN>="blue" hinzugefügt. Das Ergebnis wird in die Datei 'NewXmlFile.xml' gespeichert.


// ExampleJdomAttr.java

import java.util.*;
import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class ExampleJdomAttr
{
  public static void main( String[] args )
  {
    if( args.length != 7 )
    {
      System.err.println( "Attention:" );
      System.err.println( "jdom.jar must be added to classpath." );
      System.err.println( "Usage:" );
      System.err.println( "java ExampleJdomAttr <XmlFile> <NewFile>"
                            + " <Elem> <AttrS> <ValS> <AttrNew> <ValN>" );
      System.err.println( "Example:" );
      System.err.println( "java -classpath .;jdom.jar ExampleJdomAttr"
                            + " MyXmlFile.xml NewXmlFile.xml"
                            + " Button size small col blue" );
      System.exit( 1 );
    }
    try {
      // ---- Read XML file ----
      SAXBuilder builder = new SAXBuilder();
      Document doc = builder.build( new File( args[0] ) );  // <XmlFile>
      // ---- Modify XML data ----
      Element root = doc.getRootElement();
      List listParentElements = root.getChildren( args[2] );  // <Elem>
      for( int i=0; i<listParentElements.size(); i++ )
      {
        // Find searched element with given attribute:
        Element elMain  = (Element)(listParentElements.get( i ));
        if( null == elMain )  continue;
        String s = elMain.getAttributeValue( args[3] );     // <AttrS>
        if( null == s || !s.equals( args[4] ) )  continue;  // <ValS>
        // Add new attribute to correct element:
        elMain.setAttribute( args[5], args[6] );            // <AttrNew>=<ValN>
        // ---- Write result ----
        XMLOutputter outp = new XMLOutputter();
        outp.setFormat( Format.getPrettyFormat() );
        // ---- Show the modified element on the screen ----
        System.out.println( "\nModified Element:\n" );
        outp.output( elMain, System.out );
        System.out.println();
        // ---- Write the complete result document to XML file ----
        outp.output( doc, new FileOutputStream( new File( args[1] ) ) );
        break;                                              // <NewFile>
      }
    } catch( Exception ex ) {
      ex.printStackTrace();
    }
  }
}





Weitere Themen: andere TechDocs | XSD (Schema) | JAXB (Binding) | XSL, XSLT, XSL-FO
© 2001-2010 Torsten Horn, Aachen