Galileo Computing <openbook>
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Buch: Java ist auch eine Insel - Zum Katalog
gp Kapitel 13 Die eXtensible Markup Language (XML)
  gp 13.1 Auszeichnungssprachen
    gp 13.1.1 Die Standard Generalized Markup Language (SGML)
    gp 13.1.2 Extensible Markup Language (XML)
  gp 13.2 Eigenschaften von XML-Dokumenten
    gp 13.2.1 Elemente und Attribute
    gp 13.2.2 Beschreibungssprache für den Aufbau von XML-Dokumenten
    gp 13.2.3 Schema, eine Alternative zu DTD
    gp 13.2.4 Namensraum (Namespace)
    gp 13.2.5 XML-Applikationen
  gp 13.3 Die Java APIs für XML
    gp 13.3.1 Das Document Object Model (DOM)
    gp 13.3.2 Simple API for XML Parsing (SAX)
    gp 13.3.3 Java Document Object Model (JDOM)
  gp 13.4 XML-Dateien mit JDOM verarbeiten
    gp 13.4.1 JDOM beziehen
    gp 13.4.2 Paketübersicht
    gp 13.4.3 Die Document-Klasse
    gp 13.4.4 Eingaben aus der Datei lesen
    gp 13.4.5 Das Dokument als XML-Datei ausgeben
    gp 13.4.6 Der Dokumententyp
    gp 13.4.7 Elemente
    gp 13.4.8 Zugriff auf Elementinhalte
    gp 13.4.9 Liste mit Unterelementen erzeugen
    gp 13.4.10 Neue Elemente einfügen und ändern
    gp 13.4.11 Attributinhalte lesen und ändern
  gp 13.5 JAXP als Java-Schnittstelle zu XML
    gp 13.5.1 Einführung in XSLT
    gp 13.5.2 Umwandlung von XML-Dateien mit JDOM und JAXP

Kapitel 13 Die eXtensible Markup Language (XML)

Ich habe die Länge und Breite dieses Landes bereist und mit den besten Leuten geredet, und ich kann Ihnen versichern, dass Datenverarbeitung
ein Tick ist, welcher dieses Jahr nicht überleben wird.
– Editor für Computerbücher bei Prentice Hall, 1957


Galileo Computing

13.1 Auszeichnungssprachen  downtop

Auszeichnungssprachen dienen zur strukturierten Gliederung von Texten und Daten. Ein Text besteht zum Beispiel aus Überschriften, Fußnoten und Absätzen, eine Rechnung aus den einzelnen Rechnungsposten wie Betrag und Kontonummer. Auszeichnungssprachen liegt die Idee zu Grunde, besondere Bausteine durch Auszeichnung hervorzuheben. So könnte ein Text etwa so beschrieben sein:

<Überschrift>
Mein Buch
<Ende Überschrift>
Hui ist das <fett>toll<Ende fett>.

Als Leser eines Buches erkennen wir zwar optisch eine Überschrift an der Schriftart, ein Computer hat damit aber seine Schwierigkeiten. Wir wollen aber auch dem Rechner die Möglichkeit geben, die Struktur zu erkennen.

HTML war die erste populäre Auszeichnungssprache, die Auszeichnungselemente (engl. Tags) wie <b>fett</b> benutzt, um bestimmte Eigenschaften von Elementen zu kennzeichnen. Damit wurde eine Visualisierung verbunden, etwa bei einer Überschrift fett und mit großer Schrift. Leider werden Auszeichnungssprachen wie HTML dazu benutzt, Formatierungseffekte zu erzielen. Zum Beispiel werden Überschriften mit dem Überschriften-Tag ausgezeichnet. Wenn an anderer Stelle eine Textstelle fett und groß sein soll, wird diese Textstelle auch mit dem Überschriften-Tag markiert, obwohl es keine Überschrift ist.


Galileo Computing

13.1.1 Die Standard Generalized Markup Language (SGML)  downtop

Das Beispiel der Überschrift in einem Buch zeigt die Idee, Bausteine mit Typen in Verbindung zu bringen. Der allgemeine Aufbau mit diesen Auszeichnungselementen lässt sich dann für beliebige hierarchische Dokumente nutzen. Eine Definition einer Auszeichnungssprache (Metasprache) ist daher auch nicht weiter schwierig. Schon Mitte der 80er-Jahre wurde als ISO-Standard die Standard Generalized Markup Language (SGML) definiert, die Basis für beliebige Auszeichnungssprachen ist. Ab der Version 2.0 ist auch HTML als SGML-Anwendung definiert. Leider kam mit den großen Freiheiten und der hohen Flexibilität eine große und aufwendige Deklaration der Anwendungen hinzu. Ein SGML-Dokument musste einen ganz bestimmten Aufbau besitzen. SGML-Dateien waren daher etwas unflexibel, da die Struktur genau eingehalten werden musste. Für HTML-Dateien wäre das schlecht, da die Browser-Konkurrenten produktspezifische Tags definieren, die auf den Browser des jeweiligen Herstellers beschränkt bleiben. So interpretiert der Internet-Explorer zum Beispiel das Tag <blink>blinkend</blink> nicht. Tags, die ein Browser nicht kennt, überliest er einfach.


Galileo Computing

13.1.2 Extensible Markup Language (XML)  downtop

Für reine Internetseiten hat sich HTML etabliert, aber für andere Anwendungen wie Datenbanken oder Rechnungen ist HTML nicht geeignet. Für SGML sprechen die Korrektheit und Leistungsfähigkeit – dagegen sprechen die Komplexität und Notwendigkeit eine Beschreibung für die Struktur angeben zu müssen. Daher setzte sich das W3C zusammen, um eine neue Auszeichnungssprache zu entwickeln, die so flexibel wie SGML ist, aber so einfach zu nutzen und zu implementieren ist wie HTML. Das Ergebnis ist die eXtensible Markup Language (XML). Diese Auszeichnungssprache ist für Compiler einfach zu verarbeiten, da es genaue Vorgaben gibt, wann ein Dokument in Ordnung ist.

Wenn von XML die Rede ist, ist nicht nur der Standard zur Beschreibung von Daten gemeint. Oft sind im gleichen Zusammenhang eine oder mehrere Technologien, die im Zusammenhang mit der Beschreibungssprache stehen, gemeint. Die wichtigsten Technologien zur Verarbeitung von XML in Java werden hier kurz vorgestellt. Eine ausführliche Beschreibung mit allen Nachbartechnologien findet der interessierte Leser auf den Web-seiten vom W3C unter http://www.w3c.org.


Galileo Computing

13.2 Eigenschaften von XML-Dokumenten  downtop


Galileo Computing

13.2.1 Elemente und Attribute  downtop

Der Inhalt eines XML-Dokuments besteht aus strukturierten Elementen, die hierarchisch geschachtelt sind. Dazwischen befindet sich der Inhalt, der aus weiteren Elementen (daher hierarchisch) und aus reinem Text bestehen kann. Die Elemente können Attribute enthalten, die zusätzliche Informationen in einem Element ablegen.

Listing 13.1   party.xml
<party datum="31.12.01">
  <gast name="Albert Angsthase">
    <getraenk>Wein</getraenk>
    <getraenk>Bier</getraenk>
    <zustand ledig=“true“ nuechtern=“false“/>
  </gast>
</party>

Die Groß- und Kleinschreibung der Namen für Elemente und Attribute ist wichtig für die Unterscheidung. Ein Attribut besteht aus einem Attributnamen und einem Wert. Der Attributwert steht immer in einfachen oder doppelten Anführungszeichen und wird dem Attributnamen mit dem Gleichheitszeichen zugewiesen.

Verwendung von Tags

Für die Angabe der Elemente werden die Tags benutzt. Diese Tags werden gemäß der Reference Concrete Syntax durch spitze Klammern gekennzeichnet. Elemente existieren in zwei Varianten. Falls das Element einen Wert einschließt, besteht es aus einem Anfangs-Tag und einem End-Tag. Der Anfangs-Tag gibt den Namen des Tags vor und enthält die Attribute. Der End-Tag hat den gleichen Namen wie das Anfangs-Tag und wird durch einen Schrägstrich nach der ersten Klammer gekennzeichnet. Zwischen dem Anfangs-Tag und dem End-Tag steht der Inhalt des Elements.

Beispiel Das Element <getraenk> mit dem Wert Wein.
<getraenk>Wein</getraenk>

Ein Element, das keine Inhalte einschließt, besteht nur aus einem Tag mit einem Schrägstrich vor der schließenden spitzen Klammer. Diese Tags haben entweder Attribute als Inhalt oder das Auftreten des Tags ist Bestandteil des Inhalts.

Beispiel Das Element <zustand> mit dem Attribut ledig und nuechtern.
<zustand ledig="true" nuechtern="false"/>

Bedeutung der Tags

Durch die freie Namensvergabe in XML-Dokumenten ist eine formatierte Darstellung eines Dokuments nicht möglich. Anders als bei HTML, gibt es keine festgelegte Menge von Tags, die den Inhalt nach bestimmten Kriterien formatieren. Falls das XML-Dokument in einem Browser dargestellt werden soll, sind zusätzliche Beschreibungen in Form von Formatvorlagen (Stylesheets) für die Darstellung in HTML notwendig.

Wohlgeformt

Ein korrektes XML-Dokument muss einige Bedingungen einhalten, dann ist es wohlgeformt. Wenn es nicht wohlgeformt ist, ist es auch kein XML-Dokument. Damit ein XML-Dokument wohlgeformt ist, muss jedes Element aus einem Anfangs- und einem End-Tag oder nur aus einem abgeschlossenen Tag bestehen. Hierarchische Elemente müssen in umgekehrter Reihenfolge ihrer Öffnung wieder geschlossen werden. Durch die Anordnung der öffnenden und schließenden Tags wird die Struktur des XML-Dokuments festgelegt. Jedes XML-Dokument muss ein Wurzelelement enthalten, das alle anderen Elemente einschließt.

