docs: def parsetuple(self,xmltuple):
      """
      Parse an XML tuple returned by pyRXP into a dictionary
      of LIGO metadata elements. The dictionary contains one
      entry for each table found in the XML tuple.
      """
      # first extract all the table and columns from the tuple from the
      # children of the ligo lightweight parent tuple
      table = {}
      tupleidx = 0
      for tag in xmltuple[2]:
        if tag[0] == 'Table' or tag[0] == 'table':
          tab = tag[1]['Name'].encode('ascii').lower()
          try:
            tab = self.tabrx.match(tab).group(2)
          except AttributeError:
            raise LIGOLwParseError, 'unable to parse a valid table name '+tab
          # initalize the table dictionary for this table
          table[tab] = { 
            'pos' : tupleidx,
            'column' : {},
            'stream' : (), 
            'query' : ''
            }
          # parse for columns in the tables children
          # look for the column name and type in the attributes
          # store the index in which the columns were found as
          # we need this to decode the stream later
          for subtag in tag[2]:
            if subtag[0] == 'Column' or subtag[0] == 'column':
              col = subtag[1]['Name'].encode('ascii').lower()
              try:
                col = self.colrx.match(col).group(3)
              except AttributeError:
                raise LIGOLwParseError, 'unable to parse a valid column name '+col
              try:
                typ = subtag[1]['Type'].encode('ascii').lower()
              except KeyError:
                raise LIGOLwParseError, 'type is missing for column '+col
              table[tab]['column'][col] = typ
              table[tab].setdefault('orderedcol',[]).append(col)
        tupleidx += 1
  
      # now iterate the dictionary of tables we have created looking for streams
      for tab in table.keys():
        for tag in xmltuple[2][table[tab]['pos']][2]:
          if tag[0] == 'Stream' or tag[0] == 'stream':
            # store the stream delimiter and create the esacpe regex
            try:
              delim = tag[1]['Delimiter'].encode('ascii')
            except KeyError:
              raise LIGOLwParseError, 'stream is missing delimiter'
            if delim != ',':
              raise LIGOLwParseError, 'unable to handle stream delimiter: '+delim
  
            # If the result set is empty tag[2] is an empty array, which causes
            # the next step to fail.  Add an empty string in this case.
            if len(tag[2]) == 0:
              tag[2].append("")
  
  
            # strip newlines from the stream and parse it
            stream = csv.reader([re.sub(r'\n','',tag[2][0])],LIGOLWStream).next()
  
            # turn the csv stream into a list of lists
            slen = len(stream)
            ntyp = len(table[tab]['column'])
            mlen, lft = divmod(slen,ntyp)
            if lft != 0:
              raise LIGOLwParseError, 'invalid stream length for given columns'
            lst = [[None] * ntyp for i in range(mlen)]
  
            # translate the stream data to the correct data types
            for i in range(slen):
              j, k = divmod(i,ntyp)
              try:
                thiscol = table[tab]['orderedcol'][k]
                if len( stream[i] ) == 0:
                  lst[j][k] = None
                else:
                  lst[j][k] = self.types[table[tab]['column'][thiscol]](stream[i])
              except (KeyError, ValueError), errmsg:
                msg = "stream translation error (%s) " % str(errmsg)
                msg += "for column %s in table %s: %s -> %s" \
                  % (tab,thiscol,stream[i],str(table[tab])) 
                raise LIGOLwParseError, msg
            table[tab]['stream'] = map(tuple,lst)
  
      # return the created table to the caller
      return table