XML mit Python: lxml.objectify

lxml hat sich inzwischen zu einer der besten und schnellsten XML Bibliotheken unter Python gemausert. Gerade in Bezug auf Benutzerkomfort ist lxml jedoch nur schwer zu übertreffen. Neben der ElementTree kompatiblen lxml.etree API gibt es inzwischen auch noch eine weitere XML API: lxml.objectify.

lxml.objectify ist ein Werkzeug zur XML-Verarbeitung, das bestmöglich der Schnittstelle von Python-Objekten nachempfunden ist. Soll heißen: Mit lxml.objectify fühlt sich XML an wie Python. Ein einfaches Beispiel:

  >>> import lxml.etree as et
  >>> from lxml import objectify

  >>> item = objectify.Element("item")
  >>> item.title = "Best of Schmidteinander XIV"
  >>> item.price = 17.98
  >>> item.price.set("currency", "EUR")

  >>> order = objectify.Element("order")
  >>> order.customer = "Herbert Feuerstein"

  >>> order.append(item)
  >>> order.item.quantity = 3

  >>> order.price = sum(item.price * item.quantity
                                for item in order.item)

  >>> print lxml.etree.tostring(order, pretty_print=True)
  <order>
    <customer>Herbert Feuerstein</customer>
    <item>
      <title>Best of Schmidteinander XIV</title>
      <price currency="EUR">17.98</price>
      <quantity>3</quantity>
    </item>
    <price>53.94</price>
  </order>

Auffällig ist hier sicherlich, dass lxml.objectify mit allerlei Datentypen umzugehen weiß, und dass sich XML-Elemente auch wie normale Python Datentypen verhalten. Strings und Zahlen fügen sich nahtlos in sie XML-Struktur ein und natürlich ist auch die Unterstützung anderer Datentypen vorgesehen.

Noch ein bisschen einfacher wird es bald mit der E-Factory gehen, die Fredrik Lundh entwickelt hat, und die mit lxml 1.3 Einzug in lxml.etree gehalten hat. In lxml.objectify wird sie ab der nächsten Version unterstützt. Damit wird die Erzeugung von (Sub-)Elementen noch ein wenig schöner und weniger fehleranfällig:

  >>> ITEM = objectify.E.item
  >>> ORDER = objectify.E.order

  >>> item = ITEM()
  >>> item.title = "Best of Schmidteinander XIV"
  >>> order = ORDER()
  >>> order.customer = "Herbert Feuerstein"
  >>> order.append(item)

Dass lxml.objectify Strukturelemente nicht automatisch erzeugt ist durchaus gewollt. Durch die E-Factory ist dies allerdings auch kein Aufwand mehr. Ganz im Gegenteil, es wird sichtbar, wo Elemente erzeugt werden und es werden nur solche Elemente erzeugt, die in der XML-Sprache auch vorgesehen sind. So lässt sich ganz einfach vorab ein entsprechendes Element-Vokabular definieren, dass dann im Programmcode sicher verwendet werden kann.