Beispiel Das Wurzelelement heißt <party> und schließt das Element <gast> ein.
<party datum="31.12.01">
  <gast name="Albert Angsthase"></gast>
</party>

Spezielle Zeichen in XML (Entitäten)

Wir müssen darauf achten, dass einige Zeichen in XML spezielle Bedeutung haben. Dazu gehören &, <, >, " und . Sie werden im Text durch spezielle Abkürzungen, die Entitäten, abgebildet. Dies sind für die oben genannten Zeichen &amp;, &lt;, &gt;, &quot; und &apos;. Diese Entitäten für die Sonderzeichen sind die einzigen, die durch den Standard festgelegt sind.

Kommentare

XML-Dokumente können auch Kommentare enthalten. Diese werden beim Auswerten der Daten übergangen. Durch Kommentare wird die Qualität des XML-Dokuments für den Benutzer wesentlich verbessert. Kommentare können an jeder Stelle des Dokuments verwendet werden, nur nicht innerhalb der Tags. Kommentare haben die Form:

<!-- Text des Kommentars -->

Der beste Kommentar eines XML-Dokuments ist die sinnvolle Gliederung des Dokuments und sprechende Namen für Tags und Attribute.

Kopfdefinition

Die Wohlgeformtheit muss mindestens erfüllt sein. Zusätzlich dürfen noch andere Elemente eingebaut werden. Dazu gehört etwa eine Kopfdefinition, die etwa

<?xml version="1.0"?>

lauten kann. Diese Kopfdefinition lässt sich durch Attribute erweitern. In diesem Beispiel wird die verwendete XML-Version und die Zeichenkodierung angeben.

<?xml version="1.0" version="1.0" encoding="iso-8859-1"?>

Wenn eine XML-Deklaration vorhanden ist, muss sie ganz am Anfang des Dokuments stehen. Dort lässt sich auch die benutzte Zeichenkodierung definieren, wenn sie nicht automatisch UTF-8 oder UTF-16 ist. Automatisch kann jedes beliebige Unicode-Zeichen unabhängig von der Kodierung über das Kürzel &#xABCD; (A, B, C, D stehen für Hexadezimalzeichen) dargestellt werden.

Die XML-Deklaration wird in Form einer Processing-Instruction (PI) dargestellt. Eine PI wird durch ein Fragezeichen nach der öffnenden spitzen Klammer markiert. Dies ist nicht Bestandteil des Inhalts der XML-Datei, sondern wird von der Anwendung, die diese XML-Datei verarbeitet, ausgewertet.


Galileo Computing

13.2.2 Beschreibungssprache für den Aufbau von XML-Dokumenten  downtop

Im Gegensatz zu HTML ist bei XML die Menge der Tags und deren Kombination nicht festgelegt. Für jede Anwendung können beliebige Tags definiert und verwendet werden. Um aber überprüfen zu können, ob eine XML-Datei für eine bestimmte Anwendung die richtige Form hat, wird eine formale Beschreibung dieser Struktur benötigt. Diese formale Struktur wird in einem bestimmten Format beschrieben. Dafür wird üblicherweise eine Document Type Definition (DTD) oder ein Schema verwendet. Mit ihrer Hilfe wird festgelegt, welche Tags zwingend vorgeschrieben sind, welchen Inhalt diese Tags haben, wie Tags miteinander verschachtelt sind, und welche Attribute ein Element hat. Damit wird beschrieben, wann eine XML-Datei gültig ist. Mittlerweile gibt es eine große Anzahl von Beschreibungen in Form von DTD und Schema, die Formatierungen für die verschiedensten Daten bieten. Einige DTDs sind unter http://www.xml.org/xmlorg_registry/index.shtml aufgeführt. Um Datenaustausch für eine bestimmte Anwendung zu gewährleisten, ist eine eindeutige Beschreibung unerlässlich. Es wäre problematisch, wenn die Unternehmen unter der Struktur einer Rechnung immer etwas Verschiedenes sehen würden.

Document Type Definition (DTD)

Für die folgende XML-Datei entwickeln wir eine DTD zur Beschreibung der Struktur.

Listing 13.2   party.xml
<?xml version="1.0" ?>
<party datum=“31.12.01“>
<gast name="Albert Angsthase">
<getraenk>Wein</getraenk>
<getraenk>Bier</getraenk>
<zustand ledig=“true“ nuechtern=“false“/>
</gast>
<gast name="Martina Mutig">
<getraenk>Apfelsaft</getraenk>
<zustand ledig=“true“ nuechtern=“true“/>
</gast>
<gast name="Zacharias Zottelig"></gast>
</party>

Für diese XML-Datei legen wir die Struktur fest und beschreiben sie in einer DTD. Dazu sammeln wir zuerst die Daten, die in dieser XML-Datei stehen.

Element Name Attribute Untergeordnete Elemente Aufgabe
party datum
Datum der Party
gast Wurzelelement mit dem Datum der Party als
Attribut
gast name
Name des Gasts
getraenk und zustand Die Gäste der Party, Name des Gasts als
Attribut
getraenk     Getränk des Gasts als Text
zustand ledig und nuechtern   Familienstand und Zustand als Attribut

Elementbeschreibung

Die Beschreibung der Struktur eines Elements besteht aus dem Elementnamen und dem Typ. Sie kann auch aus einem oder mehreren untergeordneten Elementen in Klammern bestehen. Der Typ legt die Art der Daten in dem Element fest. Mögliche Typen sind etwa PCDATA (Parsed Character Data) für einfachen Text oder ANY für beliebige Daten.

Untergeordnete Elemente werden als Liste der Elementnamen angegeben. Die Namen sind durch ein Komma getrennt. Falls verschiedene Elemente oder Datentypen alternativ vorkommen können, werden diese ebenfalls in Klammern angegeben und mit dem ODER-Operator (|) verknüpft. Hinter jedem Element und hinter der Liste von Elementen wird durch einen Operator festgelegt, wie häufig das Element oder die Folgen von Elementen erscheinen müssen. Falls kein Operator angegeben ist, muss das Element oder die Elementliste genau einmal erscheinen. Folgende Operatoren stehen zur Verfügung:

? Einmal oder gar nicht
+ Mindestens einmal
* Keinmal, einmal oder beliebig oft

Beispiel Das Element <party>.
<!ELEMENT party (gast)*>

Das Element <party> hat als Inhalt beliebig viele Unterelemente vom Typ <gast>. Damit wird ausgedrückt, dass auf einer Party beliebig viele Gäste erscheinen können.

Attributbeschreibung

Die Beschreibung der Attribute sieht sehr ähnlich aus. Sie besteht aus dem Element, den Attributnamen, den Datentypen der Attribute und einem Modifizierer. In einem Attribut können als Werte keine Elemente angegeben werden, sondern nur Datentypen wie CDATA (Character Data). Der Modifizierer legt fest, ob ein Attribut zwingend vorgeschrieben ist oder nicht. Folgende Modifizierer stehen zur Verfügung:

#IMPLIED Muss nicht vorkommen
#REQUIRED Muss auf jeden Fall vorkommen
#FIXED [Wert] Der Wert wird gesetzt und kann nicht verändert werden

Beispiel Das Attribut datum für das Element <party>:
<!ATTLIST party datum CDATA 
#REQUIRED>

