summaryrefslogtreecommitdiff
path: root/source/node.py
blob: 6b1d62e323786ebb894beed107c525ca5f9e9928 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# This file (node.py) gets copied in several of my projects.  Find out a way 
# to avoid making duplicate copies in each of my projects.

import sys

class NodeType:
    # unknown node type.
    Unknown = 0
    # the document root - typically has only one child element, but it can 
    # have multiple children.
    Root    = 1 
    # node that has name and attributes, and may have child nodes.
    Element = 2
    # node that only has textural content.
    Content = 3

class NodeBase:
    def __init__ (self, nodeType = NodeType.Unknown):
        self.parent = None
        self.nodeType = nodeType

        self.__children = []
        self.__hasContent = False

    def appendChild (self, node):
        self.__children.append(node)
        node.parent = self

    def appendElement (self, name):
        node = Element(name)
        self.appendChild(node)
        return node

    def hasContent (self):
        return self.__hasContent

    def appendContent (self, text):
        node = Content(text)
        self.appendChild(node)
        self.__hasContent = True
        return node

    def firstChild (self):
        return self.__children[0]

    def setChildNodes (self, children):
        self.__children = children

    def getChildNodes (self):
        return self.__children

    def firstChildByName (self, name):
        for child in self.__children:
            if child.nodeType == NodeType.Element and child.name == name:
                return child
        return None

    def getChildByName (self, name):
        children = []
        for child in self.__children:
            if child.nodeType == NodeType.Element and child.name == name:
                children.append(child)
        return children

class Root(NodeBase):
    def __init__ (self):
        NodeBase.__init__(self, NodeType.Root)

class Content(NodeBase):
    def __init__ (self, content):
        NodeBase.__init__(self, NodeType.Content)
        self.content = content

class Element(NodeBase):
    def __init__ (self, name, attrs=None):
        NodeBase.__init__(self, NodeType.Element)
        self.name = name
        self.attrs = attrs
        if self.attrs == None:
            self.attrs = {}

    def getContent (self):
        text = ''
        first = True
        for child in self.getChildNodes():
            if first:
                first = False
            else:
                text += ' '
            if child.nodeType == NodeType.Content:
                text += child.content
            elif child.nodeType == NodeType.Element:
                text += child.getContent()
        return text

    def getAttr (self, name):
        if not self.attrs.has_key(name):
            return None
        return self.attrs[name]

    def setAttr (self, name, val):
        self.attrs[name] = val

    def hasAttr (self, name):
        return self.attrs.has_key(name)

encodeTable = {
    '>': 'gt',
    '<': 'lt',
    '&': 'amp',
    '"': 'quot',
    '\'': 'apos'
}

def encodeString (sin):
    sout = ''
    for c in sin:
        if ord(c) >= 128:
            # encode non-ascii ranges.
            sout += "\\x%2.2x"%ord(c)
        elif encodeTable.has_key(c):
            # encode html symbols.
            sout += '&' + encodeTable[c] + ';'
        else:
            sout += c

    return sout

def convertAttrValue (val):
    if type(val) == type(True):
        if val:
            val = "true"
        else:
            val = "false"
    elif type(val) == type(0):
        val = "%d"%val
    elif type(val) == type(0.0):
        val = "%g"%val

    return val

def prettyPrint (fd, node):
    printNode(fd, node, 0, True)

def printNode (fd, node, level, breakLine):
    singleIndent = ''
    lf = ''
    if breakLine:
        singleIndent = ' '*4
        lf = "\n"
    indent = singleIndent*level
    if node.nodeType == NodeType.Root:
        # root node itself only contains child nodes.
        for child in node.getChildNodes():
            printNode(fd, child, level, True)
    elif node.nodeType == NodeType.Element:
        hasChildren = len(node.getChildNodes()) > 0

        # We add '<' and '>' (or '/>') after the element content gets 
        # encoded.
        line = node.name
        if len(node.attrs) > 0:
            keys = node.attrs.keys()
            keys.sort()
            for key in keys:
                val = node.attrs[key]
                if val == None:
                    continue
                val = convertAttrValue(val)
                line += " " + key + '="' + encodeString(val) + '"'

        if hasChildren:
            breakChildren = breakLine and not node.hasContent()
            line = "<%s>"%line
            if breakChildren:
                line += "\n"
            fd.write (indent + line)
            for child in node.getChildNodes():
                printNode(fd, child, level+1, breakChildren)
            line = "</%s>%s"%(node.name, lf)
            if breakChildren:
                line = indent + line
            fd.write (line)
        else:
            line = "<%s/>%s"%(line, lf)
            fd.write (indent + line)

    elif node.nodeType == NodeType.Content:
        content = node.content
        content = encodeString(content)
        if len(content) > 0:
            fd.write (indent + content + lf)