Convert a table dictionary to LIGO lightweight XML

def xml(self, ilwdchar_to_hex = True):
    """Convert a table dictionary to LIGO lightweight XML"""
    if len(self.table) == 0:
      raise LIGOLwDBError, 'attempt to convert empty table to xml'
    ligolw = """\
<?xml version='1.0' encoding='utf-8' ?>
<?xml-stylesheet type="text/xsl" href="ligolw.xsl"?>
<!DOCTYPE LIGO_LW SYSTEM "http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt">
<LIGO_LW>
"""

    for tab in self.table.keys():
      try:
        ligolw += '   <Comment>'+self.strtoxml.xlat(self.table[tab]['query'])+'</Comment>\n'
      except KeyError:
        pass
      ligolw += '   <Table Name="'+tab+':table">\n'
      for col in self.table[tab]['orderedcol']:
        ligolw +='      <Column Name="'+tab.lower()+':'+col.lower()+'" Type="'+self.table[tab]['column'][col].lower()+'"/>\n'
      ligolw += '      <Stream Name="'+tab.lower()+':table" Type="Local" Delimiter=",">\n'
      stridx = 0
      ligolw += '      '
      for tup in self.table[tab]['stream']:
        if stridx != 0:
          ligolw += ',\n      '
        colidx = 0
        for tupi in tup:
          if tupi is not None:
            coltype = self.table[tab]['column'][self.table[tab]['orderedcol'][colidx]]
            if re.match(r'\Ailwd:char_u\Z',coltype):
              ligolw += '"'
              for ch in str(tupi):
                # NOTE: escape the backslash in the ilwd:char_u octal string
                ligolw += '\\\\%.3o' % (ord(ch))
              ligolw += '"'
            elif re.match(r'\Ailwd:char\Z',coltype):
              if ilwdchar_to_hex is True:
                # encode in DB2-style hex (e.g., "x'deadbeef'")
                ligolw += '"x\''
                for ch in str(tupi):
                  ligolw += "%02x" % ord(ch)
                ligolw += '\'"'
              else:
                ligolw += '"' + str(tupi) + '"'
            elif re.match(r'\Alstring\Z',coltype):
              # this santizes the contents of tupi in several ways: 
              # strtoxml.xlat escapes any double-quote and
              # backslash chars (with a preceding blackslash); and
              # then replaces <>& chars with their html
              # code equivalents
              # NOTE: string_format_func was removed so the enclosing ""
              # chars need to be added ourselves
              ligolw += '"'+self.strtoxml.xlat(tupi)+'"' 
            elif re.match(r'\Areal_4\Z',coltype):
              ligolw += '%13.7e' % tupi
            elif re.match(r'\Areal_8\Z',coltype):
              ligolw += '%22.16e' % tupi
            else:
              ligolw += str(tupi)
          else:
            ligolw += ''
          if colidx < (len(self.table[tab]['column']) - 1):
            ligolw += ','
          colidx += 1
        stridx += 1
      ligolw += '\n      </Stream>\n'
      ligolw += '   </Table>\n'
    ligolw += '</LIGO_LW>'

    return ligolw