Da sitzt man nun als Programmierer mit einer mehr oder wenigen komplexen XML-Datei und muss diese in die Java-Welt überführen... SAX oder DOM erfordert viel Fleiß und Zeit aber wer eine zugehörige Schema-Datei besitzt, kann sich glücklich schätzen!
Mit dem JSR 31 "Java Architecture for XML Binding" wurde die Möglichkeit bereitgestellt, Java Klassen aus einem Schema heraus zu generieren, XML sozusagen an Java zu "binden".
Eine beispielhafte Vorgehensweise wird Anhand eines Beispiels mit Apache XMLBeans erklärt.
Um an vorherige Beiträge aus der Track'n'Mash Reihe anzuknüpfen, nehmen wir den Fall an, dass der Entwickler eine GPX-Datei in die Java-Welt überführen soll:
<gpx creator="Trails 1.87+" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xalan="http://xml.apache.org/xalan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<trk>
<name>Auf der Straße</name>
<desc>n/a</desc>
<trkseg>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642451" lon="8.649525">
<ele>0.000000</ele>
<time>2009-08-23T12:25:35Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
Die entsprechende Schema-Datei http://www.topografix.com/GPX/1/1/gpx.xsd wird an einem entsprechenden Ort gespeichert und wir besorgen uns die entsprechenden XMLBeans Bibliotheken von Apache.
Die meiner Meinung nach schnellste Herangehensweise zur Generierung der entsprechenden "GPX Java Klassen", geht über Ant. XMLBeans stellt dazu einen eigenen Task bereit.
<project name="GPX2Java" default="build" basedir=".">
<taskdef name="xmlbean" classname="org.apache.xmlbeans.impl.tool.XMLBean" classpathref="xmlbeans.classpath" />
<property name="lib.dir" value="/tmp/gpx2java/lib/xmlbeans-2.4.0/lib" />
<property name="schema.file" value="/tmp/gpx2java/schema/gpx.xsd" />
<property name="src.dir" value="/tmp/gpx2java/gen_src" />
<property name="dest.file" value="/tmp/gpx2java/gpx.jar" />
<path id="xmlbeans.classpath">
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</path>
<target name="prepare" depends="xbeans_clean">
<mkdir dir="${src.dir}" />
</target>
<target name="clean">
<delete dir="${src.dir}" failonerror="false" />
</target>
<target name="build" depends="prepare">
<xmlbean schema="${schema.file}" javasource="1.5" destfile="${dest.file}" srcgendir="${src.dir}">
<classpath>
<path refid="xmlbeans.classpath" />
</classpath>
</xmlbean>
</target>
</project>
Das Target "build" erwartet eine Angabe zur Schema-Datei und benötigt eine Referenz zu den XMLBeans Bibliotheken. Optional werden hier noch die Parameter für den Namen der zu generierenden Jar-Datei gesetzt ("destfile") und ein Ordner für die zu generierenden Sourcen angegeben ("srcgendir").
Der Aufruf des Target "build" sollte nun die Datei "gpx.jar" produzieren.
Mit dem "gpx.jar" und den XMLBeans-Bibliotheken im Classpath, steht der Generierung von Java-Objekten aus XML und XML aus Java-Objekten nichts mehr im Weg. Der Prozeß wird als "Marshalling" und "Unmarshalling" beschrieben:
Unmarshalling:
GpxDocument doc = GpxDocument.Factory.parse(new File("/tmp/gpx2java/test.gpx"));
System.out.println(doc);
Ausgabe:
<gpx creator="Trails 1.87+" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xalan="http://xml.apache.org/xalan" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<trk>
<name>Auf der Straße</name>
<desc>n/a</desc>
<trkseg>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642583" lon="8.643338">
<ele>0.000000</ele>
<time>2009-08-23T12:25:30Z</time>
</trkpt>
<trkpt lat="49.642451" lon="8.649525">
<ele>0.000000</ele>
<time>2009-08-23T12:25:35Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
Marshalling:
Calendar cal = Calendar.getInstance();
GpxDocument doc = GpxDocument.Factory.newInstance();
GpxType gpx = doc.addNewGpx();
TrkType track = gpx.addNewTrk();
track.setName("Test track");
track.setDesc("n/a");
TrksegType segment = track.addNewTrkseg();
WptType waypoint = segment.addNewTrkpt();
waypoint.setLat(new BigDecimal("52.459781"));
waypoint.setLon(new BigDecimal("9.308918"));
waypoint.setEle(new BigDecimal("0"));
cal.setTime(new Date());
waypoint.setTime(cal);
waypoint = segment.addNewTrkpt();
waypoint.setLat(new BigDecimal("52.453430"));
waypoint.setLon(new BigDecimal("9.348915"));
waypoint.setEle(new BigDecimal("5"));
cal.setTime(new Date());
waypoint.setTime(cal);
System.out.println(doc);
Ausgabe:
<gpx xmlns="http://www.topografix.com/GPX/1/1">
<trk>
<name>Test track</name>
<desc>n/a</desc>
<trkseg>
<trkpt lat="52.459781" lon="9.308918">
<ele>0</ele>
<time>2009-12-10T16:44:00.355+01:00</time>
</trkpt>
<trkpt lat="52.453430" lon="9.348915">
<ele>5</ele>
<time>2009-12-10T16:44:00.418+01:00</time>
</trkpt>
</trkseg>
</trk>
</gpx>
.. sieht ja ganz brauchbar aus! Oft sind die generierten Jaxb-Klassen ja einfach nur gaga und nicht wirklich intuitiv nutzbar.
Für KML gibt es JAK - hier wird auch Jaxb eingesetzt, allerdings wird hier auch von Hand optimiert. JAK kann ich für KML bisher nur empfehlen.