Skip to content

Instantly share code, notes, and snippets.

@simon-engledew
Created September 8, 2011 14:09
Show Gist options
  • Save simon-engledew/1203486 to your computer and use it in GitHub Desktop.
Save simon-engledew/1203486 to your computer and use it in GitHub Desktop.
Python magic to concisely generate XML
import xml.dom.minidom as xml
class Document(object):
"""
XML Document Builder
@author Simon Engledew
example:
dom = Document.catalog(version="1.0")
dom.book(
dom.name("The Pragmatic Programmer"),
dom.author("Andrew Hunt and David Thomas"),
dom['publish-date']("20 Oct 1999"),
id="1"
)
print str(dom)
output:
<?xml version="1.0" encoding="utf-8"?>
<catalog version="1.0">
<book id="1">
<name>The Pragmatic Programmer</name>
<author>Andrew Hunt and David Thomas</author>
<publish_date>20 Oct 1999</publish_date>
</book>
</catalog>
"""
class MetaClass(type):
def __getattr__(self, tagname, *args, **attributes):
return lambda *args, **attributes: Document(tagname, *args, **attributes)
def __dir__(self):
return ['__getitem__', '__getattr__', '__str__', '__unicode__', '__root__']
__metaclass__=MetaClass
class Element(object):
def __init__(self, document, tagname):
self.__document__ = document
self.__document__.start_element(tagname)
def element(self, *args, **attributes):
for value in (o for o in args if o is not None):
if not isinstance(value, Document.Element):
self.__document__.append_text_node(unicode(value))
self.__document__.append_attributes(attributes)
self.__document__.end_element()
return self
@property
def __root__(self):
return self.__stack__[-1]
def start_element(self, tagname):
element = self.__dom__.createElement(tagname)
self.__root__.appendChild(element)
self.__stack__.append(element)
return element
def append_attributes(self, attributes):
for key, value in attributes.items():
self.__root__.setAttribute(key, unicode(value))
def append_text_node(self, value):
self.__root__.appendChild(self.__dom__.createTextNode(unicode(value)))
def end_element(self):
self.__stack__.pop()
def __init__(self, tagname, *args, **attributes):
self.__dom__ = xml.getDOMImplementation().createDocument(None, tagname, None)
self.__stack__ = []
self.__stack__.append(self.__dom__.documentElement)
self.append_attributes(attributes)
for value in (o for o in args if o is not None):
if not isinstance(value, Document.Element):
self.append_text_node(unicode(value))
def __getitem__(self, tagname):
return self.__getattr__(tagname)
def __getattr__(self, tagname):
return Document.Element(self, tagname).element
def __str__(self, encoding='utf-8'):
return self.__dom__.toxml(encoding=encoding)
def __unicode__(self, encoding='utf-8'):
return self.__str__(encoding).decode(encoding)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment