Method to print tables in an xml file in other formats.
    Input is an xmldoc, output is a file object containing the
    tables.

    @xmldoc: document to convert
    @output: file object to write output to; if None, will write to stdout
    @output_format: format to convert to
    @tableList: only convert the listed tables. Default is
     to convert all the tables found in the xmldoc. Tables
     not converted will not be included in the returned file
     object.
    @columnList: only print the columns listed, in the order given. 
     This applies to all tables (if a table doesn't have a listed column, it's just
     skipped). To specify a column in a specific table, use table_name:column_name.
     Default is to print all columns.
    @round_floats: If turned on, will smart_round floats to specifed
     number of places.
    @format_links: If turned on, will convert any html hyperlinks to specified
     output_format.
    @decimal_places: If round_floats turned on, will smart_round to this
     number of decimal places.
    @title: Add a title to this set of tables.
    @unique_rows: If two consecutive rows are exactly the same, will condense into
     one row.
    @print_table_names: If set to True, will print the name of each table
     in the caption section.
    @row_span_columns: For the columns listed, will
     concatenate consecutive cells with the same values
     into one cell that spans those rows. Default is to span no rows.
    @rspan_break_column: Columns listed will prevent all cells
     from rowspanning across two rows in which values in the
     columns are diffrent. Default is to have no break columns.

def print_tables(xmldoc, output, output_format, tableList = [], columnList = [],
    round_floats = True, decimal_places = 2, format_links = True,
    title = None, print_table_names = True, unique_rows = False,
    row_span_columns = [], rspan_break_columns = []):
    """
    Method to print tables in an xml file in other formats.
    Input is an xmldoc, output is a file object containing the
    tables.

    @xmldoc: document to convert
    @output: file object to write output to; if None, will write to stdout
    @output_format: format to convert to
    @tableList: only convert the listed tables. Default is
     to convert all the tables found in the xmldoc. Tables
     not converted will not be included in the returned file
     object.
    @columnList: only print the columns listed, in the order given. 
     This applies to all tables (if a table doesn't have a listed column, it's just
     skipped). To specify a column in a specific table, use table_name:column_name.
     Default is to print all columns.
    @round_floats: If turned on, will smart_round floats to specifed
     number of places.
    @format_links: If turned on, will convert any html hyperlinks to specified
     output_format.
    @decimal_places: If round_floats turned on, will smart_round to this
     number of decimal places.
    @title: Add a title to this set of tables.
    @unique_rows: If two consecutive rows are exactly the same, will condense into
     one row.
    @print_table_names: If set to True, will print the name of each table
     in the caption section.
    @row_span_columns: For the columns listed, will
     concatenate consecutive cells with the same values
     into one cell that spans those rows. Default is to span no rows.
    @rspan_break_column: Columns listed will prevent all cells
     from rowspanning across two rows in which values in the
     columns are diffrent. Default is to have no break columns.
    """
    # get the tables to convert
    if tableList == []:
        tableList = [tb.getAttribute("Name") for tb in xmldoc.childNodes[0].getElementsByTagName(u'Table')]

    # set the output
    if output is None:
        output = sys.stdout

    # get table bits
    ttx, xtt, tx, xt, capx, xcap, rx, xr, cx, xc, rspx, xrsp, hlx, hxl, xhl = set_output_format( output_format )

    # set the title if desired
    if title is not None:
        print >> output, "%s%s%s" %(ttx,str(title),xtt)
    # cycle over the tables in the xmldoc
    for table_name in tableList:
        this_table = table.get_table(xmldoc, table_name)
        if columnList == []:
            col_names = [ col.getAttribute("Name").split(":")[-1]
                for col in this_table.getElementsByTagName(u'Column') ]
        else:
            requested_columns = [col.split(':')[-1] for col in columnList if not (':' in col and col.split(':')[0] != table_name) ]
            requested_columns = sorted(set(requested_columns), key=requested_columns.index)
            actual_columns = [actual_column.getAttribute("Name").split(":")[-1]
                for actual_column in this_table.getElementsByTagName(u'Column') ]
            col_names = [col for col in requested_columns if col in actual_columns]
        # get the relevant row_span/break column indices
        rspan_indices = [ n for n,col in enumerate(col_names) if col in row_span_columns or ':'.join([table_name,col]) in row_span_columns ]
        break_indices = [ n for n,col in enumerate(col_names) if col in rspan_break_columns or ':'.join([table_name,col]) in rspan_break_columns ] 

        # start the table and print table name
        print >> output, tx
        if print_table_names:
            print >> output, "%s%s%s" %(capx, table_name, xcap)
        print >> output, "%s%s%s%s%s" %(rx, cx, (xc+cx).join(format_header_cell(val) for val in col_names), xc, xr)

        # format the data in the table
        out_table = []
        last_row = ''
        for row in this_table:
            out_row = [ str(format_cell( get_row_data(row, col_name),
                round_floats = round_floats, decimal_places = decimal_places,
                format_links = format_links,  hlx = hlx, hxl = hxl, xhl = xhl ))
                for col_name in col_names ]
            if unique_rows and out_row == last_row:
                continue
            out_table.append(out_row)
            last_row = out_row

        rspan_count = {}
        for mm, row in enumerate(out_table[::-1]):
            this_row_idx = len(out_table) - (mm+1)
            next_row_idx = this_row_idx - 1
            # cheack if it's ok to do row-span
            rspan_ok = rspan_indices != [] and this_row_idx != 0
            if rspan_ok:
                for jj in break_indices:
                    rspan_ok = out_table[this_row_idx][jj] == out_table[next_row_idx][jj]
                    if not rspan_ok: break
            # cycle over columns in the row setting row span values
            for nn, val in enumerate(row):
                # check if this cell should be spanned;
                # if so, delete it, update rspan_count and go on to next cell
                if rspan_ok and nn in rspan_indices:
                    if val == out_table[next_row_idx][nn]:
                        out_table[this_row_idx][nn] = ''
                        if (this_row_idx, nn) in rspan_count:
                            rspan_count[(next_row_idx,nn)] = rspan_count[(this_row_idx,nn)] + 1
                            del rspan_count[(this_row_idx,nn)]
                        else:
                            rspan_count[(next_row_idx,nn)] = 2 
                    elif (this_row_idx, nn) in rspan_count:
                        out_table[this_row_idx][nn] = ''.join([rspx, str(rspan_count[(this_row_idx,nn)]), xrsp, str(val), xc])
                    else:
                        out_table[this_row_idx][nn] = ''.join([cx, str(val), xc])
                    continue
                # format cell appropriately
                if (this_row_idx, nn) in rspan_count:
                    out_table[this_row_idx][nn] = ''.join([rspx, str(rspan_count[(this_row_idx,nn)]), xrsp, str(val), xc])
                else:
                    out_table[this_row_idx][nn] = ''.join([cx, str(val), xc])

        # print the table to output
        for row in out_table:
            print >> output, "%s%s%s" % (rx, ''.join(row), xr)

        # close the table and go on to the next
        print >> output, xt