def excel_to_html(path, sheetname='<STR_LIT>', css_classes='<STR_LIT>',caption='<STR_LIT>', details=[], row_headers=False, merge=False):
def get_data_on_merged_cells():<EOL><INDENT>"""<STR_LIT>"""<EOL>merged_cells = xls.book.sheet_by_name(sheetname).merged_cells<EOL>ds = {}<EOL>for crange in merged_cells:<EOL><INDENT>rlo, rhi, clo, chi = crange<EOL>for rowx in range(rlo, rhi):<EOL><INDENT>for colx in range(clo, chi):<EOL><INDENT>parent_cell = (rlo,clo)<EOL>child_cell = (rowx,colx)<EOL>if not parent_cell in ds:<EOL><INDENT>ds[parent_cell] = [[<NUM_LIT:1>,<NUM_LIT:1>], set([])]<EOL><DEDENT>else:<EOL><INDENT>if parent_cell != child_cell and child_cell[<NUM_LIT:0>] == parent_cell[<NUM_LIT:0>]:<EOL><INDENT>ds[parent_cell][<NUM_LIT:0>][<NUM_LIT:0>] += <NUM_LIT:1><EOL>ds[parent_cell][<NUM_LIT:1>].add('<STR_LIT:right>')<EOL><DEDENT>elif parent_cell != child_cell and child_cell[<NUM_LIT:0>] > parent_cell[<NUM_LIT:0>]:<EOL><INDENT>if child_cell[<NUM_LIT:1>] == parent_cell[<NUM_LIT:1>]:<EOL><INDENT>ds[parent_cell][<NUM_LIT:0>][<NUM_LIT:1>] += <NUM_LIT:1><EOL><DEDENT>ds[parent_cell][<NUM_LIT:1>].add('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>return ds<EOL><DEDENT>def mark_cells_going_right(cell, curr_cell, merged_cells):<EOL><INDENT>"""<STR_LIT>"""<EOL>try:<EOL><INDENT>xcount = merged_cells[curr_cell][<NUM_LIT:0>][<NUM_LIT:0>]<EOL>if xcount > <NUM_LIT:1>: <EOL><INDENT>cell['<STR_LIT>'] = xcount<EOL><DEDENT>col_count = xcount - <NUM_LIT:1> <EOL>while col_count > <NUM_LIT:0>:<EOL><INDENT>cell = cell.find_next_sibling()<EOL>cell['<STR_LIT:class>'] = '<STR_LIT>'<EOL>col_count -= <NUM_LIT:1><EOL><DEDENT><DEDENT>except:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>def mark_cells_going_down(cell, curr_cell, merged_cells):<EOL><INDENT>"""<STR_LIT>"""<EOL>if curr_cell in merged_cells and merged_cells[curr_cell][<NUM_LIT:1>] == set(['<STR_LIT>']):<EOL><INDENT>ycount = merged_cells[curr_cell][<NUM_LIT:0>][<NUM_LIT:1>]<EOL>cell['<STR_LIT>'] = ycount<EOL>row_count = ycount<EOL>for child_row in cell.parent.find_next_siblings(limit=row_count - <NUM_LIT:1>):<EOL><INDENT>i = <NUM_LIT:0><EOL>for child in child_row.find_all('<STR_LIT>'):<EOL><INDENT>if i == curr_cell[<NUM_LIT:1>]:<EOL><INDENT>child['<STR_LIT:class>'] = '<STR_LIT>'<EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT><DEDENT>def mark_cells_going_down_and_right(cell, curr_cell, merged_cells):<EOL><INDENT>"""<STR_LIT>"""<EOL>if curr_cell in merged_cells and('<STR_LIT>' in merged_cells[curr_cell][<NUM_LIT:1>] and'<STR_LIT:right>' in merged_cells[curr_cell][<NUM_LIT:1>]):<EOL><INDENT>xcount = merged_cells[curr_cell][<NUM_LIT:0>][<NUM_LIT:0>]<EOL>ycount = merged_cells[curr_cell][<NUM_LIT:0>][<NUM_LIT:1>]<EOL>row_count = ycount<EOL>col_count = xcount<EOL>mark_cells_going_right(cell, curr_cell, merged_cells)<EOL>flag = False<EOL>for child_row in [cell.parent] + cell.parent.find_all_next('<STR_LIT>', limit=row_count - <NUM_LIT:1>):<EOL><INDENT>i = <NUM_LIT:0><EOL>for child in child_row.find_all('<STR_LIT>'):<EOL><INDENT>if i == curr_cell[<NUM_LIT:1>]:<EOL><INDENT>mark_cells_going_right(child, curr_cell, merged_cells)<EOL>if not flag:<EOL><INDENT>child['<STR_LIT>'] = col_count<EOL>child['<STR_LIT>'] = row_count<EOL>flag = True<EOL><DEDENT>else:<EOL><INDENT>child['<STR_LIT:class>'] = '<STR_LIT>'<EOL><DEDENT><DEDENT>i += <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT><DEDENT>def is_empty_th(string):<EOL><INDENT>"""<STR_LIT>"""<EOL>if string[:<NUM_LIT:8>] == '<STR_LIT>':<EOL><INDENT>data = string.split('<STR_LIT:U+0020>')<EOL>if is_numeric(data[<NUM_LIT:1>]):<EOL><INDENT>return True<EOL><DEDENT><DEDENT>return False<EOL><DEDENT>def mark_header_cells(html):<EOL><INDENT>"""<STR_LIT>"""<EOL>th = html.find_all('<STR_LIT>')<EOL>for header in th:<EOL><INDENT>txt = header.string<EOL>if not is_empty_th(txt):<EOL><INDENT>header['<STR_LIT>'] = '<STR_LIT>'<EOL>count = <NUM_LIT:1><EOL>for sibling in header.find_next_siblings():<EOL><INDENT>if is_empty_th(sibling.string):<EOL><INDENT>count += <NUM_LIT:1><EOL>sibling['<STR_LIT:class>'] = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>break<EOL><DEDENT><DEDENT>if count > <NUM_LIT:1>:<EOL><INDENT>header['<STR_LIT>'] = count<EOL>header['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT><DEDENT><DEDENT><DEDENT>def create_caption(html, caption):<EOL><INDENT>"""<STR_LIT>"""<EOL>ctag = html.new_tag('<STR_LIT>')<EOL>ctag.insert(<NUM_LIT:0>, caption)<EOL>html.table.insert(<NUM_LIT:0>, ctag)<EOL><DEDENT>def create_summary_and_details(html, details):<EOL><INDENT>"""<STR_LIT>"""<EOL>if len(details) != <NUM_LIT:2>:<EOL><INDENT>msg = '<STR_LIT>'+ '<STR_LIT>'+ '<STR_LIT>'+ '<STR_LIT>'<EOL>raise RuntimeError(msg)<EOL><DEDENT>summary = details[<NUM_LIT:0>]<EOL>details = details[<NUM_LIT:1>]<EOL>if not caption:<EOL><INDENT>create_caption(html, caption)<EOL><DEDENT>dtag = html.new_tag('<STR_LIT>')<EOL>stag = html.new_tag('<STR_LIT>')<EOL>ptag = html.new_tag('<STR_LIT:p>')<EOL>stag.insert(<NUM_LIT:0>, summary)<EOL>ptag.insert(<NUM_LIT:0>, details)<EOL>dtag.insert(<NUM_LIT:0>, stag)<EOL>dtag.append(ptag) <EOL>html.table.caption.insert(<NUM_LIT:1>, dtag)   <EOL><DEDENT>def format_properly(html):<EOL><INDENT>"""<STR_LIT>"""<EOL>return html.replace('<STR_LIT>', '<STR_LIT>').replace('<STR_LIT>','<STR_LIT>').replace('<STR_LIT>', '<STR_LIT>').replace('<STR_LIT>','<STR_LIT>').replace('<STR_LIT>', '<STR_LIT>')<EOL><DEDENT>def add_row_headers(html):<EOL><INDENT>"""<STR_LIT>"""<EOL>for row in html.tbody.find_all('<STR_LIT>'):<EOL><INDENT>spans_rows = '<STR_LIT>' in row.td.attrs<EOL>spans_columns = '<STR_LIT>' in row.td.attrs<EOL>new_tag = html.new_tag('<STR_LIT>')<EOL>new_tag['<STR_LIT>'] = '<STR_LIT>'<EOL>new_tag.string = row.td.string<EOL>if spans_rows:<EOL><INDENT>new_tag['<STR_LIT>'] = row.td.attrs['<STR_LIT>']<EOL>new_tag['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT>if spans_columns:<EOL><INDENT>new_tag['<STR_LIT>'] = row.td.attrs['<STR_LIT>']<EOL><DEDENT>row.td.replace_with(new_tag)<EOL><DEDENT><DEDENT>def beautify(html):<EOL><INDENT>"""<STR_LIT>"""<EOL>table = html.find('<STR_LIT>')<EOL>first_tr = table.find('<STR_LIT>')<EOL>del table['<STR_LIT>']<EOL>del first_tr['<STR_LIT>']<EOL>return format_properly(html.prettify(formatter='<STR_LIT>'))<EOL><DEDENT>def parse_html(html, caption, details):<EOL><INDENT>"""<STR_LIT>"""<EOL>new_html = BeautifulSoup(html, '<STR_LIT>')<EOL>if merge:<EOL><INDENT>row_num = <NUM_LIT:1><EOL>merged_cells = get_data_on_merged_cells()<EOL>rows = new_html.find('<STR_LIT>').find('<STR_LIT>').find_all('<STR_LIT>')<EOL>for row in rows:<EOL><INDENT>cell_num = <NUM_LIT:0> <EOL>cells = row.find_all('<STR_LIT>')<EOL>for cell in cells:<EOL><INDENT>curr_cell = (row_num, cell_num)<EOL>mark_cells_going_right(cell, curr_cell, merged_cells)  <EOL>mark_cells_going_down(cell, curr_cell, merged_cells)<EOL>mark_cells_going_down_and_right(cell, curr_cell, merged_cells)<EOL>cell_num += <NUM_LIT:1><EOL><DEDENT>row_num += <NUM_LIT:1><EOL><DEDENT>mark_header_cells(new_html)<EOL>destroy = new_html.find_all(attrs={'<STR_LIT:class>' : '<STR_LIT>' })<EOL>for item in destroy:<EOL><INDENT>item.extract()<EOL><DEDENT><DEDENT>if row_headers:<EOL><INDENT>add_row_headers(new_html)<EOL><DEDENT>if caption:<EOL><INDENT>create_caption(new_html, caption)<EOL><DEDENT>if details:<EOL><INDENT>create_summary_and_details(new_html, details)<EOL><DEDENT>return beautify(new_html)<EOL><DEDENT>pd.options.display.max_colwidth = -<NUM_LIT:1><EOL>xls = pd.ExcelFile(path)<EOL>df = xls.parse(sheetname)<EOL>panda_html = df.to_html(classes=css_classes, index=False, na_rep='<STR_LIT>')<EOL>return parse_html(panda_html, caption, details)<EOL>
Convert an excel spreadsheet to an html table.
This function supports the conversion of merged 
cells. It can be used in code or run from the 
command-line. If passed the correct arguments
it can generate fully accessible html.

Args:
    path: string, path to the spreadsheet.

    sheetname: string, name of the sheet
    to convert. 

    css_classes: string, space separated
    classnames to append to the table.

    caption: string, a short heading-like 
    description of the table.

    details: list of strings, where the first
    item in the list is a string for the html 
    summary element and the second item is
    a string for the details element. The 
    summary should be very short, e.g. "Help",
    where as the details element should be a 
    long description regarding the purpose or 
    how to navigate the table.

    row_headers: boolean, defaults to False.
    Does the table have row headers? If set
    to True, the first element in each row
    will be a <th scope="row"> element 
    instead of a <td> element.

    merge: boolean, whether or not to 
    combine cells that were merged in the 
    spreadsheet.

Returns:
    string, html table