Objekte <-> XML (Serialisierung/Deserialisierung)

Im Folgenden wird beschrieben, wie man mithilfe der Open-Source-Bibliothek Simple XML einen Objektbaum in eine XML-Zeichenkette umwandelt und umgekehrt eine XML-Zeichenkette in einen Objektbaum.
Die beschriebene Vorgehensweise deckt nur einen sehr kleinen Funktionsumfang von Simple XML ab. Es wird dringend empfohlen, das sehr verständliche Tutorial durchzuarbeiten.

Aufnahme der Bibliothek ins Projekt

Auf der Downloadseite des Projekts kann ein Archiv heruntergeladen werden, das die Simple XML-Bibliothek, die Quelltexte und die Dokumentation enthält. In der Entwicklungsumgebung benötigen wir nur die Bibliothek selbst, also die Datei simple-xmml-2.7.1.jar. Sie muss in den Ordner libs des Projekts kopiert werden. („Reinziehen“ vom Dateiexplorer in den Package Explorer von Eclipse oder Kopieren im Dateisystem und anschließend „F5“ aufs Projekt im Package-Explorer).

Model-Klassen

Damit Objekte mit Simple XML serialisiert und deserialisiert werden können, müssen sie mit Annotations versehen werden, die angeben, welche Attribute wie umgewandelt werden sollen. Hier ein Beispiel:

@Root
public class Buch {
 
	@Element
	private String titel;
 
	@Element
	private String autor;
 
	@Element
	private int seitenzahl;
 
	public Buch() {
	};
 
	public Buch(String titel, String autor, int seitenzahl) {
		super();
		this.titel = titel;
		this.autor = autor;
		this.seitenzahl = seitenzahl;
	}
 
	public String getTitel() {
		return titel;
	}
 
	public void setTitel(String titel) {
		this.titel = titel;
	}
 
	public String getAutor() {
		return autor;
	}
 
	public void setAutor(String autor) {
		this.autor = autor;
	}
 
	public int getSeitenzahl() {
		return seitenzahl;
	}
 
	public void setSeitenzahl(int seitenzahl) {
		this.seitenzahl = seitenzahl;
	}
 
	@Override
	public String toString() {
 
		return "[" + titel + "; " + autor + "; " + seitenzahl + "]";
 
	}
 
}

Die Annotation @Root zeigt an, dass es sich um eine serialisierbare Klasse handelt. @Element bedeutet, dass das Attribut des Klasse als XML-Unterelement serialisiert wird (im Unterschied zu @Attribute). Enthält ein Objekt eine Liste anderer Objekte, so gibt es dazu die Annotation @ElementList. So besteht eine Bibliothek beispielsweise aus mehreren Büchern:

@Root
public class Bibliothek {
 
	@Attribute
	private String name;
 
	@ElementList
	private List<Buch> buecher = new ArrayList<Buch>();
 
	public Bibliothek(){};
 
...

Ein beispielhafter Objektbaum sieht so aus:

<bibliothek name="CSG-Schülerbücherei">
   <buecher class="java.util.ArrayList">
      <buch>
         <autor>Michael Ende</autor>
         <titel>Jim Knopf und Lukas der Lokomotivführer</titel>
         <seitenzahl>327</seitenzahl>
      </buch>
      <buch>
         <autor>Astrid Lindgren</autor>
         <titel>Pippi Langstrumpf</titel>
         <seitenzahl>451</seitenzahl>
      </buch>
      <buch>
         <autor>Benno Beispiel</autor>
         <titel>Mathe macht Spass</titel>
         <seitenzahl>1265</seitenzahl>
      </buch>
   </buecher>
   <verlage class="java.util.ArrayList">
      <verlag>
         <name>Oettinger</name>
         <ort>Hamburg</ort>
      </verlag>
      <verlag>
         <name>Klett</name>
         <ort>München</ort>
      </verlag>
   </verlage>
</bibliothek>

Code zum Serialisieren

Hier der Code zum Serialisieren:

    	Bibliothek bib = BeispielFactory.getBeispielBibliothek();
 
    	Style style = new HyphenStyle();
    	Format format = new Format(style);
 
    	Serializer serializer = new Persister(format);
 
    	StringWriter writer = new StringWriter();
 
    	try {
    		serializer.write(bib, writer);
    		Log.i("XML", writer.getBuffer().toString()); // Statt Ausgabe ins Log kann der String bspw. auch per HttpRequest an einen Server gesendet werden ...
 
    	} catch (Exception ex){
    		ausgabe.setText(ex.toString());
    	}

Code zum Deserialisieren

Hier der Code zum Deserialisieren:

