blob: 499341fbf7021cc1408006fe9379843c2befaac1 [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
14 def __init__(self, file, dtd=None, indentwhite=INDENT):
15 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
23 self.dtd = dtd
24 self.indentwhite = indentwhite
25 self.indentlevel = 0
26 self.stack = []
27 self.needindent = 1
28 self.writeraw("<?xml version='1.0'?>")
29 self.newline()
30 if self.dtd:
31 # DOCTYPE???
32 self.newline()
33
34 def close(self):
35 self.file.close()
36
37 def write(self, data):
38 self.writeraw(escape(data))
39
40 def write_noindent(self, data):
41 self.file.write(escape(data))
42
43 def write8bit(self, data):
44 self.writeraw(escape8bit(data))
45
46 def write16bit(self, data):
47 self.writeraw(escape16bit(data))
48
49 def writeraw(self, data):
50 if self.needindent:
51 self.file.write(self.indentlevel * self.indentwhite)
52 self.needindent = 0
53 self.file.write(data)
54
55 def newline(self):
56 self.file.write("\n")
57 self.needindent = 1
58
59 def comment(self, data):
60 data = escape(data)
61 lines = string.split(data, "\n")
62 self.writeraw("<!-- " + lines[0])
63 for line in lines[1:]:
64 self.newline()
65 self.writeraw(" " + line)
66 self.writeraw(" -->")
67
68 def simpletag(self, _TAG_, *args, **kwargs):
69 attrdata = apply(self.stringifyattrs, args, kwargs)
70 data = "<%s%s/>" % (_TAG_, attrdata)
71 self.writeraw(data)
72
73 def begintag(self, _TAG_, *args, **kwargs):
74 attrdata = apply(self.stringifyattrs, args, kwargs)
75 data = "<%s%s>" % (_TAG_, attrdata)
76 self.writeraw(data)
77 self.stack.append(_TAG_)
78 self.indent()
79
80 def endtag(self, _TAG_):
81 assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag"
82 del self.stack[-1]
83 self.dedent()
84 data = "</%s>" % _TAG_
85 self.writeraw(data)
86
87 def dumphex(self, data):
88 linelength = 16
89 hexlinelength = linelength * 2
90 chunksize = 8
91 for i in range(0, len(data), linelength):
92 hexline = hexStr(data[i:i+linelength])
93 line = ""
94 white = ""
95 for j in range(0, hexlinelength, chunksize):
96 line = line + white + hexline[j:j+chunksize]
97 white = " "
98 self.writeraw(line)
99 self.newline()
100
101 def indent(self):
102 self.indentlevel = self.indentlevel + 1
103
104 def dedent(self):
105 assert self.indentlevel > 0
106 self.indentlevel = self.indentlevel - 1
107
108 def stringifyattrs(self, *args, **kwargs):
109 if kwargs:
110 assert not args
111 attributes = kwargs.items()
112 attributes.sort()
113 elif args:
114 assert len(args) == 1
115 attributes = args[0]
116 else:
117 return ""
118 data = ""
119 for attr, value in attributes:
120 data = data + ' %s="%s"' % (attr, escapeattr(str(value)))
121 return data
122
123
124def escape(data):
125 data = string.replace(data, "&", "&amp;")
126 data = string.replace(data, "<", "&lt;")
127 return data
128
129def escapeattr(data):
130 data = string.replace(data, "&", "&amp;")
131 data = string.replace(data, "<", "&lt;")
132 data = string.replace(data, '"', "&quot;")
133 return data
134
135def escape8bit(data):
136 def escapechar(c):
137 n = ord(c)
138 if c in "<&":
139 if c == "&":
140 return "&amp;"
141 else:
142 return "&lt;"
143 elif 32 <= n <= 127:
144 return c
145 else:
146 return "&#" + `n` + ";"
147 return string.join(map(escapechar, data), "")
148
149needswap = struct.pack("h", 1) == "\001\000"
150
151def escape16bit(data):
152 import array
153 a = array.array("H")
154 a.fromstring(data)
155 if needswap:
156 a.byteswap()
157 def escapenum(n, amp=ord("&"), lt=ord("<")):
158 if n == amp:
159 return "&amp;"
160 elif n == lt:
161 return "&lt;"
162 elif 32 <= n <= 127:
163 return chr(n)
164 else:
165 return "&#" + `n` + ";"
166 return string.join(map(escapenum, a), "")
167
168
169def hexStr(s):
170 h = string.hexdigits
171 r = ''
172 for c in s:
173 i = ord(c)
174 r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
175 return r
176