阅读文本 / Reading text
This paper uses synthetic samples to demonstrate the processing method. The code has been verified using examples in an isolated environment; this does not guarantee effectiveness for all real files or products. Before processing important files, please retain the original copies and verify them against the boundaries and acceptance criteria specified in the text.
When you are working with an HTML document that contains complex table headers, directly extracting
<td>
text often yields corrupted data. A setting with
rowspan="3"
The cell appears only once in the DOM tree, but it occupies three rows in the logical table. If subsequent code assumes that each row has the same number of columns, the program will either throw an index-out-of-bounds exception or incorrectly concatenate data belonging to the next row with the current row. An even more insidious risk is memory explosion: malicious or corrupted HTML might declare a
colspan="99999"
, if the script blindly allocates memory, it will exhaust resources in an instant.
The core of solving this problem is not to look for some off-the-shelf “table-to-CVS” magic function, but rather to manually maintain a state machine for a two-dimensional grid. You need to scan the DOM nodes line by line while keeping track of which coordinates have already been occupied by above‑lying merged cells. When you encounter an occupied coordinate, skip it; when you come across a new cell, fill multiple grid positions according to its span attribute. This process must include explicit checks on size constraints, shifting the parsing behavior from “trusting input” to “defensive validation.”
synthesis example and boundary condition design
To verify the correctness of the expansion logic, we need to construct a minimal yet complete synthetic HTML sample. This sample should not be derived from real-world business data but should instead be specifically designed to cover critical paths.
The correct input should encompass three typical cases: ordinary cells, horizontal merging (colspan), and vertical merging (rowspan). For example, in a 3-row-by-3-column logical table, the first cell in the first row
rowspan="2"
, the second cell in the second row
colspan="2"
. The expected output is a standard two-dimensional list, with the positions that have been merged and overwritten filled with
None
or a specific placeholder, rather than leaving it blank and causing inconsistent row lengths. For the example above, the value in the first column of the second row should be identical to that in the first column of the first row (since it is a rowspan continuation), while the second and third columns of the second row should contain values; similarly, the first column of the third row should also continue the value from the first row.
errors or boundary inputs are equally important. Consider a statement that declares
colspan="10000"
but in reality, the table contains only 3 columns of data, or
rowspan
exceeds the actual number of rows in the table. There are even more challenging conflicts: two cells have span ranges that logically overlap, which typically indicates an error in the HTML source itself. When handling such inputs, the code should neither crash nor silently accept them. A reasonable strategy is to set a maximum grid threshold (e.g., 1000x1000); once the computed target dimensions exceed this value, immediately throw a clear exception or return partial results along with a warning. For overlapping conflicts, one can choose to prioritize the earlier-appearing cell, ignore the later illegal overwrite, and log the coordinate conflict.
Python implementation with protection mechanism
The following example uses BeautifulSoup to parse HTML and expand tables. It does not rely on any third-party table-specific libraries, instead relying entirely on DOM traversal and coordinate state management.
Note: This code is for instructional demonstration and must be used after locking
beautifulsoup4
Run in a standalone environment of the specified version; the example uses only an in-memory HTML string and does not involve network requests, file deletions, or credential operations. If you need to process external files, first read the file contents into a string variable and pass it in.
from bs4 import BeautifulSoup
def expand_html_table(html_content, max_rows=1000, max_cols=1000):
"""
将含rowspan/colspan的HTML表格展开为二维列表。
包含网格尺寸防护,防止恶意或错误标签导致内存溢出。
"""
soup = BeautifulSoup(html_content, 'html.parser')
table = soup.find('table')
if not table:
return []
grid = []
rows = table.find_all('tr')
for r_idx, tr in enumerate(rows):
if r_idx >= max_rows:
raise ValueError(f"表格行数超过安全上限 {max_rows}")
# 确保当前行存在
while len(grid) <= r_idx:
grid.append([])
c_idx = 0
cells = tr.find_all(['td', 'th'])
for cell in cells:
# 找到下一个未被占用的列位置
while c_idx < len(grid[r_idx]) and grid[r_idx][c_idx] is not None:
c_idx += 1
# 防御性解析:非数字属性默认为1
try:
colspan = int(cell.get('colspan', 1))
rowspan = int(cell.get('rowspan', 1))
except (ValueError, TypeError):
colspan, rowspan = 1, 1
text = cell.get_text(strip=True)
# 安全检查:防止单个单元格撑爆网格
if c_idx + colspan > max_cols or r_idx + rowspan > max_rows:
raise ValueError(
f"单元格跨度({rowspan}x{colspan})在位置({r_idx},{c_idx})"
f"超出安全网格{max_rows}x{max_cols}"
)
# 填充所有被该单元格覆盖的坐标
for i in range(rowspan):
target_row = r_idx + i
while len(grid) <= target_row:
grid.append([])
for j in range(colspan):
target_col = c_idx + j
while len(grid[target_row]) <= target_col:
grid[target_row].append(None)
# 仅当目标位置为空时才写入(处理冲突)
if grid[target_row][target_col] is None:
grid[target_row][target_col] = text
c_idx += colspan
return grid
# 合成测试用例(仅用于验证逻辑,非生产实测)
TEST_HTML = """
<table>
<tr><td rowspan="2">A</td><td>B</td><td>C</td></tr>
<tr><td colspan="2">D</td></tr>
<tr><td>E</td><td>F</td><td>G</td></tr>
</table>
"""
result = expand_html_table(TEST_HTML)
assert result == [
['A', 'B', 'C'],
['A', 'D', 'D'],
['E', 'F', 'G']
], f"展开结果不符合预期: {result}"
The key to this code lies in its double-layered safeguard: the outer loop checks the total number of rows, while the inner loop verifies, before populating a cell, whether the span of that individual cell would cause the grid to exceed its bounds.
while
dynamically expands rows and columns in a loop, thereby avoiding the risk of pre-allocating extremely large arrays. Assertion statements verify the expected output of synthetic examples, but this only confirms that the logic is correct for the current input; it does not guarantee that the implementation has been validated through empirical testing on a variety of real-world documents.
Acceptance Criteria and Manual Review Thresholds
code can successfully run the synthetic example, but that does not mean it can handle dirty data in a production environment. The table below summarizes common observations encountered in real-world document processing and the corresponding handling decisions, distinguishing between issues that can be resolved automatically and scenarios requiring manual intervention.
Observation of the phenomenon
automatic processing decision
Cases requiring manual review
The rowspan/colspan value is a non-numeric string
is treated as 1 by default, and warning logs are recorded
This type of issue frequently occurs in the same table, suspected to be due to OCR recognition errors or template corruption
cell span causes inconsistency in the number of logical columns
is based on the maximum number of columns, with short rows padded with None
The number of columns differs from the expected range (e.g., >30%), which may indicate that the table structure has been corrupted
nested table (table within td)
Only expand the outermost table, leaving the inner HTML fragments intact.
business semantics depend on nested table content, requiring a customized recursive expansion strategy
grid size has reached the safety threshold
throws an exception, refusing to process this table
After confirming that it is a legitimate oversized table rather than malicious input, adjust the parameters and retry.
merged cell text contains newline characters
retains the original line breaks and is not cleaned up
Whether a newline character is typesetting noise or a structured-data delimiter depends on the context.
Note that this table describes the behavioral boundaries of the parsing logic, not a guarantee of end-to-end translation quality. The code demonstration only verifies the correctness of coordinate expansion; actual acceptance testing requires comparing against the original document’s visual layout to ensure that critical data points have not been lost or misaligned during the conversion process.
References and Next Steps
Beautiful Soup official documentation:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/#navigating-the-tree
HTML Table Specification (MDN): Understanding the Valid Values of rowspan/colspan and Browser Tolerance Behaviors
Next steps: Run the above code using your own de-identified HTML sample, and record the types and frequencies of exceptions triggered. If boundary issues occur frequently, evaluate whether to switch to a platform-based processing solution.
uses this checklist for document translation
The body text, links, code, and structure of the web document should be processed separately. Include the protected sections in the acceptance checklist, then evaluate the post-translation readability and page display.
OmniDoc (product entry point)
provides an entry point for translating multi-format documents, and the official website highlights its OCR, terminology database, and bilingual alignment features. For teams that prefer to start processing directly from files, this is a path worth evaluating with real-world samples. Please use de-identified files that you are authorized to upload, and verify the results against the checklist provided in this document; we do not claim that OmniDoc utilizes the open-source libraries or internal algorithms referenced herein, nor do we substitute examples for formal product performance testing.
- 1 -
Updated 2026-10-08