    	String xml = ... // Von irgendwoher kommt der XML-Text...
 
    	Serializer serializer = new Persister();
 
    	try {    	
    		Bibliothek bib = serializer.read(Bibliothek.class, xml);
    		// bib ist der Knoten des Objektbaums, mit dem jetzt weitergearbeitet werden kann!
    	} catch (Exception ex){
    		ausgabe.setText(ex.toString());
    	}

Was tun bei Objektgraphen mit Zyklen?

Das obige Vorgehen funktioniert natürlich nur bei baumförmigen Objektstrukturen. Sobald der Objektgraph Zyklen besitzt, ist eine direkte Umsetzung in einen XML-Baum nicht mehr möglich, weil ein Objekt in mehreren anderen Objekten enthalten sein kann. Hier hält Simple XML eine Lösung bereit: Es versieht alle XML-Objekte mit einem zusätzliche Attribut „id“, das eine fortlaufende Nummerierung enthält. Ist ein Objekt in zwei anderen Objekte enthalten, so wird es nur als Unterelement des ersten serialisiert. Beim zweiten fügt Simple XML nur eine Referenz auf die id des Objekts ein. Vor dem Serialisieren muss dem Serializer nur eine CycleStrategy mitgegeben werden:

    	Strategy strategy = new CycleStrategy("id", "ref");
    	Serializer serializer = new Persister(strategy, format);
 
    ...

Ebenso vor dem Deserialisieren:

    	Strategy strategy = new CycleStrategy("id", "ref");
    	Serializer serializer = new Persister(strategy);
...

Fügt man dem obigen Objektmodell noch eine Klasse Verlag hinzu und referenziert man die Verlage sowohl als Liste beim Bibliothek-Objekt als auch als Attribut jedes einzelnen Buchs, so erhält man etwa folgendes:

public class Verlag {
 
	@Element
	private String name;
 
	@Element
	private String ort;
...
 
}
 
@Root
public class Bibliothek {
 
	@Attribute
	private String name;
 
	@ElementList
	private List<Verlag> verlage = new ArrayList<Verlag>();
 
	@ElementList
	private List<Buch> buecher = new ArrayList<Buch>();
...
 
}
 
@Root
public class Buch {
 
	@Element
	private String titel;
 
	@Element
	private Verlag verlag;
 
...
}

Ein Beispiel für eine als XML serialisierte Bibliothek sieht dann so aus:

<bibliothek id="0" name="CSG-Schülerbücherei">
   <buecher class="java.util.ArrayList" id="1">
      <buch id="2">
         <autor id="3">Michael Ende</autor>
         <verlag id="4">
            <name id="5">Oettinger</name>
            <ort id="6">Hamburg</ort>
         </verlag>
         <titel id="7">Jim Knopf und Lukas der Lokomotivführer</titel>
         <seitenzahl id="8">327</seitenzahl>
      </buch>
      <buch id="9">
         <autor id="10">Astrid Lindgren</autor>
         <verlag ref="4"/>
         <titel id="11">Pippi Langstrumpf</titel>
         <seitenzahl id="12">451</seitenzahl>
      </buch>
      <buch id="13">
         <autor id="14">Benno Beispiel</autor>
         <verlag id="15">
            <name id="16">Klett</name>
            <ort id="17">München</ort>
         </verlag>
         <titel id="18">Mathe macht Spass</titel>
         <seitenzahl id="19">1265</seitenzahl>
      </buch>
   </buecher>
   <verlage class="java.util.ArrayList" id="20">
      <verlag ref="4"/>
      <verlag ref="15"/>
   </verlage>
</bibliothek>

Ausblick

Die Bibliothek Simple XML bietet noch weit mehr Möglichkeiten als oben gezeigt, bspw.:

  • XML-Elementnamen, die von den Attributnamen abweichen
  • Optionale XML-Elemente
  • Möglichkeit, Binärdaten (z.B. Grafiken) zu serialisieren, z.B. als Base64-String
  • Möglichkeit, CDATA-Sections in XML zu schreiben und zu lesen
  • Transiente Attribute (d.h. Attribute, die nicht serialisiert werden)
  • Aufruf bestimmter Methoden vor dem Serialisieren bzw. nach dem Serialisieren der Objekte
  • Serialisieren von Maps
  • Einfach Implementierung einer XML-basierten Template Engine
Drucken/exportieren
QR-Code
QR-Code programmieren:java:android:xml:start (erstellt für aktuelle Seite)