Java und XML
Willemers Informatik-Ecke

Das Datenformat XML

XML steht für Extensible Markup Language, also eine erweiterbare Auszeichnungssprache. XML ist der Standard, wenn es darum geht, strukurierte Daten portabel zu speichern oder zu übertragen.
<Fuhrpark>
  <Auto>
    <Marke>Renault</Marke>
    <Typ>R4</Typ>
    <Preis>6798.99</Preis>
    <Hubraum einheit="ccm">845</Hubraum>
  </Auto>
  <Auto>
    <Marke>Opel</Marke>
    <Typ>Zafira</Typ>
    <Preis>8798.99</Preis>
    <Hubraum einheit="ccm">1598</Hubraum>
  </Auto>
</Fuhrpark>

Parsen und Generieren von XML in Java

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("datei.xml"));
// Wir holen das root-Element
Node rootNode = document.getDocumentElement();
NodeList nodeList = rootNode.getChildNodes();
// Durchsuchen aller Unterknoten
for (int i = 0; i < nodeList.getLength(); i++) {
    Node nodeChild = nodeList.item(i);
    // Verarbeite die Knoten hier!
}

Von XML zum Objekt: JAXB

JAXB ist eine Bibliothek, die auch von REST verwendet wird, wenn als Datenformat appication/xml angegeben wird. Die Handhabung ist dort extrem einfach. Die Klasse, deren Objekte übertragen werden sollen, wird die Annotation @XmlRootElement vorangestellt.
@XmlRootElement
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long id;
    // ...
Eine solche Person wird dann im REST-Server zur Verfügung gestellt. Dabei wird als Rückgabetyp einfach Person angegeben. Die Umwandung in XML erledigt JAXB im Hintergrund.
    // ... Innerhalb der REST-Service-Klasse
    @GET
    @Path("person/id/{id}")
    @Produces(MediaType.APPLICATION_XML)
    public Person getXmlPerson(
            @PathParam("id") long id) {
        Person person = dao.getPerson(id);
        return person;
    }
Der Client muss natürlich auch eine Klasse Person definieren, die sinnvollerweise identisch ist, um aus dem XML-String ein brauchbares Objekt zu machen. Auch der Client gibt @XmlRoot als Annotation an.

Verwendet der Client Jersey, kann er ebenso einfach angeben, dass XML verwendet werden soll und das Thema ist durch. Wird aber beispielsweise HttpUrlConnection direkt verwendet, muss das Client-Programm die Wandlung von XML in ein Objekt selbst durchführen.

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
// ...
    private Person getPerson(String url, int id) {
        url += "/api/person/id/" + id;
        Person person = null;
        try {
            // Der XML-String wird geholt (hier nicht näher ausgeführt.
            String xmlStr = verbindGetXmlString(url);
            // Setze den Kontext auf eine Person, baue den Ummarshaller
            JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            StringReader reader = new StringReader(xmlStr);
            person = (Person) unmarshaller.unmarshal(reader);
            // Zum Test ausgeben...
            System.out.println(person.getName());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return person;
    }
    // ...

Im Array

In der Regel werden Personen nicht nur einzeln benötigt, sondern eine ganze Reihe davon. Bei REST ist das kein Problem, Sie geben lediglich an, dass Sie eine Liste meinen:
    @GET
    @Path("allpersons")
    @Produces(MediaType.APPLICATION_XML)
    public List<Person> getPersonen() {(
        
        List<Person> list = dao.getPersonenListe();
        return list;
    }
Auf Client-Seite müssen Sie nun eine neue Klasse erstellen, die die übertragene Liste als solche aufnimmt. Der REST-Server wird der automatisch erzeugten Listen-Klasse ein s anhängen. Die Listenklasse für Person heißt also Persons.
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Persons implements Serializable {
    private static final long serialVersionUID = 6516481325506402152L;
    
    private List<Person> liste = new ArrayList<Person>();

    public List<Person> getPerson() {
        return liste;
    }

    public void setPerson(List<Person> liste) {
        this.liste = liste;
    }
}
Das Programm wird nun ein Objekt von Persons entgegen nehmen und über die Methode getPerson an die Liste der Personen gelangen.
    private static String getBuchungen(String url, int jahr, int monat) {
        url += "/api/allpersons/";
        List<Person> liste = new ArrayList<Person>();
        try {
            String xmlStr = verbindGetXmlString(url);
            JAXBContext jaxbContext = JAXBContext.newInstance(Persons.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            StringReader reader = new StringReader(xmlStr);
            Persons ps = (Persons) unmarshaller.unmarshal(reader);
            liste = ps.getPerson();
            // Zum Test ausgeben
            for (Person p : liste) {
                System.out.println(p.getName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlStr;