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