Skip to content

fix(html): escape pipe characters in table cells - #2439

Open
Soroush Ahmadi (soroush5) wants to merge 1 commit into
microsoft:mainfrom
soroush5:fix/html-table-pipe-escape
Open

fix(html): escape pipe characters in table cells#2439
Soroush Ahmadi (soroush5) wants to merge 1 commit into
microsoft:mainfrom
soroush5:fix/html-table-pipe-escape

Conversation

@soroush5

Copy link
Copy Markdown

Fixes #2438.

markdownify passes table cell text through untouched, so a literal pipe in a cell splits the Markdown row into phantom columns. This adds convert_td/convert_th overrides on _CustomMarkdownify that escape unescaped pipes, mirroring the base logic otherwise (colspan handling, newline collapsing).

The match is parity-correct: already-escaped pipes are left alone, so converters that pre-escape before reaching this layer (XLSX via _escape_sheet, PPTX in #1785) are unaffected — no double escaping. DOCX tables are fixed as well since they convert via the HTML converter (verified end-to-end with a .docx containing a pipe in a table cell).

Tests: 3 new cases in test_html_converter.py (cell pipe, header pipe, no double-escape). The first two fail before the fix, all pass after. Full package suite green: 649 passed, 4 skipped.

A literal pipe in a table cell is data, not a column separator.
markdownify passes cell text through untouched, so 'a|b' rendered
as phantom columns. Escape unescaped pipes in convert_td/convert_th.
The match is parity-correct (already-escaped pipes are left alone),
so converters that pre-escape (XLSX, PPTX) are unaffected. This also
fixes DOCX tables, which convert via the HTML converter.
@soroush5

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@erekola

Copy link
Copy Markdown

I tested d5d07b1 with four two-column HTML tables and rendered the Markdown with markdown-it-py 4.2.0, with table support enabled. The first cell contained a plain pipe, a pipe inside inline code, a pipe in link text or an HTML pipe entity. The second cell was always end. All four lose that control cell on current main. On this PR all four keep both cells, and the inline code and link still render as code and a link. The converter dependency was markdownify 1.2.3 on Windows with Python 3.13.15.

The inline-code case is a useful extra regression fixture because checking the rendered cells catches content loss that counting separators misses:

<table><tr><th>Value</th><th>Control</th></tr><tr><td><code>a|b</code></td><td>end</td></tr></table>

Expected body cells after rendering are <td><code>a|b</code></td> and <td>end</td>. I ran four parameterized assertions against main and the PR checkout: four failed on main and four passed on the PR. I haven't tested DOCX or the full suite. AI assistance was used for the fixtures, checks and this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTML/DOCX: pipe characters in table cells break Markdown tables

2 participants