xmlWriter.py revision 14fb031125b773f0a15eb19be4f02ed8540b2db6
17842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""xmlWriter.py -- Simple XML authoring class""" 27842e56b97ce677b83bdab09cda48bc2d89ac75aJust 37842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport string 47842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport struct 5e414c92045cee859cd5bd76610c5819c5ec8c68bJustimport os 67842e56b97ce677b83bdab09cda48bc2d89ac75aJust 77842e56b97ce677b83bdab09cda48bc2d89ac75aJustINDENT = " " 87842e56b97ce677b83bdab09cda48bc2d89ac75aJust 981b0c2b659aec8df184d09c0d7ab069956b87b28jvr 107842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass XMLWriter: 117842e56b97ce677b83bdab09cda48bc2d89ac75aJust 124b3df49b5b70b3618e91e3ab954cedca773831d6Behdad Esfahbod def __init__(self, fileOrPath, indentwhite=INDENT, idlefunc=None, encoding="utf-8"): 1390beb95b77fdef99cad25354f36bf615d2042197jvr if not hasattr(fileOrPath, "write"): 1490beb95b77fdef99cad25354f36bf615d2042197jvr self.file = open(fileOrPath, "w") 157842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 167842e56b97ce677b83bdab09cda48bc2d89ac75aJust # assume writable file object 1790beb95b77fdef99cad25354f36bf615d2042197jvr self.file = fileOrPath 187842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.indentwhite = indentwhite 197842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.indentlevel = 0 207842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.stack = [] 217842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.needindent = 1 2233f3327ad74d4550ee48ce85ce52a7374e55b997jvr self.idlefunc = idlefunc 2333f3327ad74d4550ee48ce85ce52a7374e55b997jvr self.idlecounter = 0 2481b0c2b659aec8df184d09c0d7ab069956b87b28jvr if encoding: 2581b0c2b659aec8df184d09c0d7ab069956b87b28jvr self.writeraw('<?xml version="1.0" encoding="%s"?>' % encoding) 2681b0c2b659aec8df184d09c0d7ab069956b87b28jvr else: 2781b0c2b659aec8df184d09c0d7ab069956b87b28jvr self.writeraw('<?xml version="1.0"?>') 287842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.newline() 297842e56b97ce677b83bdab09cda48bc2d89ac75aJust 307842e56b97ce677b83bdab09cda48bc2d89ac75aJust def close(self): 317842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.file.close() 327842e56b97ce677b83bdab09cda48bc2d89ac75aJust 337842e56b97ce677b83bdab09cda48bc2d89ac75aJust def write(self, data): 347842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(escape(data)) 357842e56b97ce677b83bdab09cda48bc2d89ac75aJust 367842e56b97ce677b83bdab09cda48bc2d89ac75aJust def write_noindent(self, data): 377842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.file.write(escape(data)) 387842e56b97ce677b83bdab09cda48bc2d89ac75aJust 397842e56b97ce677b83bdab09cda48bc2d89ac75aJust def write8bit(self, data): 407842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(escape8bit(data)) 417842e56b97ce677b83bdab09cda48bc2d89ac75aJust 427842e56b97ce677b83bdab09cda48bc2d89ac75aJust def write16bit(self, data): 437842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(escape16bit(data)) 447842e56b97ce677b83bdab09cda48bc2d89ac75aJust 457842e56b97ce677b83bdab09cda48bc2d89ac75aJust def writeraw(self, data): 467842e56b97ce677b83bdab09cda48bc2d89ac75aJust if self.needindent: 477842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.file.write(self.indentlevel * self.indentwhite) 487842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.needindent = 0 497842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.file.write(data) 507842e56b97ce677b83bdab09cda48bc2d89ac75aJust 517842e56b97ce677b83bdab09cda48bc2d89ac75aJust def newline(self): 527842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.file.write("\n") 537842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.needindent = 1 5433f3327ad74d4550ee48ce85ce52a7374e55b997jvr idlecounter = self.idlecounter 5533f3327ad74d4550ee48ce85ce52a7374e55b997jvr if not idlecounter % 100 and self.idlefunc is not None: 5633f3327ad74d4550ee48ce85ce52a7374e55b997jvr self.idlefunc() 5733f3327ad74d4550ee48ce85ce52a7374e55b997jvr self.idlecounter = idlecounter + 1 587842e56b97ce677b83bdab09cda48bc2d89ac75aJust 597842e56b97ce677b83bdab09cda48bc2d89ac75aJust def comment(self, data): 607842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = escape(data) 6114fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod lines = data.split("\n") 627842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw("<!-- " + lines[0]) 637842e56b97ce677b83bdab09cda48bc2d89ac75aJust for line in lines[1:]: 647842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.newline() 657842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(" " + line) 667842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(" -->") 677842e56b97ce677b83bdab09cda48bc2d89ac75aJust 687842e56b97ce677b83bdab09cda48bc2d89ac75aJust def simpletag(self, _TAG_, *args, **kwargs): 6966214cbe8c220625e61a85f386756c6de4ec82b2Behdad Esfahbod attrdata = self.stringifyattrs(*args, **kwargs) 707842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = "<%s%s/>" % (_TAG_, attrdata) 717842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(data) 727842e56b97ce677b83bdab09cda48bc2d89ac75aJust 737842e56b97ce677b83bdab09cda48bc2d89ac75aJust def begintag(self, _TAG_, *args, **kwargs): 7466214cbe8c220625e61a85f386756c6de4ec82b2Behdad Esfahbod attrdata = self.stringifyattrs(*args, **kwargs) 757842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = "<%s%s>" % (_TAG_, attrdata) 767842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(data) 777842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.stack.append(_TAG_) 787842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.indent() 797842e56b97ce677b83bdab09cda48bc2d89ac75aJust 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust def endtag(self, _TAG_): 817842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag" 827842e56b97ce677b83bdab09cda48bc2d89ac75aJust del self.stack[-1] 837842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.dedent() 847842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = "</%s>" % _TAG_ 857842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(data) 867842e56b97ce677b83bdab09cda48bc2d89ac75aJust 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust def dumphex(self, data): 887842e56b97ce677b83bdab09cda48bc2d89ac75aJust linelength = 16 897842e56b97ce677b83bdab09cda48bc2d89ac75aJust hexlinelength = linelength * 2 907842e56b97ce677b83bdab09cda48bc2d89ac75aJust chunksize = 8 917842e56b97ce677b83bdab09cda48bc2d89ac75aJust for i in range(0, len(data), linelength): 927842e56b97ce677b83bdab09cda48bc2d89ac75aJust hexline = hexStr(data[i:i+linelength]) 937842e56b97ce677b83bdab09cda48bc2d89ac75aJust line = "" 947842e56b97ce677b83bdab09cda48bc2d89ac75aJust white = "" 957842e56b97ce677b83bdab09cda48bc2d89ac75aJust for j in range(0, hexlinelength, chunksize): 967842e56b97ce677b83bdab09cda48bc2d89ac75aJust line = line + white + hexline[j:j+chunksize] 977842e56b97ce677b83bdab09cda48bc2d89ac75aJust white = " " 987842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.writeraw(line) 997842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.newline() 1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust def indent(self): 1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.indentlevel = self.indentlevel + 1 1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust def dedent(self): 1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert self.indentlevel > 0 1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust self.indentlevel = self.indentlevel - 1 1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust def stringifyattrs(self, *args, **kwargs): 1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust if kwargs: 1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert not args 111ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod attributes = sorted(kwargs.items()) 1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif args: 1137842e56b97ce677b83bdab09cda48bc2d89ac75aJust assert len(args) == 1 1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust attributes = args[0] 1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "" 1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = "" 1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust for attr, value in attributes: 1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust data = data + ' %s="%s"' % (attr, escapeattr(str(value))) 1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1237842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef escape(data): 12414fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = data.replace("&", "&") 12514fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = data.replace("<", "<") 1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 1277842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1287842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef escapeattr(data): 12914fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = data.replace("&", "&") 13014fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = data.replace("<", "<") 13114fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod data = data.replace('"', """) 1327842e56b97ce677b83bdab09cda48bc2d89ac75aJust return data 1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1347842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef escape8bit(data): 1357842e56b97ce677b83bdab09cda48bc2d89ac75aJust def escapechar(c): 1367842e56b97ce677b83bdab09cda48bc2d89ac75aJust n = ord(c) 1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust if c in "<&": 1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust if c == "&": 1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "&" 1407842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 1417842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "<" 1427842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif 32 <= n <= 127: 1437842e56b97ce677b83bdab09cda48bc2d89ac75aJust return c 1447842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 145dc7e6f3e5563a853477ebe26166b002c158dbe8bBehdad Esfahbod return "&#" + repr(n) + ";" 146e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod return "".join(map(escapechar, data)) 1477842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1487842e56b97ce677b83bdab09cda48bc2d89ac75aJustneedswap = struct.pack("h", 1) == "\001\000" 1497842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1507842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef escape16bit(data): 1517842e56b97ce677b83bdab09cda48bc2d89ac75aJust import array 1527842e56b97ce677b83bdab09cda48bc2d89ac75aJust a = array.array("H") 1537842e56b97ce677b83bdab09cda48bc2d89ac75aJust a.fromstring(data) 1547842e56b97ce677b83bdab09cda48bc2d89ac75aJust if needswap: 1557842e56b97ce677b83bdab09cda48bc2d89ac75aJust a.byteswap() 1567842e56b97ce677b83bdab09cda48bc2d89ac75aJust def escapenum(n, amp=ord("&"), lt=ord("<")): 1577842e56b97ce677b83bdab09cda48bc2d89ac75aJust if n == amp: 1587842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "&" 1597842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif n == lt: 1607842e56b97ce677b83bdab09cda48bc2d89ac75aJust return "<" 1617842e56b97ce677b83bdab09cda48bc2d89ac75aJust elif 32 <= n <= 127: 1627842e56b97ce677b83bdab09cda48bc2d89ac75aJust return chr(n) 1637842e56b97ce677b83bdab09cda48bc2d89ac75aJust else: 164dc7e6f3e5563a853477ebe26166b002c158dbe8bBehdad Esfahbod return "&#" + repr(n) + ";" 165e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod return "".join(map(escapenum, a)) 1667842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1677842e56b97ce677b83bdab09cda48bc2d89ac75aJust 1687842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef hexStr(s): 1697842e56b97ce677b83bdab09cda48bc2d89ac75aJust h = string.hexdigits 1707842e56b97ce677b83bdab09cda48bc2d89ac75aJust r = '' 1717842e56b97ce677b83bdab09cda48bc2d89ac75aJust for c in s: 1727842e56b97ce677b83bdab09cda48bc2d89ac75aJust i = ord(c) 1737842e56b97ce677b83bdab09cda48bc2d89ac75aJust r = r + h[(i >> 4) & 0xF] + h[i & 0xF] 1747842e56b97ce677b83bdab09cda48bc2d89ac75aJust return r 1757842e56b97ce677b83bdab09cda48bc2d89ac75aJust 176