blob: ab72ba774bdcda6e1c734c10ade3b830d837e80f [file] [log] [blame]
Just7842e561999-12-16 21:34:53 +00001"""xmlWriter.py -- Simple XML authoring class"""
2
3__author__ = "jvr"
4__version__ = "0.9"
5
6import string
7import struct
Juste414c922000-01-04 13:51:59 +00008import os
Just7842e561999-12-16 21:34:53 +00009
10INDENT = " "
11
12class XMLWriter:
13
jvr33f33272002-07-23 16:41:08 +000014 def __init__(self, file, indentwhite=INDENT, idlefunc=None):
Just7842e561999-12-16 21:34:53 +000015 if type(file) == type(""):
16 self.file = open(file, "w")
Juste414c922000-01-04 13:51:59 +000017 if os.name == "mac":
18 import macfs
19 macfs.FSSpec(file).SetCreatorType('R*ch', 'TEXT')
Just7842e561999-12-16 21:34:53 +000020 else:
21 # assume writable file object
22 self.file = file
Just7842e561999-12-16 21:34:53 +000023 self.indentwhite = indentwhite
24 self.indentlevel = 0
25 self.stack = []
26 self.needindent = 1
jvr33f33272002-07-23 16:41:08 +000027 self.idlefunc = idlefunc
28 self.idlecounter = 0
Just7842e561999-12-16 21:34:53 +000029 self.writeraw("<?xml version='1.0'?>")
30 self.newline()
Just7842e561999-12-16 21:34:53 +000031
32 def close(self):
33 self.file.close()
34
35 def write(self, data):
36 self.writeraw(escape(data))
37
38 def write_noindent(self, data):
39 self.file.write(escape(data))
40
41 def write8bit(self, data):
42 self.writeraw(escape8bit(data))
43
44 def write16bit(self, data):
45 self.writeraw(escape16bit(data))
46
47 def writeraw(self, data):
48 if self.needindent:
49 self.file.write(self.indentlevel * self.indentwhite)
50 self.needindent = 0
51 self.file.write(data)
52
53 def newline(self):
54 self.file.write("\n")
55 self.needindent = 1
jvr33f33272002-07-23 16:41:08 +000056 idlecounter = self.idlecounter
57 if not idlecounter % 100 and self.idlefunc is not None:
58 self.idlefunc()
59 self.idlecounter = idlecounter + 1
Just7842e561999-12-16 21:34:53 +000060
61 def comment(self, data):
62 data = escape(data)
63 lines = string.split(data, "\n")
64 self.writeraw("<!-- " + lines[0])
65 for line in lines[1:]:
66 self.newline()
67 self.writeraw(" " + line)
68 self.writeraw(" -->")
69
70 def simpletag(self, _TAG_, *args, **kwargs):
71 attrdata = apply(self.stringifyattrs, args, kwargs)
72 data = "<%s%s/>" % (_TAG_, attrdata)
73 self.writeraw(data)
74
75 def begintag(self, _TAG_, *args, **kwargs):
76 attrdata = apply(self.stringifyattrs, args, kwargs)
77 data = "<%s%s>" % (_TAG_, attrdata)
78 self.writeraw(data)
79 self.stack.append(_TAG_)
80 self.indent()
81
82 def endtag(self, _TAG_):
83 assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag"
84 del self.stack[-1]
85 self.dedent()
86 data = "</%s>" % _TAG_
87 self.writeraw(data)
88
89 def dumphex(self, data):
90 linelength = 16
91 hexlinelength = linelength * 2
92 chunksize = 8
93 for i in range(0, len(data), linelength):
94 hexline = hexStr(data[i:i+linelength])
95 line = ""
96 white = ""
97 for j in range(0, hexlinelength, chunksize):
98 line = line + white + hexline[j:j+chunksize]
99 white = " "
100 self.writeraw(line)
101 self.newline()
102
103 def indent(self):
104 self.indentlevel = self.indentlevel + 1
105
106 def dedent(self):
107 assert self.indentlevel > 0
108 self.indentlevel = self.indentlevel - 1
109
110 def stringifyattrs(self, *args, **kwargs):
111 if kwargs:
112 assert not args
113 attributes = kwargs.items()
114 attributes.sort()
115 elif args:
116 assert len(args) == 1
117 attributes = args[0]
118 else:
119 return ""
120 data = ""
121 for attr, value in attributes:
122 data = data + ' %s="%s"' % (attr, escapeattr(str(value)))
123 return data
124
125
126def escape(data):
127 data = string.replace(data, "&", "&amp;")
128 data = string.replace(data, "<", "&lt;")
129 return data
130
131def escapeattr(data):
132 data = string.replace(data, "&", "&amp;")
133 data = string.replace(data, "<", "&lt;")
134 data = string.replace(data, '"', "&quot;")
135 return data
136
137def escape8bit(data):
138 def escapechar(c):
139 n = ord(c)
140 if c in "<&":
141 if c == "&":
142 return "&amp;"
143 else:
144 return "&lt;"
145 elif 32 <= n <= 127:
146 return c
147 else:
148 return "&#" + `n` + ";"
149 return string.join(map(escapechar, data), "")
150
151needswap = struct.pack("h", 1) == "\001\000"
152
153def escape16bit(data):
154 import array
155 a = array.array("H")
156 a.fromstring(data)
157 if needswap:
158 a.byteswap()
159 def escapenum(n, amp=ord("&"), lt=ord("<")):
160 if n == amp:
161 return "&amp;"
162 elif n == lt:
163 return "&lt;"
164 elif 32 <= n <= 127:
165 return chr(n)
166 else:
167 return "&#" + `n` + ";"
168 return string.join(map(escapenum, a), "")
169
170
171def hexStr(s):
172 h = string.hexdigits
173 r = ''
174 for c in s:
175 i = ord(c)
176 r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
177 return r
178