177 lines
3.9 KiB
Python
177 lines
3.9 KiB
Python
"""xmlWriter.py -- Simple XML authoring class"""
|
|
|
|
import string
|
|
import struct
|
|
import os
|
|
|
|
INDENT = " "
|
|
|
|
|
|
class XMLWriter:
|
|
|
|
def __init__(self, fileOrPath, indentwhite=INDENT, idlefunc=None, encoding="utf-8"):
|
|
if not hasattr(fileOrPath, "write"):
|
|
self.file = open(fileOrPath, "w")
|
|
else:
|
|
# assume writable file object
|
|
self.file = fileOrPath
|
|
self.indentwhite = indentwhite
|
|
self.indentlevel = 0
|
|
self.stack = []
|
|
self.needindent = 1
|
|
self.idlefunc = idlefunc
|
|
self.idlecounter = 0
|
|
if encoding:
|
|
self.writeraw('<?xml version="1.0" encoding="%s"?>' % encoding)
|
|
else:
|
|
self.writeraw('<?xml version="1.0"?>')
|
|
self.newline()
|
|
|
|
def close(self):
|
|
self.file.close()
|
|
|
|
def write(self, data):
|
|
self.writeraw(escape(data))
|
|
|
|
def write_noindent(self, data):
|
|
self.file.write(escape(data))
|
|
|
|
def write8bit(self, data):
|
|
self.writeraw(escape8bit(data))
|
|
|
|
def write16bit(self, data):
|
|
self.writeraw(escape16bit(data))
|
|
|
|
def writeraw(self, data):
|
|
if self.needindent:
|
|
self.file.write(self.indentlevel * self.indentwhite)
|
|
self.needindent = 0
|
|
self.file.write(data)
|
|
|
|
def newline(self):
|
|
self.file.write("\n")
|
|
self.needindent = 1
|
|
idlecounter = self.idlecounter
|
|
if not idlecounter % 100 and self.idlefunc is not None:
|
|
self.idlefunc()
|
|
self.idlecounter = idlecounter + 1
|
|
|
|
def comment(self, data):
|
|
data = escape(data)
|
|
lines = string.split(data, "\n")
|
|
self.writeraw("<!-- " + lines[0])
|
|
for line in lines[1:]:
|
|
self.newline()
|
|
self.writeraw(" " + line)
|
|
self.writeraw(" -->")
|
|
|
|
def simpletag(self, _TAG_, *args, **kwargs):
|
|
attrdata = self.stringifyattrs(*args, **kwargs)
|
|
data = "<%s%s/>" % (_TAG_, attrdata)
|
|
self.writeraw(data)
|
|
|
|
def begintag(self, _TAG_, *args, **kwargs):
|
|
attrdata = self.stringifyattrs(*args, **kwargs)
|
|
data = "<%s%s>" % (_TAG_, attrdata)
|
|
self.writeraw(data)
|
|
self.stack.append(_TAG_)
|
|
self.indent()
|
|
|
|
def endtag(self, _TAG_):
|
|
assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag"
|
|
del self.stack[-1]
|
|
self.dedent()
|
|
data = "</%s>" % _TAG_
|
|
self.writeraw(data)
|
|
|
|
def dumphex(self, data):
|
|
linelength = 16
|
|
hexlinelength = linelength * 2
|
|
chunksize = 8
|
|
for i in range(0, len(data), linelength):
|
|
hexline = hexStr(data[i:i+linelength])
|
|
line = ""
|
|
white = ""
|
|
for j in range(0, hexlinelength, chunksize):
|
|
line = line + white + hexline[j:j+chunksize]
|
|
white = " "
|
|
self.writeraw(line)
|
|
self.newline()
|
|
|
|
def indent(self):
|
|
self.indentlevel = self.indentlevel + 1
|
|
|
|
def dedent(self):
|
|
assert self.indentlevel > 0
|
|
self.indentlevel = self.indentlevel - 1
|
|
|
|
def stringifyattrs(self, *args, **kwargs):
|
|
if kwargs:
|
|
assert not args
|
|
attributes = kwargs.items()
|
|
attributes.sort()
|
|
elif args:
|
|
assert len(args) == 1
|
|
attributes = args[0]
|
|
else:
|
|
return ""
|
|
data = ""
|
|
for attr, value in attributes:
|
|
data = data + ' %s="%s"' % (attr, escapeattr(str(value)))
|
|
return data
|
|
|
|
|
|
def escape(data):
|
|
data = string.replace(data, "&", "&")
|
|
data = string.replace(data, "<", "<")
|
|
return data
|
|
|
|
def escapeattr(data):
|
|
data = string.replace(data, "&", "&")
|
|
data = string.replace(data, "<", "<")
|
|
data = string.replace(data, '"', """)
|
|
return data
|
|
|
|
def escape8bit(data):
|
|
def escapechar(c):
|
|
n = ord(c)
|
|
if c in "<&":
|
|
if c == "&":
|
|
return "&"
|
|
else:
|
|
return "<"
|
|
elif 32 <= n <= 127:
|
|
return c
|
|
else:
|
|
return "&#" + repr(n) + ";"
|
|
return string.join(map(escapechar, data), "")
|
|
|
|
needswap = struct.pack("h", 1) == "\001\000"
|
|
|
|
def escape16bit(data):
|
|
import array
|
|
a = array.array("H")
|
|
a.fromstring(data)
|
|
if needswap:
|
|
a.byteswap()
|
|
def escapenum(n, amp=ord("&"), lt=ord("<")):
|
|
if n == amp:
|
|
return "&"
|
|
elif n == lt:
|
|
return "<"
|
|
elif 32 <= n <= 127:
|
|
return chr(n)
|
|
else:
|
|
return "&#" + repr(n) + ";"
|
|
return string.join(map(escapenum, a), "")
|
|
|
|
|
|
def hexStr(s):
|
|
h = string.hexdigits
|
|
r = ''
|
|
for c in s:
|
|
i = ord(c)
|
|
r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
|
|
return r
|
|
|