docs: 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