]> git.sesse.net Git - xml-template/blob - python/xmltemplate.py
Implement alternate() in Python. All Python tests pass!
[xml-template] / python / xmltemplate.py
1 #! /usr/bin/python
2 import re
3 import xml.dom.minidom
4
5 def process_file(filename, obj, clean = True):
6         doc = xml.dom.minidom.parse(filename)
7         process(doc, obj, clean)
8         return doc
9
10 def process(node, obj, clean = True):
11         if isinstance(obj, str):                        # overwrite
12                 while not node.firstChild is None:
13                         node.removeChild(node.firstChild)
14                 doc = _get_document_element(node)
15                 node.appendChild(doc.createTextNode(obj))
16         elif isinstance(obj, xml.dom.Node):             # overwrite
17                 while not node.firstChild is None:
18                         node.removeChild(node.firstChild)
19
20                 if isinstance(obj, xml.dom.minidom.Document):
21                         obj = obj.documentElement
22
23                 newobj = obj.cloneNode(True)
24                 node.appendChild(newobj)
25
26                 process(newobj, {}, clean)
27         elif isinstance(obj, dict):                     # substitute
28                 for child in node.childNodes:
29                         processed = False
30
31                         if child.nodeType == xml.dom.Node.ELEMENT_NODE:
32                                 id = None
33
34                                 attrs = child.attributes
35                                 if not attrs is None:
36                                         for i in range(attrs.length):
37                                                 attr = attrs.item(0)
38                                                 if attr.namespaceURI == "http://template.sesse.net/" or attr.name == "id":
39                                                         id = attr.value
40                                                         if clean:
41                                                                 child.removeAttribute(attr.name)
42
43                                 # check all substitutions to see if we found anything
44                                 # appropriate
45                                 for key in obj.keys():
46                                         if key.startswith(child.tagName + "/"):
47                                                 child.setAttribute(key.split("/")[1], obj[key])
48                                         elif (not id is None) and key.startswith("#" + id + "/"):
49                                                 child.setAttribute(key.split("/")[1], obj[key])
50
51                                         if not processed:
52                                                 if key == child.localName or ((not id is None) and key == "#" + id):
53                                                         process(child, obj[key], clean)
54                                                         processed = True
55
56                         if not processed:
57                                 process(child, obj, clean)
58         elif isinstance(obj, list):                     # repeat
59                 doc = _get_document_element(node)
60                 frag = doc.createElement("temporary-fragment")     # ugh
61
62                 while not node.firstChild is None:
63                         child = node.firstChild
64                         node.removeChild(child)
65                         frag.appendChild(child)
66
67                 for instance in obj:
68                         newnode = frag.cloneNode(True)
69                         node.appendChild(newnode)
70                         process(newnode, instance, clean)
71                         if clean:
72                                 _clean(newnode)
73
74                 # remove all the <fragment> tags
75
76                 children_to_remove = []
77                 for child in node.childNodes:
78                         if isinstance(child, xml.dom.minidom.Element) and child.tagName == 'temporary-fragment':
79                                 while not child.firstChild is None:
80                                         child2 = child.firstChild
81                                         child.removeChild(child2)
82                                         node.appendChild(child2)
83                                 children_to_remove.append(child)
84
85                 for child in children_to_remove:
86                         node.removeChild(child)
87
88         if clean:
89                 _clean(node)
90
91 def alternate(tag, array, *elems):
92         i = 0
93         for ref in array:
94                 ref[tag] = elems[i % len(elems)]
95                 i = i + 1
96                 
97         return array
98
99 def _clean(node):
100         if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.namespaceURI == "http://template.sesse.net/":
101                 # as this is a dummy node, we want to remove it and move everything further up
102                 # after we've done any required replacements
103                 doc = _get_document_element(node)
104                 parent = node.parentNode
105
106                 while not node.firstChild is None:
107                         child = node.firstChild
108                         node.removeChild(child)
109                         parent.insertBefore(child, node)
110
111                 parent.removeChild(node)
112
113 # ugh
114 def _get_document_element(node):
115         if node.parentNode is None:
116                 return node
117         else:
118                 return _get_document_element(node.parentNode)