August 5, 2011

Jonas Galvez: XMLWitch

xmlwitch is a Python 2.5+ library that offers idiomatic XML generation through context managers in a minimalist implementation with less than 100 lines of code. BSD-licensed

Download latest release (0.2.1). Follow development on GitHub.

To install, just run pip install xmlwitch, easy_install xmlwitch or copy xmlwitch.py to your appropriate project’s directory. It’s just one file.

In a nutshell, xmlwitch lets you generate XML using code like this:

from __future__ import with_statement # <Py2.6 import xmlwitch xml = xmlwitch.Builder(version='1.0', encoding='utf-8') with xml.feed(xmlns='http://www.w3.org/2005/Atom'): xml.title('Example Feed') xml.updated('2003-12-13T18:30:02Z') with xml.author: xml.name('John Doe') xml.id('urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6') with xml.entry: xml.title('Atom-Powered Robots Run Amok') xml.id('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a') xml.updated('2003-12-13T18:30:02Z') xml.summary('Some text.') print(xml)

xmlwitch has two classes: Builder and Element. Builder takes three parameters: encoding, which is required and defaulted to UTF-8; version, whose optional presence adds a <?xml?> processing instruction at the top of the document; and indent, which determines the white-space string used to indent the document tree (defaulted to two spaces). xmlwitch currently only generates human-readable XML documents, with linebreaks and indentation.

Builder holds the document and its metadata (encoding and XML version, if set). Element (not directly exposed) takes two parameters: name and builder. When trying to access an attribute or item of a Builder instance, an Element instance is returned representing an XML element named after the attribute or item requested. This is done with overridden __getattr__() and __getitem__() methods in Builder. A reference (builder) to the originating Builder instance is also passed along and kept in the Element instance.

Element implements a __call__() method which has a flexible parameter signature. The first parameter, if present, indicates the content of the element. If explicitly set to None, it indicates an empty element. Not setting the first parameter at all indicates the element is wrapping child elements in a with statement. Also, all content needs to be passed as a string since xmlwitch does not automatically convert them.

>>> xml = xmlwitch.Builder() >>> with xml.parent(foo='1'): ...     xml.child('text', bar='2') ...     xml.empty(None, baz='3') ...  >>> print(xml) <parent foo="1"> <child bar="2">text</child> <empty baz="3" /> </parent>
Namespaced elements can be created by using square brackets (item access) on a Builder instance, or replacing the colons with two underscores (thanks to a commit by Beat Bolli). The same applies to attribute names: you can unpack an inline dictionary as the keyword arguments of Element.__call__() or just replace the colons in attribute names with two underscores:
with xml.parent(**{'xmlns:my':'http://example.org/ns/'}): xml.my__child(None, my__attr='foo')

In the snippet above, the attributes for the <parent> element are defined by unpacking an inline dictionary (and thus using quotes to define argument names). In contrast, both the element’s name itself and its attributes are defined using two underscores to indicate colons.

Similarly, Python reserved words (for, in etc) can be used as element names or attribute names without resorting to square brackets or inline dictionaries by adding an underscore at the end:

xml.message(None, for_=user.name, content="Hello!")

Please submit any bug reports via GitHub.

Last updated: January 2, 2011.

Cool python xml writing module!