Der Wert des Attributs datum ist Text und muss angegeben sein (festgelegt durch den Modifizierer #REQUIRED).

Kümmern wir uns um die Beschreibung eines Gasts, der einen Namen und einen Zustand hat.

<!ELEMENT gast (getraenk*, zustand?)>
<!ATTLIST gast name CDATA #REQUIRED>

Das Element hat als Attribut name und die Unterelemente <getraenk> und <zustand>. Ein Gast kann kein Getränk, ein Getränk oder viele Getränke einnehmen. Die Attribute des Elements <zustand> müssen genau einmal oder gar nicht vorkommen.

Das Element <getraenk> hat keine Unterelemente, aber einen Text, der das Getränk beschreibt.

<!ELEMENT getraenk (#PCDATA)>

Das Element <zustand> hat keinen Text und keine Unterelemente, aber die Attribute ledig und nuechtern, die mit Text gefüllt sind. Die Attribute müssen nicht unbedingt angegeben werden (Modifizierer #IMPLIED).

<!ELEMENT zustand EMPTY>
<!ATTLIST zustand ledig CDATA #IMPLIED
   nuechtern CDATA #IMPLIED>

Sich auf eine DTD beziehen

Falls die DTD in einer speziellen Datei steht, wird im Kopf der XML-Datei angegeben, wo die DTD für dieses XML-Dokument steht:

<!DOCTYPE party SYSTEM "dtd\partyfiles\party.dtd">

Hinter DOCTYPE wird das Wurzelelement der XML-Datei angegeben. Hinter SYSTEM steht die URI mit der Adresse der DTD-Datei. Die DTD selbst kann in einer eigenen Datei stehen oder Bestandteil der XML-Datei sein.

Die vollständige DTD zu dem Partybeispiel sieht folgendermaßen aus:

Listing 13.3   party.dtd
<!ELEMENT party (gast)*>
<!ATTLIST party datum CDATA #REQUIRED>

<!ELEMENT gast (getraenk*, zustand?)>
<!ATTLIST gast name CDATA #REQUIRED>

<!ELEMENT getraenk (#PCDATA)>

<!ELEMENT zustand EMPTY>
<!ATTLIST zustand ledig CDATA #IMPLIED nuechtern CDATA #IMPLIED>

Durch diese DTD wird die Struktur aller XML-Dateien, die eine Party nach dieser Struktur beschreiben möchten, festgelegt.


Galileo Computing

13.2.3 Schema, eine Alternative zu DTD  downtop

Ein anderes Verfahren, um die Struktur von XML-Dateien zu beschreiben, ist Schema. Es ermöglicht eine Strukturbeschreibung wie DTD in Form einer XML-Datei. Dadurch wird das Parsen der Schema-Datei vereinfacht, da die Strukturbeschreibung und die Daten vom gleichen Dateityp sind. Durch Schema können die Datentypen der Elemente und Attribute einer XML-Datei viel detaillierter beschrieben werden. Die üblichen Datentypen wie string, integer und double der gängigen Programmiersprachen sind bereits vorhanden. Weitere Datentypen wie date und duration sind auch vorhanden. Zusätzlich ist es möglich, eigene Datentypen zu definieren. Mit Schema kann zum Beispiel festgelegt werden, ob ein Element nur Ganzzahlwerte, Wahrheitswerte oder Fließkommawerte hat.

Die Vorteile sind eine genauere Beschreibung der Daten, die in einer XML-Datei dargestellt werden. Dadurch wird die Strukturbeschreibung aufwendiger als mit einer DTD. Wenn eine Struktur sehr detailliert beschrieben oder diese Struktur für sehr viele Dokumente verwendet werden soll, ist der Mehraufwand gerechtfertigt.

Moderne Parser unterstützen die Verwendung von Schema, allerdings ist Schema noch kein Bestandteil der Spezifikation von XML 1.0. Grundsätzlich kann mit Schema, genau wie mit einer DTD, die Gültigkeit einer XML-Datei überprüft werden.

Hier ist ein Beispiel für ein Schema, das die Struktur der Datei party.xml beschreibt:

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

   <xsd:complexType name="partyType">
      <xsd:sequence>
         <xsd:element name="gast" type="gastType" />
      </xsd:sequence>
      <xsd:attribute name="datum" type="datumType" />
   </xsd:complexType>

   <xsd:complexType name="gastType">
      <xsd:sequence>
         <xsd:element name="getraenk" type="xsd:string" />
         <xsd:element name="zustand" type="zustandType" />
      </xsd:sequence>
   </xsd:complexType>

   <xsd:simpleType name="datumType">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="[0-3][0-9].[0-1][0-9].[0-9][0-9] " />
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:complexType name="zustandType">
      <xsd:complexContent>
         <xsd:restriction base="xsd:anyType">
            <xsd:attribute name="nuechtern" type="xsd:boolean" 
/>
            <xsd:attribute name="ledig" type="xsd:boolean" 
/>
         </xsd:restriction>
      </xsd:complexContent>
   </xsd:complexType>

</xsd:schema>

In diesem Beispiel werden die Typen String für die Beschreibung des Elements <getraenk>, und boolean für die Beschreibung des Elements <ledig> verwendet. Die Typen gastType und datumType sind selbstdefinierte Typen. Für das Datum wird ein sehr einfacher regulärer Ausdruck verwendet, der die Form eines Datums beschreibt. Ein Datum besteht aus drei Gruppen mit je zwei Ziffern, die durch Punkte getrennt sind. Die erste Ziffer der ersten Zifferngruppe muss aus dem Zahlenbereich 0 bis 3 stammen.

Bei den Typen datumType und zustandType wird auf vorhandene Typen zurückgegriffen, um diese einzuschränken. Beim datumType wird der Typ String auf eine Form von Datum eingeschränkt. Beim zustandType wird der Type anyType auf die beiden Attribute nuechtern und ledig eingeschränkt. Dadurch wird ein neuer Typ erzeugt, der keinen Text als Inhalt enthält, sondern nur die beiden Attribute nuechtern und ledig. Der Wert der beiden Attribute ist ein Wahrheitswert.

Simple und komplexe Typen

In Schema wird zwischen simplen und komplexen Typen unterschieden. Simple Typen sind alle Typen, die keine Unterelemente und keine Attribute, sondern nur textbasierten Inhalt haben.

Beispiel Das Element <getraenk> besteht nur aus einer Zeichenkette.
<xsd:element name="getraenk" 
type="xsd:string" />

Komplexe Typen können neben textbasiertem Inhalt auch noch Unterelemente und Attribute haben.

Beispiel Das Element <gast> hat den Typ gastType und die Unterelemente <getraenk> und <zustand>.
<xsd:element name="gast" type="gastType" />

<xsd:complexType name="gastType">
  <xsd:sequence>
    <xsd:element name="getraenk" type="xsd:string" />
    <xsd:element name="zustand" type="zustandType" />
  </xsd:sequence>
</xsd:complexType>

Simple und komplexe Typen können andere Typen einschränken. Komplexe Typen können zusätzlich noch andere Typen erweitern. Beim Erweitern ist es möglich, mehrere Typen miteinander zu kombinieren, um einen neuen Typ mit Eigenschaften verschiedener Typen zu erschaffen.

Das vorherige Beispiel kann nur einen kleinen Einblick in die Möglichkeiten von Schema geben. Umfangreiche Dokumentation ist unter der URL http://www.w3.org/XML/Schema vorhanden. Dort gibt es drei verschiedene Dokumentationen zu Schema:

gp  Schema Part0 Primer: Gut lesbares Tutorial mit vielen Beispielen.
gp  Schema Part1 Structures: Genaue Beschreibung der Struktur einer Schema-Datei.
gp  Schema Part2: Datatypes: Beschreibung der Datentypen die in Schema verwendet werden.

Der erste Teil bietet eine tiefe Einführung mit vielen Beispielen. Die beiden anderen Teile dienen als Referenzen für spezielle Fragestellungen.


Galileo Computing

13.2.4 Namensraum (Namespace)  downtop

Das Konzept Namensraum ist besonders wichtig, wenn

gp  XML-Daten nicht nur lokal mit einer Anwendung benutzt werden
gp  Daten ausgetauscht oder
gp  XML-Dateien kombiniert werden

Eine Überschneidung der Namen der Tags, die in den einzelnen XML-Dateien verwendet werden, lässt sich nicht verhindern. Daher ist es möglich, einer XML-Datei einen oder mehrere Namensräume zuzuordnen.

Der Namensraum ist eine Verknüpfung zwischen einem Präfix, das vor den Element-namen steht, und einer URI. Ein Namensraum wird als Attribut an ein Element (typischerweise das Wurzelelement) gebunden und kann dann von allen Elementen verwendet werden. Das Attribut hat die Form

xmlns:Präfix="URI"

Dem Element, dass den Namensraum deklariert, wird das Präfix vorangestellt und hat die Form

<Präfix:lokaler Name xmlns:Präfix="URI">

Das Präfix ist ein frei wählbares Kürzel, das den Namensraum benennt. Dieses Kürzel wird dem Namen der Elemente, die zu diesem Namensraum gehören, vorangestellt. Der Name eines Elements des Namensraums Präfix hat die Form

<Präfix:lokaler Name>...</Präfix:lokaler 
Name>

Angenommen, wir möchten für unsere Party das Namensraumpräfix geburtstag verwenden. Die URI für diesen Namensraum ist http://www.geburtstag.de. Der Namensraum wird in dem Wurzelelement party deklariert. Das Präfix wird jedem Element zugeordnet.

<geburtstag:party xmlns:geburtstag="http://www.geburtstag.de" 
geburtstag:datum="31.12.01">
<geburtstag:gast geburtstag:name="Albert Angsthase">
</geburtstag:gast>
</ geburtstag:party>

Eine weitere wichtige Anwendung von Namensräumen ist es, Tags bestimmter Technologien zu kennzeichnen. Für die XML-Technologien, wie Schema, werden feste Namensräume vergeben.

Beispiel Namensraumdefinition für Schema
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Eine Anwendung, die XML-Dateien verarbeitet, kann an Hand des Namensraums erkennen, welche Technologie verwendet wird. Dabei ist nicht das Präfix, sondern die URI für die Identifikation des Namensraums entscheidend. Für XML-Dateien, die eine Strukturbeschreibung in Form eines Schemas definieren, ist es üblich, das Präfix xsd zu verwenden. Es ist aber jedes andere Präfix möglich, wenn die URI auf die Adresse http://www.w3.org/2001/XMLSchema verweist. Diese Adresse muss nicht unbedingt existieren, und eine Anwendung kann auch nicht erwarten, dass sich hinter dieser Adresse eine konkrete HTML-Seite verbirgt. Die URI dient nur zur Identifikation des Namensraums für eine XML-Datei.


Galileo Computing

13.2.5 XML-Applikationen  downtop

Eine XML-Applikation ist eine festgelegte Auswahl von XML-Elementen und einem Namensraum. XHTML ist eine XML-Applikation, bei der die XML-Elemente die HTML-Elemente zur Beschreibung von Webseiten sind. Durch die Beschränkung auf eine bestimmte Menge von Elementen ist es möglich, diese XML-Dateien für bestimmte Anwendungen zu nutzen. Der Namensraum legt fest, zu welcher Applikation die einzelnen XML-Elemente gehören. Dadurch können verschiedene XML-Applikationen miteinander kombiniert werden.

Die bekannteste XML-Applikation ist XHTML. Die Menge möglicher Tags werden durch mehrere DTDs beschrieben. Für XHTML 1.0 gibt es die DTDs:

gp  XHTML1-strict.dtd: Minimale Menge von HTML-Tags
gp  XHTML1-transitional.dtd: Die gängigsten HTML-Tags
gp  XHTML1-frameset.dtd: HTML-Tags zur Beschreibung von Frames

Der Standard XHTML 1.1 geht noch einen Schritt weiter und bietet modulare DTD’s an. Hier kann sehr genau differenziert werden, welche HTML-Tags für die eigene XML-Applikation gültig sind. Dadurch ist es sehr einfach möglich, XHTML-Elemente mit eigenen XML-Elementen zu kombinieren. Durch die Verwendung von Namensräumen können die XHTML-Tags und die XML-Tags zur Datenbeschreibung unterschieden werden.


Galileo Computing

13.3 Die Java APIs für XML  downtop

Für XML basierte Daten gibt es zwei wohldefinierte Verarbeitungsverfahren: DOM und SAX. Während DOM das gesamte Dokument in einer internen Struktur einliest und bereitstellt, verfolgt SAX einen ereignisorientierten Ansatz. Das Dokument wird in Stücken geladen und immer dann, wenn ein angemeldetes Element beim Parser vorbeikommt, meldet er dies in Form eines Ereignisses, das für die Verarbeitung abgefangen werden kann.


Galileo Computing

13.3.1 Das Document Object Model (DOM)  downtop

DOM ist eine Entwicklung vom W3C und wird von vielen Programmiersprachen unterstützt. Das Standard DOM ist so konzipiert, dass er unabhängig von einer Programmiersprache ist und eine strikte Hierarchie erzeugt. DOM definiert eine Reihe von Schnittstellen, die durch konkrete Programmiersprachen implementiert werden.


Galileo Computing

13.3.2 Simple API for XML Parsing (SAX)  downtop

SAX ist zum schnellen Verarbeiten der Daten von David Megginson als Public-Domain entworfen worden. SAX ist im Gegensatz zu DOM nicht so speicherhungrig, weil das XML-Dokument nicht vollständig im Speicher abgelegt ist, und daher auch für kleine Probleme geeignet. Da SAX auf einem Ereignismodell basiert, wird es wie ein Datenstrom gelesen und für erkannte Elemente ein Ereignis ausgelöst. Dies ist aber mit dem Nachteil verbunden, dass wahlfreier Zugriff auf ein einzelnes Element nicht so ohne weiteres möglich ist.

Ob in eigenen Programmen DOM oder SAX eingesetzt wird, ist von Fall zu Fall unterschiedlich. In vielen Fällen ist dies auch Geschmacksache, doch ärgerlicherweise unterscheidet sich das Programmiermodell, sodass eine Umstellung nicht so angenehm ist. Wünschenswert ist eine API, die einen unabhängigen Zugriff auf XML-Daten anbietet.


Galileo Computing

13.3.3 Java Document Object Model (JDOM)  downtop

JDOM ist eine einfache Möglichkeit, XML-Dokumente leicht und effizient mit einer schönen Java-API zu nutzen. Im Gegensatz zu SAX und DOM, die unabhängig von einer Programmiersprache sind, wurde JDOM speziell für die Programmiersprache Java entwickelt. Durch die Optimierung der API auf Java ist eine wesentlich bessere Performance und eine bessere Speichernutzung als bei DOM möglich.


Galileo Computing

13.4 XML-Dateien mit JDOM verarbeiten  downtop

Über JDOM lassen sich die XML-formatierten Dateien einlesen, manipulieren und dann wieder schreiben. Mit einfachen Aufrufen lässt sich ein Dokument im Speicher erstellen. Zur internen JDOM-Repräsentation werden dazu einige Java-typische Features verwendet, beispielsweise die Collection-API zur Speicherung, Reflection oder schwache Referenzen. Die Nutzung der Collection-API ist ein Vorteil, der unter dem herkömmlichen DOM nicht zum Vorschein kam. Mit JDOM können mit dem new-Operator auch einfach Elemente und Attribute erzeugt werden. Es gibt spezielle Klassen für das Dokument, Elemente, Attribute und Kommentare. Es sind keine Fabrik-Schnittstellen, die konfiguriert werden müssen, sondern alles wird direkt erzeugt.

Die Dokumentenmodelle DOM oder SAX liegen eine Ebene unter JDOM; doch JDOM ist der gemeinsame Aufbau, der die Vorteile von beiden Technologien vereinigt. Mit einem SAX-Parser kann eine Java-spezifische Baumstruktur im Speicher erzeugt werden. Die Bibliothek bietet daher eine neutrale Schnittstelle für diverse Parser, um die Verarbeitung der XML-Daten so unabhängig wie möglich von den Implementierungen zu machen. JDOM unterstützt dabei aktuelle Standards wie DOM Level 2, SAX 2.0 oder XML-Schema. Wenn es nötig wird, DOM oder SAX zu unterstützen, dann bieten Schnittstellen diesen Einstieg an.

Mit JDOM wird auch eine interne Datenstruktur der XML-Datei erzeugt. Dadurch kann jederzeit auf alle Element der XML-Datei zugegriffen werden. Dies ist viel effizienter, als bei einer Implementierung von DOM, da Java-spezifische Datenstrukturen verwendet werden. JDOM ist eine echte Alternative zu DOM. Eine Zusammenarbeit von JDOM und SAX ist auch möglich, weil JDOM in der Lage ist, als Ausgabe SAX-Ereignisse auszulösen. Diese können mit SAX-basierten Tools weiter verarbeitet werden. Dadurch kann JDOM auch sehr gut in Umgebungen eingesetzt werden, in denen weitere Tools zur Verarbeitung von XML genutzt werden.


Galileo Computing

13.4.1 JDOM beziehen  downtop

JDOM ist freie Software, die auf der Apache-Lizenz beruht. Das heißt, dass JDOM auch in kommerziellen Produkten eingesetzt werden kann, die dann nicht automatisch Open Source sein müssen. Die Entwicklung von JDOM geht von Brett McLaughlin und Jason Hunter aus. Brett und Jason sind zwei bekannte Java-Buch Autoren. Brett hat ein XML-Buch und Jason ein Servlet-Buch beim O’Reilly-Verlag herausgegeben. Die Homepage der Software mit Dokumentation und Mailinglisten liegt auf http://www.jdom.org. Von dort sollten wir uns für unsere folgende Arbeit das Archiv mit den Bibliotheken und die Hilfe besorgen. Es gibt immer einen Meilenstein und eine nächtliche Version. (Der Meilenstein ist eine gut funktionierende Version, und der nächtliche Build ist nur für die Bastler.) JDOM ist im Standardisierungsprozess der Firma Sun.


Galileo Computing

13.4.2 Paketübersicht  downtop

JDOM besteht aus fünf Paketen mit den Klassen zur Repräsentation des Dokuments, mit Klassen zum Einlesen und Ausgeben.

Das Paket org.jdom

In diesem Paket sind alle Klasse zusammengefasst, damit ein XML-Dokument im Speicher repräsentiert werden kann. Dazu gehören zum Beispiel die Klassen Attribute, Comment, CDATA für Text, DocType, Document, Element, Entity und ProcessingInstruction. Ein Dokument-Objekt hat ein Wurzelelement, eventuell Kommentare, einen DocType und ProcessingInstructions.

Das Paket org.jdom.output und org.jdom.input

In den beiden Paketen liegen die Klassen, die XML-Dateien lesen und schreiben können. XMLOutputter übernimmt die interne Repräsentation und erzeugt eine XML-Ausgabe in einen PrintWriter. Daneben werden die unterschiedlichen Verarbeitungsstrategien DOM und SAX durch die Ausgabeklassen SAXOutputter und DOMOutputter berücksichtigt. SAXOutputter nimmt einen JDOM-Baum und erzeugt benutzerdefinierte SAX2-Ereignisse. Der SAXOutputter ist eine sehr einfache Klasse und bietet lediglich eine output(Document)-Methode an. Mit DOMOutputter wird aus dem internen Baum ein DOM-Baum erstellt. SAXBuilder ist schneller und speicherschonender. Ein DOMBuilder wird meistens nur dann benutzt, wenn ein DOM-Baum weiterverarbeitet werden soll.

Ein Builder nimmt Daten in verschiedenen Formaten entgegen und erzeugt daraus ein JDOM-Dokument-Objekt. Das ist bei JDOM der wirkliche Verdienst, dass unabhängig von der Eingabe ein API-Set zur Verfügung steht. Die verschiedenen DOM-Implementierungen unterscheiden sich an manchen Stellen. Die Schnittstelle Builder wird von allen einlesenden Klassen implementiert. Im Input-Paket befinden sich dafür die Klassen DOMBuilder, die einen JDOM Baum mit DOM erzeugt, und SAXBuilder, die dafür SAX verwendet. Beide Klassen basieren auf der abstrakten Oberklasse AbstractBuilder, die Builder implementiert und drei build()-Funktionen angibt. Damit kann das Dokument aus einer Datei, einem Stream oder einer URL erzeugt werden. Nach dem Einlesen sind die Daten unabhängig von dem konkreten Parser des Herstellers, und sie können weiterverarbeitet werden.

Im org.jdom.contrib-Package gibt es noch einige Erweiterungen für JDOM. Eine bemerkenswerte Erweiterung ist der ResultSetBuilder. Diese Klasse ermöglicht das Erstellen einer JDOM-Datenstruktur an Hand eines java.sql.ResultSet. Dadurch ist eine Brücke zwischen Datenbanken und XML sehr einfach zu realisieren. Diese und noch viele weitere nützliche Erweiterungen sind nicht in der JDOM-Standarddistribution enthalten, sondern können unter der Adresse http://cvs.jdom.org/cgi-bin/viewcvs.cgi/jdom-contrib gefunden werden.

Das Paket org.jdom.transform

Mit diesem Paket wird das JAXP TRaX Modell in JDOM integriert. Dies ermöglicht JDOM die Unterstützung für XSLT-Transformationen von XML-Dokumenten. Das Paket enthält die beiden Klassen JDOMResult und JDOMSource. Die Klasse JDOMSource ist eine Wrapper-Klasse, die ein JDOM- Dokument als Parameter nimmt und diesen als Eingabe für das JAXP TRaX Modell bereitstellt. Die Klasse JDOMResult enthält das Ergebnis der Transformation als JDOM-Dokument. Die beiden Klassen haben nur wenige Methoden und in der API sind Beispiele für die Benutzung dieser Klassen angegeben.

Das Paket org.jdom.adapters

Klassen dieses Pakets implementieren die Schnittstelle DOMAdapter. Sie sind von AbstractDOM Adapter abgeleitet und erlauben JDOM existierende DOM-Implementierungen zu nutzen. Ein konkreter Adapter ummantelt die Implementierung und gibt ein Dokument-Objekt zurück. Es existieren dafür die Klassen OracleV1DOMAdapter, OracleV2DOMAdapter für Oracle–Version 1 und 2 DOM-Parser, ProjectXDOMAdapter (Projekt X DOM-Parser von Sun), XercesDOMAdapter (DOM-Parser von Apache Xerces), CrimsonDOMAdapter (DOM-Parser von SUN) und XML4JDOMAdapter für einen IBM XML4J Parser. Jeder Parser, der die Schnittstelle org.xml.sax.XMLReader oder die Schnittstelle org.jdom.adapters.DOMBuilder implementiert, kann als Parser für JDOM verwendet werden. Es ist daher auch möglich, eigene Implementierungen von Parsern zu verwenden. Die Implementierung nutzt als Standard den Xerces Parser von Apache.


Galileo Computing

13.4.3 Die Document-Klasse  downtop

Dokumente werden bei JDOM über die Klasse Document verwaltet. Ein Dokument besteht aus einem DocType, ProcessingInstructions, einem Wurzelelement und Kommentaren. Die Klasse Document gibt es auch in der Standardschnittstelle für das DOM. Falls sowohl JDOM als auch DOM verwendet werden, muss für die Klasse Document der voll qualifizierte Klassenname mit vollständiger Angabe der Pakete verwendet werden, weil sonst nicht klar ist, welche Document-Klasse verwendet wird.

Ein Document im Speicher erstellen

Um ein Document-Objekt zu erzeugen, bietet die Klasse drei Konstruktoren an. Über einen Standardkonstruktor erzeugen wir ein leeres Dokument. Dies können wir später bearbeiten, indem wir zum Beispiel Elemente (Objekt vom Typ Element), Entitäten oder Kommentare einfügen. Ein neues Dokument mit einem Element erhalten wir über einen Konstruktur, dem wir ein Wurzelelement angeben. Jedes XML-Dokument hat ein Wurzelelement.

Beispiel Das Wurzelement für ein XML-Dokument
<party>
</party >

erzeugt die Zeilen

Document doc = new Document( 
new Element("party") );


Galileo Computing

13.4.4 Eingaben aus der Datei lesen  downtop

Ein zweiter Weg ein JDOM-Dokument anzulegen, führt über einen Eingabestrom oder eine Datei. Dafür brauchen wir einen Builder, zum Beispiel den SAXBuilder (den wir bevorzugen wollen).

SAXBuilder builder = new SAXBuilder();
Document doc = builder.build( dateiname );

Die Klasse Document kann selbst nicht aus anderen Quellen Daten entnehmen. Es sind immer die Builder, die Document-Objekte liefern. Es ist ebenso möglich, ein JDOM-Dokument mit Hilfe des DOM Parsers DOMBuilder zu erzeugen. Als Parameter im Konstruktor kann der zu verwendende Parser und ein boolean-Wert, der die Validierung auf wohldefinierten XML-Code einschaltet, angegeben werden.

Tipp Wenn ein DOM nicht unbedingt benötigt wird, ist es sinnvoll, ein JDOM-Dokument stets mit dem SAX-Parser zu erzeugen. Dies schont die Ressourcen und geht viel schneller, da nicht eine spezielle Datenstruktur für den DOM-Baum erzeugt werden muss. Das Ergebnis ist in beiden Fällen ein JDOM-Dokument, das die XML-Datei in einer baumähnlichen Struktur abbildet.


Galileo Computing

13.4.5 Das Dokument als XML-Datei ausgeben  downtop

Mit der Hilfsklasse XMLOutputter lässt sich der interne JDOM-Baum leicht als XML-Datenstrom ausgeben. Mit diesem Formatierer werden die Daten mit Einrückungen geschrieben. Jeder Eintrag kommt in eine einzelne Zeile. Durch folgende beiden Zeilen wird ein JDOM-Dokument über die Konsole ausgegeben:

XMLOutputter out = new XMLOutputter();
out.output( doc, System.out );

Über dem Konstruktor kann die Einrückung bestimmt werden.

XMLOutputter out = new XMLOutputter( "  ", false 
);
Out.output( doc, System.out );

Diese Anweisungen erzeugen eine kompakte Ausgabe ohne Einrückung und Trennzeilen.


Galileo Computing

13.4.6 Der Dokumententyp  downtop

Ein XML-Dokument beschreibt in seinem Dokumenttyp den Typ der Datei und besitzt oft einen Verweis auf die beschreibende DTD.

Beispiel Ein gültiger Dokumententyp für XHTML-Dateien hat folgendes Format:
<!DOCTYPE html PUBLIC
  "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Bearbeiten wir dies über JDOM, so liefert die Methode getDocType() vom Dokument-Objekt ein DocType-Objekt, welches wir nach den IDs fragen können. Über setDocType() kann der veränderte Dokumententyp neu zugewiesen werden.

class org.jdom.Document

gp  DocType getDocType()
Liefert das zugehörige DocType-Objekt oder null, wenn keines existiert.
gp  Document setDocType( DocType docType )
Setzt ein neues DocType-Objekt für das Dokument.
Beispiel Wir erfragen vom Dokument den Elementnamen, die öffentliche ID und die System-ID.
DocType docType = doc.getDocType();
System.out.println( "Element: " + docType.getElementName() 
);
System.out.println( "Public ID: " + docType.getPublicID() 
);
System.out.println( "System ID: " + docType.getSystemID() 
);

Zu den Methoden getPublicID() und getSystemID() gibt es entsprechende Setze-Methoden, nicht aber für den Elementnamen, dieser kann nachträglich nicht mehr modifiziert werden. Wir müssten dann ein neues DocTyp-Objekt anlegen. Es gibt mehreren Varianten von Konstruktoren, mit denen gesteuert werden kann, welche Einträge gesetzt werden.

Beispiel Wir legen ein neues DocType-Objekt an und weisen es einem Dokument doc zu.
DocType doctype =  new DocType( "html", "-//W3C...", 
"http://..." ) ;
doc.setDocType( doctype  );


Galileo Computing

13.4.7 Elemente  downtop

Jedes Dokument besteht aus einem Wurzelelement. Wir haben schon gesehen, dass dies durch die Klasse Element abgebildet wird. Mit dem Wurzelelement gelingt der Zugriff auf die anderen Elemente des Dokumentenbaums.

Wurzelelement

Im Folgenden wird die Beispieldatei party.xml verwendet, um die Funktionen von JDOM vorzustellen. Durch das Erzeugen eines leeren JDOM-Dokuments und den Methoden zum Erzeugen von Elementen und Attributen, kann diese Datei auch leicht mit JDOM erzeugt werden.

Beispiel Die Datei party.xml hat folgendes Format:
party.xml
<party datum=“31.12.01“>
<gast name="Albert Angsthase">
<getraenk>Wein</getraenk>
<getraenk>Bier</getraenk>
<zustand ledig=“true“ nuechtern=“false“/>
</gast>
<gast name="Martina Mutig">
<getraenk>Apfelsaft</getraenk>
<zustand ledig=“true“ nuechtern=“true“/>
</gast>
<gast name="Zacharias Zottelig"></gast>
</party>

Um an das Wurzelelement <party> zu kommen, und von dort aus weitere Elemente oder Attribute auslesen zu können, schreiben wir:

//Erzeugen eines JDOM-Dokuments anhand der Datei 
party.xml
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build( "party.xml" );

//Lesen des Wurzelelements des JDOM-Dokuments doc
Element party = doc.getRootElement();
class org.jdom.Document

gp  Element getRootElement()
Gibt das Root-Element zurück oder null, falls kein Root-Element vorhanden ist.
gp  boolean isRootElement()
Rückgabe eine Wahrheitswerts, der ausdrückt, ob das Element die Wurzel der JDOM-Datenstruktur ist.

Durch die oben gezeigten Anweisungen wird aus der XML-Datei party.xml eine JDOM-Datenstruktur im Speicher erzeugt. Um mit dem Inhalt der XML-Datei arbeiten zu können, ist der Zugriff auf die einzelnen Elemente notwendig. Durch die Methode getRoot Element() wird das Wurzelelement der XML-Datei zurückgegeben. Dieses Element ist der Ausgangspunkt für die weitere Verarbeitung der Datei.

Zugriff auf Elemente

Um ein bestimmtes Element zu erhalten, gibt es die Methode getChild(String name). Mit dieser Methode wird das nächste Unterelement des Elements, das diesen Namen trägt, zurückgegeben. Eine Liste mit allen Elementen liefert die Methode getChildren(). Sie gibt eine Liste mit allen Elementen mit diesem Namen zurück:

org.jdom.Element

gp  Element getChild( String name )
Rückgabe des ersten untergeordneten Elements mit dem lokalen Namen name, das keinem Namensraum zugeordnet ist.
gp  Element getChild( String name, Namespace ns )
Rückgabe des ersten untergeordneten Elements mit dem lokalen Namen name, das dem Namensraum ns zugeordnet ist.
gp  List getChildren()
Rückgabe einer Liste der Elemente, die diesem Element direkt untergeordnet sind. Falls keine Elemente existieren wird eine leere Liste zurückgegeben. Änderungen an der Liste spiegeln sich auch in der JDOM-Datenstruktur wieder.
gp  List getChildren( String name )
Rückgabe einer Liste der Elemente mit dem Namen name, die diesem Element direkt untergeordnet sind. Falls keine Elemente existieren wird eine leere Liste zurückgegeben. Änderungen an der Liste spiegeln sich auch in der JDOM-Datenstruktur wieder.
gp  List getChildren( String name, Namespace ns )
Rückgabe einer Liste der Elemente mit dem Namen name, die diesem Namensraum zugeordnet sind, die diesem Element direkt untergeordnet sind. Falls keine Elemente existieren wird eine leere Liste zurückgegeben. Änderungen an der Liste spiegeln sich auch in der JDOM-Datenstruktur wieder.
gp  boolean hasChildren()
Rückgabe eines boolean-Werts, der ausdrückt, ob Elemente untergeordnet sind oder nicht.
Beispiel Wenn wir den ersten Gast auf der Party bekommen möchten, schreiben wir:
Element party = doc.getRootElement();
Element albert = party.
getChild( "gast" );

Wenn wir wissen wollen, was Albert trinkt:

Element albertGetraenk = albert.getChild( 
"getraenk" );

Es ist aber auch möglich über das Wurzelelement auf das Getränk des ersten Gastes zuzugreifen:

Element albertGetraenk = party.getChild( "gast" 
).getChild( "getraenk" );

Falls wir eine Gästeliste der Party haben wollen, schreiben wir:

List gaeste = party.getChildren( 
"gast" );

Diese Liste enthält alle Elemente der Form <gast ...> ... </gast>, die direkt unter dem Element <party> liegen. Diese Liste ist eine Java-Collection und kann mit den Anweisungen für Collections weiter verarbeitet werden. Dadurch ist es möglich, mit einem Iterator die Liste zu durchlaufen, um einzelne Elemente zu verarbeiten.



Galileo Computing

13.4.8 Zugriff auf Elementinhalte  downtop

Von Beginn eines Elements bis zu dessen Ende treffen wir auf drei unterschiedliche Informationen:

gp  Es können weitere Elemente folgen. Im oberen Beispiel folgt in <gast> noch ein Element <getraenk>.
gp  Das Element enthält Text (wie das Element <getraenk>).
gp  Zusätzlich kann ein Element auch Attribute beinhalten. Dies haben wir auch beim Element <gast> gesehen, das als Attribut den Namen des Gasts enthält. Der Inhalt von Attributen ist immer Text.

Für diese Aufgaben bietet die Element-Klasse unterschiedliche Anfrage- und Setze-Methoden. Wir wollen mit dem Einfachsten, dem Zugriff auf den Textinhalt eines Elements, beginnen.

Elementinhalte auslesen und setzen

Betrachten wir das Element, dessen Inhalt wir auslesen wollen, so nutzen wir dazu die Methode getText().

<getraenk>Wein</getraenk>

Sie liefert einen String, sofern eine String-Repräsentation des Inhalts erlaubt ist. Falls das Element keinen Text oder nur Unterelemente besitzt, so ist der Rückgabewert ein Leerstring.

Um an das erste Getränk von Albert zu kommen, schreiben wir:

Element party = doc.getRootElement();
Element albertGetraenk = party.getChild( "gast" ).getChild( "getraenk" );
String getraenk = albertGetraenk.
getText();
class org.jdom.Element

gp  String getText()
Rückgabe des Inhalts des Elements. Dies beinhaltet alle Leerzeichen und CDATA-Sektionen. Falls der Elementinhalt nicht zurückgeben werden kann, wird der leere String zurückgeben.
gp  String getTextNormalize()
Verhält sich wie wie getText(). Leerzeichen am Anfang und am Ende des Strings werden entfernt. Leerzeichen innerhalb des Strings werden auf ein Leerzeichen normalisiert. Falls der Text nur aus Leerzeichen besteht, wird der leere String zurückgegeben.
gp  String getTextTrim()
Verhält sich wie getTextNormalize(). Leerzeichen innerhalb des String bleiben erhalten.

Für die Methode getText() muss das Element vorliegen, dessen Inhalt gelesen werden soll. Mit der Methode getChildText() kann auch direkt der Inhalt eines untergeordneten Elements ermittelt werden. Das folgende Beispiel liest den Text des ersten untergeordneten Elements mit dem Namen getränk. Das übergeordnete Element von Getränk ist albert:

Element albert = party.getChild( 
"gast" );
String getraenk = albert.
getChildText( "getraenk" );

In der Implementierung der Methode getChildText() sind die Methoden getChild() und getText() zusammen gefasst.

class org.jdom.Element

gp  String getChildText( String name )
Rückgabe des Inhalts des Elements mit dem Namen name. Falls der Inhalt kein Text ist wird ein leeren String zurückgegeben. Falls das Element nicht existiert, wird null zurückgegeben.
gp  String getChildText( String name, Namespace ns )
Verhält sich wie getChildText(String) im Namensraum ns.
gp  String getChildTextTrim( String name )
Verhält sich wie getChildText(String). Leerzeichen am Anfang und am Ende des String werden entfernt. Leerzeichen innerhalb des String bleiben erhalten.
gp  String getChildTextTrim( String name, Namespace ns )
Verhält sich wie getChildTextTrim(String) im Namensraum ns.
gp  String getName()
Rückgabe des lokalen Namens des Elements ohne Namensraum-Präfix.
gp  Namespace getNamespace()
Rückgabe des Namensraums oder einen leeren String falls diesem Element kein Namensraum zugeordnet ist.
gp  Namespace getNamespace( String prefix )
Rückgabe des Namensraums des Elements mit diesem Präfix. Dies beinhaltet das Hochlaufen in der Hierarchie des JDOM-Dokuments. Falls kein Namensraum gefunden wird, gibt diese Methode null zurück.
gp  String getNamespacePrefix()
Rückgabe des Namensraum-Präfix. Falls kein Namensraum-Präfix existiert, wird ein Leerstring zurückgegeben.
gp  String getNamespaceURI()
Rückgabe der Namensraum URI, die dem Präfix dieses Elements zugeordnet ist, oder des Standard-Namensraums. Falls keine URI gefunden werden kann, wird ein leerer String zurückgegeben.

Galileo Computing

13.4.9 Liste mit Unterelementen erzeugen  downtop

Mit den oben beschriebenen Methoden war es bislang immer nur möglich, das erste untergeordnete Element mit einem bestimmten Namen zu lesen. Um gezielt nach bestimmten Element zu suchen, ist es notwendig, die untergeordneten Elemente in eine Liste zu übertragen. Mit der Methode getContent() wird eine Liste mit allen Elementen und Unterelementen erzeugt. Diese Liste enthält Referenzen der Elemente aus der JDOM-Datenstruktur.

Beispiel Hole eine Liste aller Informationen der Party.
Element party = doc.getRootElement();
List partyInfo = party.
getContent();

Mit einem Iterator kann diese Liste durchlaufen werden.

Beispiel Einen Iterator aus der Liste partyInfo erzeugen und die Liste durchlaufen.
Iterator partyIterator = partyInfo.iterator();
while ( partyIterator.hasNext() )
{
  System.out.println( partyIterator.next().toString() );
}

class org.jdom.Element

List getContent()


Dies liefert den vollständigen Inhalt eines Elements mit allen Unterelementen. Die Liste kann Objekte vom Typ String, Element, Comment, ProcessingInstruction und Entity enthalten. Falls keine Elemente vorhanden sind, wird eine leere Liste zurückgegeben.


Galileo Computing

13.4.10 Neue Elemente einfügen und ändern  downtop

Um neue Elemente zu erzeugen, bietet die Klasse Element unter anderem den Konstruktor Element(String) an. Es wird ein Element mit dem entsprechenden Namen erzeugt.

Beispiel Wir erzeugen eine Liste mit allen Unterelementen von albert, erzeugen ein neues Element und fügen dies in die Liste ein.
Element party = doc.getRootElement();
Element albert = party.getChild( "gast" );
List albertInfo = albert.getContent();
Element wasser = new Element( "getraenk" );
wasser.addContent( "Wasser" );

Um den Wert eines Elements zu ändern, gibt es die Methoden setText() und addContent(). Die Methode setText() hat allerdings die unangenehme Eigenschaft, alle Unterelemente zu entfernen. Die Methode addContent() fügt neuen Inhalt hinzu.

Wenn der Inhalt eines Elements ausgetauscht werden soll, muss der alte Inhalt entfernt, und der neue Inhalt mit addContent() hinzugefügt werden. Die Methode addContent() kann nicht nur Text, sondern jeden beliebigen Inhalt einfügen.

Beispiel Albert will in Zukunft keinen Wein mehr trinken, sondern nur noch Wasser und Bier.

Zuerst wird das erste Unterelement gelöscht

albert.removeChild( "getraenk" );

Ein neues Element Wasser wird erzeugt und mit Inhalt gefüllt

Element wasser = new Element( "getraenk" );
wasser.addContent( "Wasser" );

Das neue Element wird dem Element Albert untergeordnet.

albert.addContent( wasser );

Werfen wir erneut einen Blick auf unsere XML-Datei und entfernen das erste Element <getraenk>, das dem ersten Element <gast> untergeordnet ist.

<party datum=“31.12.01“>
<gast name="Albert Angsthase">
<getraenk>Wein</getraenk>
<getraenk>Bier</getraenk>
<zustand ledig=“true“ nuechtern=“false“/>
</gast>
<party>
Beispiel Die Funktion entfernt das Element <getraenk>.
Element party = doc.getRootElement();
Element albert = party.getChild( "gast" );

// Es werden nur die direkten Nachfolger durchsucht. Diese Funktion
// findet das Element <getraenk>Wein</getraenk> nicht.
party.removeChild("getraenk");

// Mit dieser Funktion wird das Element
// <getraenk>Wein</getraenk> gelöscht.
albert.removeChild("getraenk");

class org.jdom.Element

gp  Element( String name )
Dieser Konstruktor erzeugt ein Element mit dem Namen name, ohne Zuordnung zu einem Namensraum.
gp  Element( String name, Namespace namespace )
Dieser Konstruktor erzeugt ein Element mit dem Namen name und dem Namensraum namespace.
gp  Element( String name, String uri )
Dieser Konstruktor erzeugt ein neues Element mit dem lokalem Namen name und der URI des Namensraums, der zu dem Element ohne Präfix gehört.
gp  Element( String name, String prefix, String uri )
Dieser Konstruktor erzeugt ein neues Element mit dem lokalem Namen name, dem Namespräfix prefix und der URI des Namensraums.
Von diesen Konstruktoren ist in den Beispielen nur der Erste benutzt worden.
gp  boolean removeChild( String name )
Entfernt das erste gefundene Unterelement mit den Namen name das gefunden wird und keinem Namensraum zugeordnet ist. Es werden nur die direkten Nachfolger durchsucht.
gp  boolean removeChild( String name, Namespace ns)
Verhält sich wie removeChild(String name). Der Namensraum wird bei der Auswahl des Elements berücksichtigt.
gp  boolean removeChildren()
Entfernt alle untergeordneten Elemente.
gp  boolean removeChildren( String name )
Entfernt alle Unterelemente mit den Namen name die gefunden werden und keinem Namensraum zugeordnet sind. Es werden nur die direkten Nachfolger durchsucht.
gp  boolean removeChildren( String name, Namespace ns )
Wie removeChildren(String) im Namensraum ns.

Bei den folgenden Methoden wird als Rückgabewert das geänderte Element zurückgegeben:

gp  Element setText( String text )
Setzt den Inhalt des Elements. Alle anderen Inhalte und alle Unterelemente werden gelöscht.
gp  Element addContent( String text )
Ergänzt den Inhalt des Elements um den Text.
gp  Element addContent( Element element )
Ergänzt den Inhalt des Elements um das Element als Unterelement.
gp  Element addContent( ProcessingInstruction pi )
Ergänzt den Inhalt des Elements um die Processing Instruction pi.
gp  Element addContent( EntityRef entität )
Ergänzt den Inhalt des Elements um die Entität.
gp  Element addContent( CDATA cdata )
Ergänzt den Inhalt des Elements um eine CDATA-Sektion.
gp  Element addContent( Comment comment )
Ergänzt den Inhalt des Elements um einen Kommentar.
gp  Element getCopy( String name )
Erzeugt eine Kopie des Elements mit dem neuen Namen name, ohne Zuordnung zu einem Namensraum.
gp  Element getCopy(java.lang.String name, Namespace ns)
Erzeugt eine Kopie des Elements mit dem neuem Namen name und eine Zuordnung zu dem Namensraum ns.
gp  Document getDocument()
Liefert das Dokument dieses Elements, null, falls das Element keinem Dokument zugeordnet ist.

Galileo Computing

13.4.11 Attributinhalte lesen und ändern  downtop

Ein Element kann auch einen Attributwert enthalten. Dies ist der Wert, der direkt in dem Tag mit angegeben ist. Betrachten wir dazu folgendes Element:

<gast name="Albert Angsthase">

Das Element hat als Attribut name="Albert Angsthase". Dieser Wert kann mit der Methode getAttribute(String).getValue() der Klasse Element gelesen werden. In diesem Fall wird mit getAttribute( "name" ).getValue() der Attributwert von dem Element albert gelesen.

Beispiel Lesen des Namens
Element party = doc.getRootElement();
Element albert = party.getChild( "gast" );
String albertName = albert.getAttribute( 
"name" );

Genauso kann auch der Wert eines Attributs geschrieben werden. Dazu gibt es die Methoden setAttribute(String) der Klasse Attribute und addAttribute(Attribute) der Klasse Element. Es gibt eine Klasse Attribute, mit deren Hilfe das Modellieren von Attributen mit Java ermöglicht wird.

Wollen wir den Namen von Albert wissen schreiben wir:

String albertName = albert.getAttribute( "name" 
).getValue();

Wenn Martina wissen möchte, ob Albert noch ledig ist:

albert.getChild( "zustand" ).getAttribute( "ledig" 
).getValue();

Martina und Albert haben geheiratet, und Albert nimmt den Namen von Martina an:

albert.getAttribute( "name" ).setAttribute( "Albert 
Mutig" );

Seit der Hochzeit mit Albert trinkt Martina auch Wein. Also muss ein neues Element wein unter dem Element <gast name="Martina Mutig"> eingefügt werden. Zuerst erzeugen wir ein Element der Form <getraenk>Wein</getraenk>.

Element wein = new Element( "getraenk" );
wein.addContent( "Wein" );

Danach suchen wir Martina in der Gästeliste und fügen das Element <wein> ein:

// Liste aller Gäste
Iterator gaesteListe = party.getChildren( "gast" ).iterator(); 

 while ( gaesteListe.hasNext() )
{
  Element gast = (Element)gaesteListe.next();

  if ( "Martina Mutig".equals( gast.getAttribute( "name" ).getValue()) 
)
    gast.addContent( wein );
}

An diesem Beispiel wird deutlich, wie flexibel die Methode addContent(Inhalt) ist. Es zeigt ebenso, wie JDOM für Java, etwa durch die Implementierung der Schnittstelle List, optimiert wurde.

class org.jdom.Element

gp  Attribute getAttribute( String name )
Rückgabe des Attributs mit dem Namen name, das keinem Namensraum zugeordnet ist. Falls das Element kein Attribut mit dem Namen name hat, wird eine leere Liste zurückgegeben.
gp  Attribute getAttribute( String name, Namespace ns )
Wie getAttribute(String) in dem Namensraum ns.
gp  List getAttributes()
Rückgabe einer Liste aller Attribute eines Elements oder einer leeren Liste, falls das Element keine Attribute hat.
gp  String getAttributeValue( String name )
Rückgabe der Attribute mit dem Namen name, dem kein Namensraum zugeordnet ist. Es wird null zurückgegeben, falls keine Attribute mit diesem Namen existieren und der leere String, falls der Wert des Attributs leer ist.
gp  String getAttributeValue( String name, Namespace ns )
Verhält sich wie getAttributeValue(String) in dem Namensraum ns.
gp  Element setAttributes( List attributes )
Fügt alle Attribute der Liste dem Element zu. Alle vorhandenen Attribute werden entfernt. Das geänderte Element wird zurückgegeben.
gp  Element addAttribute(Attribute attribute)
Einfügen des Attributs attribute. Bereits vorhandene Attribute mit gleichem Namen und gleichem Namensraum werden ersetzt.
gp  Element addAttribute( String name, String value )
Einfügen des Attributs mit dem Namen name und dem Wert value. Um Attribute mit einem Namensraum hinzuzufügen, sollte man die Methode addAttribute(Attribute attribute) verwenden
class org.jdom.Attribute

gp  String getValue()
Rückgabe des Werts dieses Attributs.

Die folgenden Methoden versuchen eine Umwandlung in einen primitiven Datentyp. Falls eine Umwandlung nicht möglich ist, wird eine DataConversionException ausgelöst.

gp  getBooleanValue()
Gibt den Wert des Attributs als boolean zurück.
gp  double getDoubleValue()
Gibt den Wert des Attributs als double zurück.
gp  float getFloatValue()
Gibt den Wert des Attributs als float zurück.
gp  int getIntValue()
Gibt den Wert des Attributs als int zurück.
gp  long getLongValue()
Gibt den Wert des Attributs als long zurück.
gp  String getName()
Gibt den lokalen Namen des Attributs zurück. Falls der Name die Form [namespacePrefix]:[elementName] hat, wird [elementName] zurückgegeben. Wenn der Name kein Namensraum-Präfix hat, wird einfach nur der Name ausgegeben.
gp  Namespace getNamespace()
Gibt den Namensraum des Attributs zurück. Falls kein Namensraum vorhanden ist, wird das konstante Namensraum-Objekt NO_NAMESPACE zurückgegeben. Diese Konstante enthält ein Namensraum-Objekt mit dem leeren String als Namensraum.
gp  String getNamespacePrefix()
Gibt das Präfix des Namensraums zurück. Falls kein Namensraum zugeordnet ist, wird ein leerer String zurückgegeben.
gp  String getNamespaceURI()
Gibt die URI zurück, die zu dem Namensraum dieses Elements gehört. Falls kein Namensraum zugeordnet ist, wird ein leerer String zurückgegeben.
gp  Element getParent()
Das gibt das Element zurück, das dem Element dieses Attributs übergeordnet ist. Falls kein übergeordnetes Element vorhanden ist, wird null zurückgegeben.
gp  String getQualifiedName()
Rückgabe des qualifizierten Names des Attributs. Falls der Name die Form [namespacePrefix]:[elementName] hat, wird dies zurückgegeben. Ansonsten wird der lokale Name zurückgegeben.
gp  getSerializedForm()
Rückgabe des Attributs im XML-Format.
gp  Attribute setValue( String value )
Setzt den Wert dieses Attributs.

Galileo Computing

13.5 JAXP als Java-Schnittstelle zu XML  downtop

Nutzen Anwender einen XML-Parser, dann wird in der Regel ein Parser-Objekt konstruiert und die Methoden verwendet, damit der Parser seiner Arbeit nachgeht. Der Nachteil bei der direkten Nutzung ist die Abhängigkeit von bestimmten Klassen. Sun hat daher eine API mit dem Namen Java API for XML Parsing (JAXP) entworfen, sodass Entwickler zwischen verschiedenen XML-Parsern wählen können, ohne den eigentlichen Code zu verändern. Das ist das gleiche Prinzip wie bei den Datenbanktreibern. Mit JAXP können XML-Dokumente mit SAX 2.0 und DOM Level 2 bearbeitet und mit XSLT transformiert werden. Das Paket ist in Java 2 SDK 1.4 integriert. Für ältere Umgebungen kann es kostenlos von http: //java.sun.com/xml bezogen werden. Eine Dokumentation findet der Leser unter http: //java.sun.com/xml/jaxp-docs-1.0.1/docs/tutorial/index.html.

Um JAXP zu verwenden, sind zunächst einige Import-Anweisungen nötig. Dazu gehören zunächst einmal:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilder;

Die Ausnahmen stammen von org.xml.sax und org.w3c.dom:

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;

Jetzt kann ein Parser-Objekt mit Hilfe einer Fabrik-Methode erzeugt werden.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

document = builder.parse( new File("Datei") );

Die Parser sind selbstständig bei DocumentBuilderFactory angemeldet, und newInstance() liefert eine Unterklasse vom DocumentBuilder.

JDOM und JAXP ergänzen sich auch gegenseitig. Eine JDOM-Datenstruktur kann mit einem XSLT-Parser aus JAXP in ein anderes Dokument umgewandelt werden.


Galileo Computing

13.5.1 Einführung in XSLT  downtop

XSLT ist eine XML-Applikation mit der XML-Dateien in andere textbasierte Dateien umgewandelt werden können. Die Eingabedatei muss immer eine XML-Datei sein. Die Ausgabedatei kann ein beliebiges Format haben. Die XSLT-Datei, in der Umwandlungsregeln festgelegt werden, muss eine XML-Datei sein. Das bedeutet insbesondere, dass HTML-Tags in der XSLT-Datei die Regeln für XML-Elemente erfüllen müssen. Die XSLT-Datei, in der die Umwandlungsregeln beschrieben werden, ist eine XML-Datei.

In der XSLT-Datei werden die Elemente der XML-Quelldatei durch Templates ausgewählt und die Formatierung der Ausgabe beschrieben. Es ist möglich, die Formatierung von Bedingungen abhängig zu machen, Elemente in der Ausgabe auszublenden und die Reihenfolge der Ausgabe festzulegen.

Die Auswahl der Elemente wird durch XPath-Ausdrücke beschrieben. XPath ist eine XML-Applikation, in der eine XML-Datei als Baumstruktur abgebildet wird. Durch eine Notation, die an die Baumstruktur von Verzeichnisbäumen angelehnt ist, können einzelne Elemente oder ganze Unterbäume ausgewählt werden.

Für unser Beispiel ist hier eine einfache XSLT-Datei angegeben, die eine XML- Ausgabe aus der Datei party.xml erzeugt. Dabei wird in dem ersten Template ein HTML-Rumpf erzeugt, in den die Ausgabe der anderen Templates eingebettet werden. Mit dem Element party wird eine Überschrift für die Ausgabedatei erzeugt. Das Element <gast> wird in einem Template benutzt, um für jeden Gast eine persönliche Anrede zu erzeugen. Jedem Gast wird sein Lieblingsgetränk serviert. Zum Schluss beschreibt noch jeder kurz wie es ihm geht, und ob er noch ledig ist.

Hier ist die XSLT-Datei für die Umwandlung:

Listing 13.4   party.xsl
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Match auf das Root Element des XPath Baum -->
<!-- Ausgabe von HTML Kopf und Fuss -->
   <xsl:template match="/">
      <html>
         <head>
            <title>Wir machen eine Party</title>
         </head>

         <body>
<!-- An dieser Stelle wird tiefer in den XPath Baum -->
<!-- verzweigt. Die Ausgabe der anderen Templates   -->
<!-- wird an dieser Stelle eingefuegt               -->
            <xsl:apply-templates />
         </body>
      </html>
   </xsl:template>

<!-- Fuer das Element party der XML-Datei wird eine Ueberschrift 
-->
<!-- fuer die Ausgabe erzeugt. Das Attribut Datum wird in der   -->
<!-- Ueberschrift ausgegeben. -->
   <xsl:template match="party">
      <h1>Partytabelle fuer den
      <xsl:value-of select="@datum" />
      </h1>
      <xsl:apply-templates />
   </xsl:template>

<!-- Fuer jeden einzelnen Gast wird eine Begruessung ausgegeben -->
   <xsl:template match="gast">
      <p>
         <h2>Hallo
         <xsl:value-of select="@name" />
         </h2>
      </p>

      <xsl:apply-templates />
   </xsl:template>

<!-- Jedem Gast wird sein Lieblingsgetraenkt angeboten. -->
   <xsl:template match="getraenk">
      <p>Hier ist ein
      <xsl:value-of select="." />

      fuer dich.</p>
   </xsl:template>

<!-- Hier wird eine bedingte Ausgabe erzeugt. Jeder Gast -->
<!-- zeigt seinen Zustand und sagt, ob er noch ledig ist. -->
   <xsl:template match="zustand">
      <xsl:if test="@nuechtern='true'">
         <h3>Ich bin noch nuechtern!</h3>
      </xsl:if>

      <xsl:if test="@ledig='true'">
         <h3>Ich bin noch zu haben!</h3>
      </xsl:if>

      <hr />
   </xsl:template>
</xsl:stylesheet>

Das Ergebnis der Umwandlung ist folgende HTML-Datei:

<html>
  <head>
    <title>Wir machen eine Party</title>
  </head>
  <body>
    <h1>Partytabelle fuer den 31.12.01</h1>
    <p><h2>Hallo Albert Angsthase</h2></p>
    <p>Hier ist ein Wein fuer dich.</p>
    <p>Hier ist ein Bier fuer dich.</p>
    <h3>Ich bin noch zu haben!</h3>

    <hr>

    <p><h2>Hallo Martina Mutig</h2></p>
    <p>Hier ist ein Apfelsaft fuer dich.</p>
    <h3>Ich bin noch nuechtern!</h3>
    <h3>Ich bin noch zu haben!</h3>

    <hr>

    <p><h2>Hallo Zacharias Zottelig</h2></p>
  </body>
</html>

Die Ausgabe des Parsers ist nicht so schön formatiert, aber das ist für die Ausgabe in HTML nicht relevant. Diese Datei wurde nachträglich formatiert, damit die Ausgabe besser lesbar ist. Die Verarbeitung von Umlauten mit XSLT ist immer noch ein Problem. Trotz der Definition des Zeichensatzes im Kopf der XSLT-Datei bereiten Umlaute dem XSL-Parser noch Probleme.


Galileo Computing

13.5.2 Umwandlung von XML-Dateien mit JDOM und JAXP  toptop

Damit die Umwandlung mit JDOM möglich ist, wird das JDOM-Dokument von einem Wrapper-Objekt aufgenommen und mit dem XSLT-Parser Xalan von JAXP umgewandelt. Das Ergebnis ist wieder in einem Wrapper-Objekt und kann in eine JDOM-Datenstruktur umgewandelt werden.

Hier werden die beiden Ummantelungsklassen erzeugt. Das JDOM-Dokument ist von dem Objekt JDOMSource umgeben. Die Ausgabe wird in dem Objekt JDOMResult gekapselt

JDOMSource XSLDoku = new JDOMSource( 
doc );
JDOMResult HTMLDoku = new JDOMResult();

Mit einer Fabrikmethode wird eine Objekt der Klasse Transformer erzeugt. Dies ist ein Objekt aus dem JAXP-Paket und übernimmt die Umwandlung von XML-Dateien mithilfe einer XSLT-Datei. Für die Ein- und Ausgabe können Streams, SAX-Eigenschaften oder eine DOM-Datenstruktur dienen. In diesem Beispiel wird die Datei als Stream an den Transformer übergeben.

Transformer transformer =
TransformerFactory.newInstance().newTransformer(
new StreamSource("party.xsl"));

Mit dem Objekt Transformer und den beiden Objekten JDOMSource und JDOMResult wird die Umwandlung durchgeführt. Das Ergebnis der Umwandlung steht in dem Objekt JDOMResult und kann mit der Methode getDocument() in eine JDOM-Datenstruktur umgewandelt werden. Hier wird die JDOM-Datenstruktur erzeugt und direkt auf der Konsole ausgegeben:

XMLOutputter xmlOut = new XMLOutputter();
xmlOut.output( HTMLDoku.getDocument(), System.out );

Dieses Beispiel zeigt das Zusammenspiel von JDOM und JAXP. Damit wird deutlich, dass JDOM kein Ersatz für JAXP ist, sondern eine komfortable Möglichkeit XML-Dateien mit einer Java-Datenstruktur zu verarbeiten. Dabei können Elemente aus JAXP, die nicht in JDOM implementiert sind, genutzt werden, ohne auf die Vorteile von JDOM zu verzichten. Diese Beschreibung bezieht sich auf JDOM in der Version Beta 7. Zum Zeitpunkt des Drucks kann es sein, dass es bereits eine neuere Version von JDOM gibt. Hier wurde nur ein kleiner Überblick über die Funktionen von JDOM und die Verarbeitung von XML mit Java gegeben. Genauere Informationen finden sich auf der Webseite von JDOM (www.jdom.org) und auf der Webseite von Sun (www.java.sun.com/xml).

 

  

Java 2




Copyright © Galileo Press GmbH 2002
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.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, fon: 0228.42150.0, fax 0228.42150.77, info@galileo-press.de