Project

General

Profile

1 21 aaronmk
# XML DOM tree manipulation
2
3
from xml.dom import Node
4 28 aaronmk
import xml.dom.minidom
5 21 aaronmk
6
def name_of(node): return node.tagName.lower()
7
8
def get_id(node): return node.getAttribute('id')
9
10
def set_id(node, id_): node.setAttribute('id', id_)
11
12
class NodeElemIter:
13
    def __init__(self, node): self.child = node.firstChild
14
15
    def __iter__(self): return self
16
17
    def curr(self):
18
        while self.child != None:
19
            if self.child.nodeType == Node.ELEMENT_NODE: return self.child
20
            self.child = self.child.nextSibling
21
        raise StopIteration
22
23
    def next(self):
24
        child = self.curr()
25
        self.child = self.child.nextSibling
26
        return child
27
28
def first_elem(node): return NodeElemIter(node).next()
29
30
class NodeElemReverseIter:
31
    def __init__(self, node): self.child = node.lastChild
32
33
    def __iter__(self): return self
34
35
    def curr(self):
36
        while self.child != None:
37
            if self.child.nodeType == Node.ELEMENT_NODE: return self.child
38
            self.child = self.child.previousSibling
39
        raise StopIteration
40
41
    def next(self):
42
        child = self.curr()
43
        self.child = self.child.previousSibling
44
        return child
45
46
def last_elem(node): return NodeElemReverseIter(node).next()
47
48
class NodeParentIter:
49
    def __init__(self, node): self.node = node
50
51
    def __iter__(self): return self
52
53
    def curr(self):
54
        if self.node != None and self.node.nodeType == Node.ELEMENT_NODE:
55
            return self.node
56
        raise StopIteration
57
58
    def next(self):
59
        node = self.curr()
60
        self.node = self.node.parentNode
61
        return node
62
63
def is_text(node):
64
    for child in NodeElemIter(node): return False # has an element node
65
    return True
66
67
def value(node):
68 29 aaronmk
    if node.firstChild != None: return node.firstChild.nodeValue
69 21 aaronmk
    else: return node.nodeValue
70
71 22 aaronmk
def set_value(doc, node, value):
72
    if node.nodeType == Node.ELEMENT_NODE:
73
        node.appendChild(doc.createTextNode(value))
74
    else: node.nodeValue = value
75
76
def by_tag_name(node, name, last_only=False):
77 23 aaronmk
    # last_only optimization returns last (most recently inserted) matching node
78 22 aaronmk
    children = []
79 21 aaronmk
    for child in NodeElemReverseIter(node):
80 22 aaronmk
        if child.tagName == name:
81
            children.append(child)
82
            if last_only: break
83
    return children
84 28 aaronmk
85
_writexml_orig = xml.dom.minidom.Element.writexml
86
87
def _writexml(self, writer, indent="", addindent="", newl=""):
88 36 aaronmk
    if self.firstChild != None and self.firstChild.nextSibling == None\
89
    and self.firstChild.nodeType == Node.TEXT_NODE: # a single text node
90 28 aaronmk
        writer.write(indent+'<'+self.tagName)
91
        for attr_idx in range(self.attributes.length):
92
            attr = self.attributes.item(attr_idx)
93
            writer.write(' '+attr.name+'='+attr.value)
94
        writer.write('>'+value(self)+'</'+self.tagName+'>'+newl)
95
    else: _writexml_orig(self, writer, indent, addindent, newl)
96
97
xml.dom.minidom.Element.writexml = _writexml