Commit | Line | Data |
---|---|---|
68c0eaa7 | 1 | import sys, collections.abc |
ff79cdbf FT |
2 | import xml.dom.minidom |
3 | ||
4 | class node(object): | |
d703ed47 | 5 | pass |
ff79cdbf | 6 | |
62551769 | 7 | class text(node, str): |
ff79cdbf FT |
8 | def __todom__(self, doc): |
9 | return doc.createTextNode(self) | |
10 | ||
3414365c | 11 | class raw(node, str): |
f3464a4a FT |
12 | def __todom__(self, doc): |
13 | raise Exception("Cannot convert raw code to DOM objects") | |
14 | ||
ff79cdbf FT |
15 | class element(node): |
16 | def __init__(self, ns, name, ctx): | |
17 | self.ns = ns | |
62551769 | 18 | self.name = str(name) |
ff79cdbf FT |
19 | self.ctx = ctx |
20 | self.attrs = {} | |
21 | self.children = [] | |
22 | ||
23 | def __call__(self, *children, **attrs): | |
24 | for child in children: | |
a573465e | 25 | self.ctx.addchild(self, child) |
62551769 | 26 | for k, v in attrs.items(): |
a573465e | 27 | self.ctx.addattr(self, k, v) |
ff79cdbf FT |
28 | return self |
29 | ||
30 | def __todom__(self, doc): | |
31 | el = doc.createElementNS(self.ns, self.name) | |
62551769 | 32 | for k, v in self.attrs.items(): |
ff79cdbf FT |
33 | el.setAttribute(k, v) |
34 | for child in self.children: | |
35 | el.appendChild(child.__todom__(doc)) | |
36 | return el | |
37 | ||
d703ed47 FT |
38 | def __str__(self): |
39 | doc = xml.dom.minidom.Document() | |
40 | return self.__todom__(doc).toxml() | |
41 | ||
ff79cdbf | 42 | class context(object): |
50be6d54 | 43 | charset = (sys.getfilesystemencoding() or "ascii") |
85ed5fa5 | 44 | |
ff79cdbf FT |
45 | def __init__(self): |
46 | self.nodeconv = {} | |
78449558 | 47 | self.nodeconv[bytes] = lambda ob: text(ob, self.charset) |
62551769 | 48 | self.nodeconv[str] = text |
ff79cdbf | 49 | self.nodeconv[int] = text |
ff79cdbf FT |
50 | self.nodeconv[float] = text |
51 | ||
52 | def nodefrom(self, ob): | |
53 | if isinstance(ob, node): | |
54 | return ob | |
55 | if hasattr(ob, "__tonode__"): | |
56 | return ob.__tonode__() | |
57 | if type(ob) in self.nodeconv: | |
58 | return self.nodeconv[type(ob)](ob) | |
6d764ed2 | 59 | return None |
ff79cdbf | 60 | |
a573465e | 61 | def addchild(self, node, child): |
b339a677 FT |
62 | if child is None: |
63 | return | |
6d764ed2 FT |
64 | new = self.nodefrom(child) |
65 | if new is not None: | |
8f33b1de | 66 | node.children.append(new) |
68c0eaa7 | 67 | elif isinstance(child, collections.abc.Iterable): |
6d764ed2 FT |
68 | for ch in child: |
69 | self.addchild(node, ch) | |
70 | else: | |
8f33b1de | 71 | raise Exception("No node conversion known for %s objects" % str(type(child))) |
a573465e FT |
72 | |
73 | def addattr(self, node, k, v): | |
4c4dcf7a | 74 | if v is not None: |
d38b2004 | 75 | node.attrs[str(k)] = str(v) |
a573465e | 76 | |
ff79cdbf | 77 | class constructor(object): |
9bc70dab | 78 | def __init__(self, ns, elcls=element, ctx=None): |
ff79cdbf FT |
79 | self._ns = ns |
80 | self._elcls = elcls | |
81 | if ctx is None: ctx = context() | |
82 | self._ctx = ctx | |
83 | ||
84 | def __getattr__(self, name): | |
85 | return self._elcls(self._ns, name, self._ctx) | |
fb5f9f27 FT |
86 | |
87 | class doctype(node): | |
88 | def __init__(self, rootname, pubid, dtdid): | |
89 | self.rootname = rootname | |
90 | self.pubid = pubid | |
91 | self.dtdid = dtdid |