XML-Verarbeitung mit XStream
on Aug 16 in Java by abiWir nutzen bei sLAB schon seit langem XStream als Möglichkeit XML zu serialisieren und deserialisieren. Die Bibliothek ist seit Dezember 2008 unverändert und ich bin im Moment wieder dabei, damit zu arbeiten.
Setup
Für das Tutorial benötigen wir erst einmal ein paar Klassen zum serialisieren. Wir beginnen einfach mit zwei Klassen Angestellter und Adresse.
package de.billmann.xstream;
public class Angestellter {
private Long personalNummer;
private String vorname;
private String nachname;
private Adresse adresse;
private long internerWert;
public Angestellter() {
this.internerWert = System.currentTimeMillis();
}
public Long getPersonalNummer() {
return personalNummer;
}
public void setPersonalNummer(Long personalNummer) {
this.personalNummer = personalNummer;
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
this.vorname = vorname;
}
public String getNachname() {
return nachname;
}
public void setNachname(String nachname) {
this.nachname = nachname;
}
public Adresse getAdresse() {
return adresse;
}
public void setAdresse(Adresse adresse) {
this.adresse = adresse;
}
}
package de.billmann.xstream;
public class Adresse {
private String strasse;
private String plz;
private String ort;
public String getStrasse() {
return strasse;
}
public void setStrasse(String strasse) {
this.strasse = strasse;
}
public String getPlz() {
return plz;
}
public void setPlz(String plz) {
this.plz = plz;
}
public String getOrt() {
return ort;
}
public void setOrt(String ort) {
this.ort = ort;
}
}
Bei der Klasse Angestellter habe ich noch zur Demonstration ein Feld hinzugefügt, welches nicht über getter/setter erreichbar ist, um zu zeigen, daß die Bibiothek auf den Klassenvariablen arbeitet.
Erste Verwendung
Als erstes wandeln wir einmal einen Angestellten ohne weitere konfiguration in XML um.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
System.out.println(xstream.toXML(angestellter1));
}
}
Als Ergebnis erhalten wir
<de.billmann.xstream.Angestellter> <personalNummer>123456</personalNummer> <vorname>Hans</vorname> <nachname>Mustermann</nachname> <internerWert>1299606058760</internerWert> </de.billmann.xstream.Angestellter>
Für den Anfang schonmal ganz brauchbar. Aber jetzt wollen wir mal anschauen wie die eine Referenz aufgelöst wird und dazu fügen wir dem Angstellten eine Adresse hinzu.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// Eine Adresse dazu erzeugen
Adresse adresse1 = new Adresse();
adresse1.setStrasse("Daheimweg");
adresse1.setPlz("12345");
adresse1.setOrt("Zuhause");
angestellter1.setAdresse(adresse1);
System.out.println(xstream.toXML(angestellter1));
}
}
Das Ergebnis sieht folgendermaßen aus:
<de.billmann.xstream.Angestellter>
<personalNummer>123456</personalNummer>
<vorname>Hans</vorname>
<nachname>Mustermann</nachname>
<adresse>
<strasse>Daheimweg</strasse>
<plz>12345</plz>
<ort>Zuhause</ort>
</adresse>
<internerWert>1299606190037</internerWert>
</de.billmann.xstream.Angestellter>
Liste von Angestellten
Häufig hat man ja nicht nur ein Objekt sondern eine ganze Liste, die man serialisieren möchte und das testen wir jetzt.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
import java.util.ArrayList;
import java.util.List;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
List firma = new ArrayList();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// Eine Adresse dazu erzeugen
Adresse adresse1 = new Adresse();
adresse1.setStrasse("Daheimweg");
adresse1.setPlz("12345");
adresse1.setOrt("Zuhause");
angestellter1.setAdresse(adresse1);
// Eine Angestellte erzeugen
Angestellter angestellter2 = new Angestellter();
angestellter2.setPersonalNummer(654321l);
angestellter2.setVorname("Giesela");
angestellter2.setNachname("Beispiel");
firma.add(angestellter1);
firma.add(angestellter2);
System.out.println(xstream.toXML(firma));
}
}
Als Ausgabe erhalten wir:
<list>
<de.billmann.xstream.Angestellter>
<personalNummer>123456</personalNummer>
<vorname>Hans</vorname>
<nachname>Mustermann</nachname>
<adresse>
<strasse>Daheimweg</strasse>
<plz>12345</plz>
<ort>Zuhause</ort>
</adresse>
<internerWert>1299606601940</internerWert>
</de.billmann.xstream.Angestellter>
<de.billmann.xstream.Angestellter>
<personalNummer>654321</personalNummer>
<vorname>Giesela</vorname>
<nachname>Beispiel</nachname>
<internerWert>1299606601941</internerWert>
</de.billmann.xstream.Angestellter>
</list>
Ausgabe aufhübschen
Das meiste kann XStream aus dem Zusammenhang der Klassen entnehmen. So werden die einzelnen Klassenvariablen als Namen für die tags verwendet. Nur bei der Klasse Angestellter funktioniert das nicht. Für eine Deserialisierung hätte XStream nicht die nötigen Informationen, die richtige Klasse zu instanziieren (angenommen es gäbe mehrere Klassen Angestellter). Bei der Adresse ist es unstrittig, da die Klassendefinition von Angestellter ja den genaun Typ enthält.
Allerdings ist die Ausgabe mit package nicht sonderlich schön aber hierzu bietet uns XStream einfache Möglichkeiten das zu konfigurieren.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// class mapping
xstream.alias("angestellter", Angestellter.class);
System.out.println(xstream.toXML(angestellter1));
}
}
Wir können für Klassen einen Alias angeben, der dann eindeutig mit dieser Klasse verknüpft ist. Sowohl zur Serialisierung als auch zur Deserialisierung nutzt extrem diesen Namen.
<angestellter> <personalNummer>123456</personalNummer> <vorname>Hans</vorname> <nachname>Mustermann</nachname> <internerWert>1299607040128</internerWert> </angestellter>
Es können hierbei nicht nur die Klassennamen mit einem Alias versehen werden, man kann auch die Klassenvariablen einen Alias zuweisen. Dadurch hat man die Möglichkeit das XML noch zu beeinflussen, falls man bestimmte Vorgaben hat, weil es zum DAtenaustausch mit einem anderen System dient.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// class mapping
xstream.alias("angestellter", Angestellter.class);
// field mapping
xstream.aliasField("pn", Angestellter.class, "personalNummer");
System.out.println(xstream.toXML(angestellter1));
}
}
Hierbei wird das tag personalNummer in pn gewandelt.
<angestellter> <pn>123456</pn> <vorname>Hans</vorname> <nachname>Mustermann</nachname> <internerWert>1299622340068</internerWert> </angestellter>
Klassenvariablen auslassen
Der interneWert soll nicht serialisiert werden. Um das zu erreichen kann man einfach XStream mit omitField davon in Kenntnis setzen.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// class mapping
xstream.alias("angestellter", Angestellter.class);
// field mapping
xstream.aliasField("pn", Angestellter.class, "personalNummer");
// omit field
xstream.omitField(Angestellter.class, "internerWert");
System.out.println(xstream.toXML(angestellter1));
}
}
Und nun taucht der Wert nicht mehr auf.
<angestellter> <pn>123456</pn> <vorname>Hans</vorname> <nachname>Mustermann</nachname> </angestellter>
Attribute hinzufügen
Nicht immer ist es gewünscht einen Wert als eigenständiges tag anzugeben. Im nachfolgenden Beispiel wird die personalNummer, welche jetzt mit pn abgekürzt wird, als attribute angegeben.
package de.billmann.xstream;
import com.thoughtworks.xstream.XStream;
public class XStreamTest {
public static void main(String[] args) {
XStream xstream = new XStream();
// Einen Angestellten erzeugen
Angestellter angestellter1 = new Angestellter();
angestellter1.setPersonalNummer(123456l);
angestellter1.setVorname("Hans");
angestellter1.setNachname("Mustermann");
// class mapping
xstream.alias("angestellter", Angestellter.class);
// field mapping
xstream.aliasField("pn", Angestellter.class, "personalNummer");
// omit field
xstream.omitField(Angestellter.class, "internerWert");
// as attribute
xstream.useAttributeFor(Angestellter.class, "personalNummer");
System.out.println(xstream.toXML(angestellter1));
}
}
<angestellter pn="123456"> <vorname>Hans</vorname> <nachname>Mustermann</nachname> </angestellter>
Fazit
Das Tutorial sollte zeigen wie einfach es mit XStream ist, mit XML umzugehen. Die Bibliothek kann weitaus mehr und es lohnt sich sie anzusehen. Die Dokumentation und Beispiele auf der Projektseite sind umfangreich und leicht nach zu vollziehen. Bei sLAB setzen wir die Bibliothek ein um XML-Konfigurationen einzulesen oder um XML als Austauschformat mit anderen Systemen zu nutzen, ohne uns mit aufwändigem parsen herum zu schlagen.






There are no comments yet, add one below.