]> git.sesse.net Git - xml-template/blob - python/xmltemplate.py
16225926876eef7dc95791a7c40401af6681b707
[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                                 attrs_to_remove = []
36                                 if not attrs is None:
37                                         for i in range(attrs.length):
38                                                 attr = attrs.item(0)
39                                                 if attr.namespaceURI == "http://template.sesse.net/" and attr.localName == "id":
40                                                         id = attr.value
41                                                         if clean:
42                                                                 attrs_to_remove.append(attr.name)
43                                                 if attr.name.startswith("xmlns:") and attr.value == "http://template.sesse.net/" and clean:
44                                                         attrs_to_remove.append(attr.name)
45
46                                         for a in attrs_to_remove:
47                                                 if child.hasAttribute(a):
48                                                         child.removeAttribute(a)
49
50
51                                 # check all substitutions to see if we found anything
52                                 # appropriate
53                                 for key in obj.keys():
54                                         if key.startswith(child.tagName + "/"):
55                                                 child.setAttribute(key.split("/")[1], obj[key])
56                                         elif (not id is None) and key.startswith("#" + id + "/"):
57                                                 child.setAttribute(key.split("/")[1], obj[key])
58
59                                         if not processed:
60                                                 if key == child.localName or ((not id is None) and key == "#" + id):
61                                                         process(child, obj[key], clean)
62                                                         processed = True
63
64                         if not processed:
65                                 process(child, obj, clean)
66         elif isinstance(obj, list):                     # repeat
67                 doc = _get_document_element(node)
68                 frag = doc.createElement("temporary-fragment")     # ugh
69
70                 while not node.firstChild is None:
71                         child = node.firstChild
72                         node.removeChild(child)
73                         frag.appendChild(child)
74
75                 for instance in obj:
76                         if instance is not None:
77                                 newnode = frag.cloneNode(True)
78                                 node.appendChild(newnode)
79                                 process(newnode, instance, clean)
80                                 if clean:
81                                         _clean(newnode)
82
83                 # remove all the <fragment> tags
84
85                 children_to_remove = []
86                 for child in node.childNodes:
87                         if isinstance(child, xml.dom.minidom.Element) and child.tagName == 'temporary-fragment':
88                                 while not child.firstChild is None:
89                                         child2 = child.firstChild
90                                         child.removeChild(child2)
91                                         node.appendChild(child2)
92                                 children_to_remove.append(child)
93
94                 for child in children_to_remove:
95                         node.removeChild(child)
96
97         if clean:
98                 _clean(node)
99
100 def alternate(tag, array, *elems):
101         i = 0
102         for ref in array:
103                 if ref is not None:
104                         ref[tag] = elems[i % len(elems)]
105                         i = i + 1
106                 
107         return array
108
109 def _clean(node):
110         if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.namespaceURI == "http://template.sesse.net/":
111                 # as this is a dummy node, we want to remove it and move everything further up
112                 # after we've done any required replacements
113                 doc = _get_document_element(node)
114                 parent = node.parentNode
115
116                 while not node.firstChild is None:
117                         child = node.firstChild
118                         node.removeChild(child)
119                         parent.insertBefore(child, node)
120
121                 parent.removeChild(node)
122
123 # ugh
124 def _get_document_element(node):
125         if node.parentNode is None:
126                 return node
127         else:
128                 return _get_document_element(node.parentNode)