| 1 | import xml.dom.minidom |
| 2 | |
| 3 | class node(object): |
| 4 | pass |
| 5 | |
| 6 | class text(node, unicode): |
| 7 | def __todom__(self, doc): |
| 8 | return doc.createTextNode(self) |
| 9 | |
| 10 | class raw(node, unicode): |
| 11 | def __todom__(self, doc): |
| 12 | raise Exception("Cannot convert raw code to DOM objects") |
| 13 | |
| 14 | class element(node): |
| 15 | def __init__(self, ns, name, ctx): |
| 16 | self.ns = ns |
| 17 | self.name = unicode(name) |
| 18 | self.ctx = ctx |
| 19 | self.attrs = {} |
| 20 | self.children = [] |
| 21 | |
| 22 | def __call__(self, *children, **attrs): |
| 23 | for child in children: |
| 24 | self.ctx.addchild(self, child) |
| 25 | for k, v in attrs.iteritems(): |
| 26 | self.ctx.addattr(self, k, v) |
| 27 | return self |
| 28 | |
| 29 | def __todom__(self, doc): |
| 30 | el = doc.createElementNS(self.ns, self.name) |
| 31 | for k, v in self.attrs.iteritems(): |
| 32 | el.setAttribute(k, v) |
| 33 | for child in self.children: |
| 34 | el.appendChild(child.__todom__(doc)) |
| 35 | return el |
| 36 | |
| 37 | def __str__(self): |
| 38 | doc = xml.dom.minidom.Document() |
| 39 | return self.__todom__(doc).toxml() |
| 40 | |
| 41 | class context(object): |
| 42 | def __init__(self): |
| 43 | self.nodeconv = {} |
| 44 | self.nodeconv[str] = lambda ob: text(ob, "utf-8") |
| 45 | self.nodeconv[unicode] = text |
| 46 | self.nodeconv[int] = text |
| 47 | self.nodeconv[long] = text |
| 48 | self.nodeconv[float] = text |
| 49 | |
| 50 | def nodefrom(self, ob): |
| 51 | if isinstance(ob, node): |
| 52 | return ob |
| 53 | if hasattr(ob, "__tonode__"): |
| 54 | return ob.__tonode__() |
| 55 | if type(ob) in self.nodeconv: |
| 56 | return self.nodeconv[type(ob)](ob) |
| 57 | raise Exception("No node conversion known for %s objects" % str(type(ob))) |
| 58 | |
| 59 | def addchild(self, node, child): |
| 60 | node.children.append(self.nodefrom(child)) |
| 61 | |
| 62 | def addattr(self, node, k, v): |
| 63 | if v is not None: |
| 64 | node.attrs[unicode(k)] = unicode(v) |
| 65 | |
| 66 | class constructor(object): |
| 67 | def __init__(self, ns, elcls=element, ctx=None): |
| 68 | self._ns = ns |
| 69 | self._elcls = elcls |
| 70 | if ctx is None: ctx = context() |
| 71 | self._ctx = ctx |
| 72 | |
| 73 | def __getattr__(self, name): |
| 74 | return self._elcls(self._ns, name, self._ctx) |