XML-Generierung in Grails

In Grails gibt es verschiedene Möglichkeiten XML zu erzeugen. Ich möchte in diesem Beitrag vier verschiedene Methoden vorstellen.

String-Generierung

Die wohl einfachste Methode XML zu erzeugen und zu senden ist es, die XML-Tags einfach als String zu deklarieren. In einem Grails-Controller sieht das dann so aus:

String xml = 
  "<books><book title=\"Der alte Mann und das Meer\"></book></books>"

render text: xml, contentType: "text/xml"

Diese Methode mag für kleine XML-Schnipsel geeignet sein, aber für größere XML-Dateien ist sie nicht zu gebrauchen. Das Quoten der Gänsefüßchen ist mühsam und macht den Code weniger lesbar. Da die XML-Tags nicht wirklich generiert werden ist Wahrscheinlichkeit eines Tippfehler eher hoch.

Also schauen wir nach anderen eleganteren Methoden.

Encoding von Objekten

Grails bietet uns die Möglichkeit an beliebige Objekte nach XML zu konvertieren. Dabei werden die Namen der Objekte (Klassen- und Variablennamen) als XML-Tags verwendet. Die ist besonders beim Kodieren von Domainobjekten sinnvoll:

import grails.converters.XML

render Books.list() as XML

Ohne viel Aufwand hat man so alle Eigenschaften der Objekte kodiert. Möchte man etwas mehr Kontrolle über das entstehende XML haben, dann bieten sich die nächsten Methoden an:

Groovy-MarkupBuilder

Mit dem Groovy-MarkupBuilder können wir XML auf eine sehr einfach Art und Weise deklarieren:

import groovy.xml.MarkupBuilder

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.books() {
  book(title: "Der alte Mann und das Meer")
}

render(text: writer.toString(), contentType: "text/xml")

Jeder XML-Tag wird als ein Methodenaufruf deklariert, wobei die Methodenparameter gleichzeitig die zu erzeugenden XML-Attribute sind. Geschachtelt wird mit den entsprechenden Closures (siehe Groovy-Dokumentation).

Der große Vorteil dieser Methode liegt in der dynamischen Verwendung, also die Verwendung von ganz normalen Groovy-Code innerhalb der Deklaration. Z.B. die Verwendung einer FOR-Schleife:

...
xml.books() {
  for (book in bookList) {
    book(title: book.title)
  }
}
...

Zwei Fallstricke sollte man jedoch beachten. Methodennamen dürfen nicht alle Zeichen enthalten. Um beispielsweise ein XML-Tag mit einen Bindestrich zu erzeugen, muss man den Methodenaufruf in Gänsefüßchen setzen.

...
xml.books() {
  "book-item" (title: "Der alte Mann und das Meer")
}
...

Außerdem kann es zu Namenskonflikten kommen. Hat man bereits eine Variable ‘book’ deklariert sollte man zur XML-Deklaration ‘book’ ebenfalls in Gänsefüßchen setzen.

Markup-Builder der ‘render’-Methode

Der Groovy-MarkupBuilder kann auch direkt mit der ‘render’-Methode von Grails verwendet werden:

render {
  books() {
    book (title: "Der alte Mann und das Meer")
  }
}

Man spart sich etwas Tipparbeit, muss aber auf die gleichen Fallstricke achten.

GSP-Rendering

Möchte man bei der XML-Generierung Controller und View ordentlich trennen, so kann man auch das GSP-Rendering verwenden. GSP’s werden normalerweise als HTML gerendert, aber das geht auch als XML:

<%@ page contentType="text/xml" %>
<books>
  <book title="Der alte Mann und das Meer"></book>
</books>

Die Daten können wie immer im Controller bereitgestellt werden und in der GSP können die gewohnten Grails-Tags verwendet werden.