Two DOCX to HTML converters add a hidden td on every merged row
A Word table with merged cells usually looks fine after conversion, which is exactly why the markup is worth counting instead of eyeballing. On one homemade DOCX I counted a 5-column, 4-row table that merges both ways, a
A Word table with merged cells usually looks fine after conversion, which is exactly why the markup is worth counting instead of eyeballing. On one homemade DOCX I counted a 5-column, 4-row table that merges both ways, and two of the five outputs handed me more cells than the table has: 2 / 5 / 4 / 5 per row, where the markup should read 2 / 5 / 3 / 3. On screen both of them were right. The three extra cells were there all along, carrying display:none.
The five outputs came from Mammoth 1.13.0 (the JS and Python builds are byte-identical, 10,167 bytes each), pandoc 3.13, docx-preview 0.4.1 running in a desktop Chromium, ImgIng https://imging.ai/ , a browser-side DOCX to HTML converter I ran without signing in, and a forty-line script of my own that reads w:tblGrid and counts w:vMerge continuations into rowspan. One Apple silicon Mac, one sample document of 43,790 bytes with three merged tables in it, one run each. I built the sample myself, so a real contract or report full of text boxes and floating shapes may well behave differently.
What the three extra cells actually are
They are ordinary table cells in the markup, carrying display:none in the style attribute with one empty paragraph inside. Every one of them sits on a continuation row of a vertical merge, directly under the cell that owns the rowspan. The second sample table merges only downward, three columns by four rows: Mammoth, pandoc and my own script emit 3 / 3 / 2 / 2 cells per row, while docx-preview emits 3 / 3 / 3 / 3 and so does the browser-side converter, two hidden cells each. So the rate holds across both tables: one hidden cell per continuation row, every time.
I did not read anyone's source, and this is only what the output suggests: in the XML a continuation cell is a real cell that owns a grid slot, and keeping it as a hidden cell leaves the markup shaped like the document it came from. The libraries do the other thing and swallow it. Both choices render the same page.
A cell count comes out one column too wide
What I measured is the count itself. On the rows that hold three cells, the DOM of those two outputs reports four and five. Since the grid is five columns across, the last row reads like a plain row of five single cells rather than a row with a merge running through it. The widths still come out right, because the browser never lays out what it does not display.
The part that worries me is the next program down the line, and here I am guessing rather than reporting: I never ran these particular files through pandas.read_html or pasted them into a spreadsheet. Anything that counts cells without applying CSS should see one extra empty column, and I would check that before building a pipeline on top of it.
Filter by style before you count anything
The fix is boring, one line of filtering. The helper below is written from the definition, not lifted from the script that produced the counts above:
def visible_cells(row):
return [td for td in row.find_all("td")
if "display:none" not in (td.get("style") or "").replace(" ", "")]
With the hidden cells dropped, every row of every output occupies exactly five grid slots once you add up the colspans and carry down what the rowspans above owe each row. Leave them in, and the same check accuses docx-preview and the browser converter of filling six slots in a five-column grid, which is a false alarm about an output that was correct. A plain count of empty cells goes wrong the same way and needs the same filter first. The colspan and rowspan values themselves were right in all five outputs, so the claim that open-source libraries cannot handle merged cells did not reproduce on this document.
Which output to hand to another program
If the HTML is going to be parsed, the three that matched the expected per-row counts on this sample are Mammoth, pandoc and the script, and they are the ones that kept headings and lists as h1 to h3 and ul / ol. The two that render Word inside a page kept the header and footer, which both libraries dropped here, and turned headings and lists into styled paragraphs. That reads less like a defect than like a page meant to be read as it was printed, rather than a document re-structured for a CMS, and it is worth knowing before you pick one.
Still open on my side: one sample, one machine, single runs, and I only tried the two browser-side renderers I happened to have. I also never built a document where a continuation cell carries text of its own, which is where I would expect the hidden-placeholder habit to actually lose something. Until then the working rule is short, which is to filter by display:none, then count, then compare against the grid column count rather than against the row above.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.