Bohnen für XML: XMLBeans

(http://www.zdnet.de/magazin/39136803/bohnen-fuer-xml-xmlbeans.htm)

von DJ Walker-Morgan, 29. September 2005

Das Schreiben von Code zum Lesen und Manipulieren von XML kann ziemlich ermüdend sein. Langwierige Aufgaben sind nicht für effizientes Schreiben von Code geeignet - dank XMLBeans können viele dieser Aufgaben beschleunigt werden.

XML-Dokumente können viel einfacher in Java mit XMLBeans gelesen und manipuliert werden. Hier werden die ersten Schritte beschrieben.

Zunächst ein Blick auf das Tool XMLBeans, das inzwischen in der zweiten Version zur Verfügung steht. XMLBeans wurde ursprünglich von BEA entwickelt und später Apache übergeben. Es gibt sehr viele XML-Java-Data-Binding-Tools; XMLBeans zeichnet sich dadurch aus, dass es für viele, wenn nicht gar für alle XML-bezogenen Codierungsklassen geeignet ist - vom Knotendurchlauf bei Nicht Daten (damit man diese Kommentare programmatisch hervorholen kann) bis hin zur abstrahierten datenorientierten Manipulation.

Das Arbeiten mit XMLBeans beginnt mit einem XML-Schema. Hier ein Beispielschema für eine einfache Applikation: sites.xsd. Dieses Beispiel, wie auch alle anderen hier aufgeführten Beispiele, sind hier als zip-Datei herunterzuladen: xmlbnat.zip[1].

Das Beispiel hier legt ein Schema mit dem Element "sites" fest, das eine Reihe von Elementen des Typs "site" enthalten kann, die dann wiederum eine beliebige Zahl von Elementen des Typs "rating oder "comment" beinhalten können, wobei beide Typen eine E-Mail-Adresse als Attribut zur Identifizierung des Autors des Rating oder Comment vorweisen. Zuerst wird XMLBeans von der Apache-Website heruntergeladen[2] und installiert. Dabei sollte man nicht vergessen, den Installationsort in der Umgebungsvariablen XMLBEANS_HOME einzustellen und das Verzeichnis $XMLBEANS_HOME/bin aus der Distribution dem eigenen Pfad hinzuzufügen. Dadurch stehen die XMLBeans-Befehle zur Verfügung, darunter auch der Schema-Compiler "scomp", der wichtigste aller Befehle.

Wird dann


scomp -out sites.jar sites.xsd

ausgeführt, sieht man:

Scomp hat ein Typensystem erstellt, dafür Java-Code erzeugt und diesen kompiliert. Ausgegeben wird lediglich die Datei "sites.jar", da scomp mangels anderer Instruktionen nur die vorkompilierte jar-Datei erzeugt. Will man die Herkunft des so erzeugten Codes anzeigen, kann man


scomp -srconly -src srcdir sites.xsd

ausführen. Alle generierten Klassen befinden sich im Paket com.example.sites.site, das aus dem Ziel-Namespaces des Schemas abgeleitet wurde. Dies wird in den Anfangszeilen der Schemadatei definiert:

Wenn kein Ziel-Namespace für das Schema vorhanden ist, erscheinen die erzeugten Klassen in einem Paket namens noNamespace. Für das Beispiel gibt es eine Klasse SitesDocument sowie Klassen für alle im Schema definierten Typen: Sites, Site, Comment, Rating und Email. Alle generierten Klassen erweitern die XMLBeans-Foundation Class XMLObject. Später mehr dazu. Nun wird erst einmal ein XML-Dokument geparst:

Fertig. Probleme beim Parsen geben eine XmlException aus. Nun kann die Verarbeitung beginnen. Alle generierten Klassen haben eine statische Factory, um die Erstellung - entweder durch Parsen oder qua Programm - von Instanzen zu ermöglichen. In diesem Beispiel wurde die einfachste Parse-Methode der Factory verwendet. Nun wird Code hinzugefügt, um die Site-Einträge abzuarbeiten und die Comments und Ratings auszudrucken. Zunächst gilt es, zum Root-Element des Dokuments zu gelangen.


Sites sites=sd.getSites();

In XMLBeans werden Sequenzen in XLM-Schemas über Arrays dargestellt, so kann man jedes Array aufnehmen und abarbeiten. (Anmerkung: Hier wird zur Konstruktion das neue Array von Java SE 5.0 verwendet.)


for(Site s:sites.getSiteArray()) {

Für Elemente und ihre Attribute werden Methoden generiert, damit ihre Werte abgerufen und festgesetzt werden können; hier wird auf das SCR-Attribut der Site zugegriffen und dieses ausgedruckt.


System.out.println(s.getSrc());

Auf die gleiche Weise kann man auch auf die Rating- und Comment-Arrays innerhalb des Site-Elements zugreifen und diese abarbeiten.

Logischerweise folgt jetzt die Manipulation von XML. Nun wird dem Dokument eine Site hinzugefügt.


Site newsite=sites.addNewSite();

Auch hier hat XMLBeans scomp Methoden generiert, mit denen man eine leere Instanz der Klasse Site erzeugen und der Instanz der Klasse Sites hinzufügen kann. Nun muss nur noch das SRC-Attribut festgelegt werden:


newsite.setSrc("http://www.example.net/specialpurpose.html");

Sequenzen können auch über die Indexnummer adressiert werden; will man beispielsweise einen Comment vor dem Inhalt des Site-Elements einfügen, kann man


Comment newcomment=newsite.insertNewComment(0);

verwenden, wodurch ein leerer Comment erzeugt und in der Position 0 eingefügt wird. Nun müssen nur noch dessen Attribut und Wert festgelegt werden.


newcomment.setEmail("fred@example.com");
newcomment.setStringValue("This was a reasonable addition");

Nach all diesen Manipulationen wäre es keine schlechte Idee, das Dokument zu speichern.


sd.save(new File("./newsites.xml"));

Die Beispiele zu diesem Artikel beinhalten alle oben genannten Codes in Example1.java. Bevor der Code ausgeführt werden kann, müssen die Dateien xbean.jar und jsr173_api.jar aus der XML-Distribution sowie die zuvor erzeugte Datei sites.jar in das Bibliotheksverzeichnis kopiert werden. Anschließend muss nur noch "ant example1" ausgeführt werden, wonach sich die Datei newsites.xml im Verzeichnis befinden sollte.

Betrachtet man sich die Datei newsites.xml, sieht man, wie XMLBeans das XML-Infoset erhält. Zwar wurde die Datei verändert, doch kann man erkennen, dass die Comments in der Datei sites.xml nicht aus der Datei entfernt wurden, sondern sich noch an ihrem Platz befinden. Hier handelt es sich um ein äußerst praktisches Feature, wenn man XML-Dateien verarbeiten möchte, ohne irgendwelche Inhalte der Dateien zu verlieren, zum Beispiel dann, wenn man Dateien manipuliert, die einer Versionskontrolle unterliegen; außerdem lässt sich dieses Ergebnis normalerweise nicht mit anderen XML-Mechanismen erreichen, die XML-Inhalte vom DOM abziehen.

Wie bereits erwähnt, basieren alle erzeugten Klassen auf XMLObject. XMLObject ist auch der Grund, dass weitere Navigations- und Validierungsoptionen zur Verfügung stehen. Standardmäßig arbeitet XMLBeans ohne Validierung, wird jedoch die Methode validate() für eine XMLBean aufgerufen, kann man die Gültigkeit der Inhalte auf jeder Bean, einschließlich der abgeleiteten Prozesse, überprüfen. Die Validierung umfasst auch eventuell definierte XML-Schema-Einschränkungen. In der Beispieldatei sites.xsd gibt es eine Einschränkung des E-Mail-Typs, damit sichergestellt wird, dass nur gültige E-Mail-Adressen eingegeben werden. Eine Instanz der Klasse Email kann mit Hilfe ihrer Factory erzeugt, mit einem Wert versehen und dann validiert werden.

Unter den Beispielen befindet sich Validate.java, das zur Prüfung eines Arrays mit E-Mail-Adressen verwendet wird. Das ist nicht der einzige Validierungsmechanismus in XMLBeans; man kann auch einen Validierungs-ErrorListener einsetzen, der alle Validierungsfehler an einem Ort sammelt, oder aber die Validierung aktivieren (dies wird eigentlich nur für das Debuggen verwendet). Um in einem Dokument zu navigieren, kann man sich mit dem Xml-Cursor von jedem XmlObject aus bewegen. Hierzu wird lediglich ein Cursor von einem Objekt angefordert; hier die Navigation zum ersten Site-Element in der Beispieldatei:

Dieser Cursor zeigt nun auf das Site-Element, und mit diesem Cursor kann man in Bezug hierauf navigieren; will man zum Beispiel das erste abgeleitete Element finden, kann man den Cursor wie folgt bewegen:


cursor.toChild(stnamespace,"rating");

Xml-Cursor sind am besten geeignet, wenn man sich auf Token-Ebene bewegen möchte, obwohl man auch auf die Zeichenebene heruntergehen kann. Um einen Eindruck davon zu bekommen, wie ein Dokument für einen Xml-Cursor aussieht, wird im nächsten Beispiel (CursorWalk.java) ein Dokument geparst, durch das Dokument gegangen und das Ergebnis ausgedruckt:

Zu beachten ist, dass hier zum ersten Mal nicht die Klasse SiteDocument, die mit scomp generiert wurde, sondern XmlObject direkt verwendet wurde - wodurch es möglich ist, jede gut konzipierte XML-Datei auch ohne Schema-Datei zu parsen. Die andere Möglichkeit der Navigation in XMLBeans liegt im anderen Extrem des Abstraktionsspektrums: Die Möglichkeit der Auswahl und Abfrage mit XPath-/XQuery-Ausdrücken, wodurch das Dokument durchsucht und aus den darin enthaltenen Knoten ausgewählt werden kann. XmlObjects unterstützen die Methoden selectPath() und execQuery(). Die Methode selectPath() wird ausschließlich zur Auswahl von Knoten im Dokument verwendet, wogegen es die Methode execQuery() ermöglicht, XQuery auszuführen und vollkommen neue Daten in XML auszugeben.

Um dies zu ermöglichen, müssen dem Klassenpfad zwei weitere Libraries hinzugefügt werden: die Saxon-Bibliothek (Version 8.1.1), und xbean_xpath.jar von der XMLBeans-Distribution. Ein Link zur entsprechenden Version von Saxon ist auf der XMLBeans-Website zu finden; die Dateien saxon8.jar aus der Saxon-Distribution und xbean_path.jar werden in das Bibliotheksverzeichnis des Beispielquellcodes eingefügt.

SimpleXPath.java bietet eine kurze Einführung zur Verwendung von XPath-Anfragen. Hier ein Blick auf den relevanten Teil des Quellcodes:

Der erste Teil ist irgendeine XQuery zur Deklarierung des Namespace. Dieser wird der Abfrage vorangestellt. Dann folgt der Aufruf selectPath(); sowohl selectPath() als auch execQuery() geben ein Array mit XML-Objekten zurück. Der eigentliche XPath lautet


//st:site[st:rating/@rated=5]

und legt fest, dass alle Site-Elemente, die ein Rating-Element mit einem Rating-Attribut von 5 beinhalten, markiert werden. Zurückgegeben wird ein Array mit XML-Objekten, das dann in ein Array mit Sites gecastet werden kann, mit nachfolgendem Ausdruck der Ergebnisse.

XPath und XQuery sind ein Thema für sich; es genügt zu sagen, dass sie XMLBeans die Möglichkeit zu ein paar ziemlich interessanten Anfragen und zur Dokumentengenerierung eröffnen, ohne sich an der Hierarchie der Schemaklassen abarbeiten zu müssen und ohne die Vorteile zu verlieren, die von den durch XMLBeans generierten Klassen angeboten werden.

XMLBeans ist eine ausgezeichnete Option, wenn man für alle XML-Codierungsbedürfnisse nach einem einzigen Anbieter sucht. Fragt man sich aber, ob man denn nicht doch ein XML-Schema benötigen wird, obwohl ein Schema die Details nie so genau abstimmen kann wie die Codierung von Hand, dann kann das XmlBean-Tool inst2xsd versuchen, eine .xsd-Datei aus einer Reihe von XML-Dateien zu erzeugen.

URLs in diesem Artikel:
[1] = http://www.zdnet.de/i/bld/program/2005/09/xmlbnat.zip
[2] = http://xmlbeans.apache.org/