如何正确转换含嵌套表格的HTML为Docx?解决多余行问题
HTML嵌套表格转Docx时多余行问题修复
问题现象
将包含单元格内嵌套表格的HTML转换为Docx格式时,嵌套表格所在行的后续会生成多余行,多余行数等于该行内所有嵌套表格的行数总和,无法实现仅将嵌套表格插入对应单元格的需求。
错误原因
在处理嵌套表格的逻辑中,错误地将父表格对象(parent_docx_table)传递给了递归调用的handle_table方法,而非当前单元格内新建的子表格。这导致嵌套表格的行被错误追加到父表格中,而非单元格内部的子表格,最终引发多余行问题。
修复后的完整代码
from docx import Document from bs4 import BeautifulSoup class HtmlToDocx: def __init__(self): self.document = Document() def handle_table(self, table_soup, parent_docx_table=None, row_idx=0, col_idx=0): rows, cols = self.get_table_dimensions(table_soup) if parent_docx_table: cell = parent_docx_table.cell(row_idx, col_idx) docx_table = cell.add_table(rows=rows, cols=cols) else: docx_table = self.document.add_table(rows=rows, cols=cols) rows = self.get_table_rows(table_soup) cell_row = 0 for row in rows: cols = self.get_table_columns(row) cell_col = 0 for col in cols: nested_table = col.find('table') docx_cell = docx_table.cell(cell_row, cell_col) if nested_table: # 修复:传递当前单元格内的子表格作为父表格,而非原父表格 self.handle_table(nested_table, docx_table, cell_row, cell_col) cell_col += 1 continue cell_html = self.get_cell_html(col) docx_cell.text = cell_html cell_col += 1 cell_row += 1 def get_table_rows(self, table_soup): return table_soup.find_all('tr') def get_table_columns(self, row): return row.find_all(['th', 'td'], recursive=False) def get_cell_html(self, soup): return ''.join([str(i) for i in soup.contents if not (i.name == 'table' or isinstance(i, BeautifulSoup))]) def get_table_dimensions(self, table_soup): rows = self.get_table_rows(table_soup) cols = self.get_table_columns(rows[0]) if rows else [] return len(rows), len(cols) def add_html_to_docx(self, html_content, output_file): self.soup = BeautifulSoup(html_content, "html.parser") top_tables = self.soup.find_all('table', recursive=False) for table_soup in top_tables: self.handle_table(table_soup) self.document.save(output_file) html_content = """ <table style="border-collapse: collapse; width: 100%; height: 232px;" border="1"> <tbody> <tr style="height: 22px;"> <td style="width: 23.7413%; height: 22px;"> </td> <td style="width: 23.7413%; height: 22px;"> </td> <td style="width: 23.7413%; height: 22px;"> </td> <td style="width: 23.7413%; height: 22px;"> </td> </tr> <tr style="height: 188px;"> <td style="width: 23.7413%; height: 188px;"> </td> <td style="width: 23.7413%; height: 188px;"> </td> <td style="width: 23.7413%; height: 188px;"> <table style="border-collapse: collapse; width: 95.0877%;" border="1"> <tbody> <tr> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6246%;"> </td> </tr> <tr> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;">ааа</td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6246%;"> </td> </tr> <tr> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6073%;"> </td> <td style="width: 14.6246%;"> </td> </tr> </tbody> </table> </td> <td style="width: 23.7413%; height: 188px;"> <table style="border-collapse: collapse; width: 95.0877%;" border="1"> <tbody> <tr> <td style="width: 27.8655%;">е</td> <td style="width: 27.8655%;"> </td> <td style="width: 27.8742%;"> </td> </tr> <tr> <td style="width: 27.8655%;"> </td> <td style="width: 27.8655%;">еее</td> <td style="width: 27.8742%;"> </td> </tr> </tbody> </table> </td> </tr> <tr style="height: 22px;"> <td style="width: 23.7413%; height: 22px;"> </td> <td style="width: 23.7413%; height: 22px;"> </td> <td style="width: 23.7413%; height: 22px;"> <table style="border-collapse: collapse; width: 95.0877%;" border="1"> <tbody> <tr> <td style="width: 19.5803%;">11</td> <td style="width: 19.5803%;"> </td> <td style="width: 19.5803%;"> </td> <td style="width: 19.5889%;"> </td> </tr> <tr> <td style="width: 19.5803%;"> </td> <td style="width: 19.5803%;"> </td> <td style="width: 19.5803%;">222</td> <td style="width: 19.5889%;">333</td> </tr> </tbody> </table> </td> <td style="width: 23.7413%; height: 22px;"> </td> </tr> </tbody> </table> """ converter = HtmlToDocx() converter.add_html_to_docx(html_content, "output.docx")
关键修复点
在处理嵌套表格的递归调用中,将传递的父表格从parent_docx_table改为当前单元格内新建的docx_table,确保嵌套表格的行被正确添加到单元格内部的子表格中,而非父表格。
内容的提问来源于stack exchange,提问作者Василий Чернов
相关产品推荐
相关产品推荐

