Skip to content

fix(md): keep inline HTML and autolinks inside GFM table cells - #4479

Closed
devYRPauli wants to merge 1 commit into
docling-project:mainfrom
devYRPauli:fix/md-table-inline-html
Closed

devYRPauli wants to merge 1 commit into
docling-project:mainfrom
devYRPauli:fix/md-table-inline-html

Conversation

@devYRPauli

Copy link
Copy Markdown
Contributor

Inline HTML (<br>, <sub>, <kbd>) or an autolink (<https://...>) in a GFM table cell closes the table at that node. Marko parses these as InlineHTML and AutoLink. _iterate_elements has no branch for them, so they reach the fallback branch, which calls _close_table(). The rest of the row leaks into the body as text.

The <br> example from the issue thread gives this on main:

, C\_D FROM T |

|   c1 | c2         |
|------|------------|
|    1 | SELECT A_B |

With this change it gives:

|   c1 | c2                      |
|------|-------------------------|
|    1 | SELECT A_B , C_D FROM T |

The fix:

  • A new branch in _iterate_elements handles InlineHTML and AutoLink while a table is open. It does not close the table.
  • The text inside a tag pair and the URL of an autolink are RawText children. They reach the cell through the existing RawText path. The tags are dropped.
  • A <br> (also <br/>, <br />, <BR>) adds \n to the cell text. The HTML backend gives the same cell text for <br> in a <td>. The Markdown export already replaces \n in a cell with a space.
  • Outside a table nothing changes.

Cell text from convert_string() on main at bba2ec58 and on this branch:

cell main this branch
SELECT A_B<br>, C_D<br>FROM T SELECT A_B, and , C_D and FROM T | leak as text SELECT A_B\n, C_D\nFROM T
header Name<br>(unit) 2 tables, header Name, (unit) | Value | leaks as text, the delimiter row becomes a header row, row a | 1 is lost 1 table, header Name\n(unit)
CO<sub>2</sub> 2 tables, cell CO, 2 leaks as text, the next row is lost 1 table, cell CO2
<kbd>Ctrl</kbd>+<kbd>C</kbd> 2 tables, cell empty, Ctrl, + and C leak as text 1 table, cell Ctrl+C
see <https://x.org> now 2 tables, cell see, https://x.org and now | x | leak as text 1 table, cell see https://x.org now

An image in a cell still closes the table. A TableCell cannot hold a picture, so that case belongs to the RichTableCell work discussed in #4327.

Tests:

  • New test_convert_table_keeps_inline_html_and_autolinks covers <br> in a header cell, the <br>, <br/> and <br /> spellings, <sub>, <kbd> and an autolink. It checks every cell text and that no text item is added outside the table. It fails on main with 9 text items outside the table, and passes with the fix.
  • tests/test_backend_markdown.py and the 4 other test files that use the Markdown backend: 136 passed. No reference data changed.
  • make validate passes. ty reports the same 2 warnings on md_backend.py as on main.

Issue resolved by this Pull Request:
Resolves #3991

Checklist:

  • Documentation has been updated, if necessary.
  • Examples have been added, if necessary.
  • Tests have been added, if necessary.

Marko parses <br>, <sub> and other inline tags as InlineHTML, and
<https://...> as AutoLink. _iterate_elements has no branch for either,
so in a table cell they reach the fallback branch, which closes the
table. The rest of the row leaks into the body as text.

Keep both in the open table. The text inside a tag pair and the URL of
an autolink are RawText children, so they reach the cell as before. A
<br> adds a line break to the cell, as the HTML backend does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yash Raj Pandey <yashpn62@gmail.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

Thanks @devYRPauli, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 Merge protection satisfied — ready to merge.

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

@dolfim-ibm

Copy link
Copy Markdown
Member

@devYRPauli could this be related to #4488?

@ceberam

ceberam commented Oct 2, 2026

Copy link
Copy Markdown
Member

@devYRPauli Please see my comment on another related issue: #4454 (comment)

With the #4488 we no longer need to do string manipulation to parse tables, in a kind of heuristic text-buffer approach. We can leverage marko to identify the structured tables. In addition, the emphasis and links in table cells are preserved through RichTableCell.

My suggestion is to close this PR #4479 since it gets superseded by #4488

@devYRPauli Please, let us know if you have any comment. Thanks anyway for your willingness to improve Docling and we look forward to more contributions!

@devYRPauli

Copy link
Copy Markdown
Contributor Author

@ceberam @dolfim-ibm Agreed. I ran the five table cases from this PR against #4488 at cd3f85511. All five give one table, and no cell text leaks into the body. On main at a25aa1de, all five leak cell text into the body, and three of them split the table.

One difference stays: #4488 keeps inline HTML tags in the cell text. The cells SELECT A_B<br>, C_D<br>FROM T and CO<sub>2</sub> keep their tags. This PR dropped the tags and turned <br> into a newline, as the HTML backend does. I can open a follow-up for that after #4488 merges, if you want it.

Closing this PR in favor of #4488.

@devYRPauli devYRPauli closed this Oct 2, 2026
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.

md: inline markup inside table cells shreds tables (code spans) and deletes intra-cell spaces

3 participants