Skip to content

fix(backend): identify and preserve subscripts and superscripts in table cells - #4809

Open
abhinavchinna wants to merge 1 commit into
docling-project:mainfrom
abhinavchinna:fix/table-subscript-superscript
Open

abhinavchinna wants to merge 1 commit into
docling-project:mainfrom
abhinavchinna:fix/table-subscript-superscript

Conversation

@abhinavchinna

Copy link
Copy Markdown

Summary

This PR fixes an issue where subscript and superscript formatting inside table cells was either dropped or broken into disconnected block paragraphs across document backends (DOCX, ODF, JATS XML, and Chandra/Dots).

Changes

  • DOCX (msword_backend.py):
    • Preserves InlineGroup items when grouping elements in rich table cells instead of stripping runs into flat UNSPECIFIED groups.
    • Wraps standalone runs with script formatting in an InlineGroup.
    • Passes the parent paragraph to Run instances in _is_rich_table_cell to ensure run formatting is read accurately.
  • ODF (opendocument_backend.py):
    • Checks paragraph children for styled text:span and text:a tags in _odf_cell_has_rich_content to prevent single-paragraph cells with script formatting from degrading to plain text cells.
  • JATS XML (jats_backend.py):
    • Added HTML inline format tags (b, i, u, s) to _JATS_FORMAT_TAG_MAP.
    • Added _walk_soup_cell to preserve inline formatting (<sub>, <sup>, links) inside table cells and constructs RichTableCell pointing to an InlineGroup.
    • Guarded doc_info.internalDTD from AttributeError when internalDTD is None.
  • Chandra / Dots (chandra_utils.py):
    • Wraps single runs with Script.SUB or Script.SUPER into an InlineGroup.
  • Tests:
    • Added unit tests verifying table cell subscript/superscript preservation in tests/test_backend_msword.py, tests/test_backend_opendocument.py, and tests/test_backend_jats.py.
    • Updated groundtruth references where table scripts were previously discarded.

Validation

  • Pre-commit hooks (prek / ruff, ty, tach, line checks) pass cleanly.
  • Full targeted test suite passes.

…ble cells

Ensure table cells identify, preserve, and serialize subscript and superscript
formatting identically to body text across all document backends:

- DOCX: Preserve InlineGroup elements inside rich table cell groups instead
  of stripping runs to unformatted groups. Wrap standalone formatted runs
  in an InlineGroup and pass the parent paragraph context to Run instances.
- ODF: Check paragraph children for styled text:span and text:a tags in
  _odf_cell_has_rich_content so single-paragraph cells with script formatting
  are classified as rich.
- JATS XML: Walk soup table cells with _walk_soup_cell to preserve inline
  script tags (sub, sup), map HTML format tags (b, i, u, s), and construct
  RichTableCell pointing to the emitted InlineGroup. Guard internalDTD
  against NoneType error.
- Chandra / Dots: Ensure single runs with Script.SUB or Script.SUPER are
  wrapped in an InlineGroup.
- Tests: Add targeted unit tests for DOCX, ODF, and JATS table cell script
  preservation and update groundtruth data where table scripts were previously
  dropped.

Signed-off-by: abhinav chinna lachannagari <abhi02111999@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

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

@mergify

mergify Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 1 of 2 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 Require two reviewer for test updates 👀 reviews
🟢 Enforce conventional commit —

🔴 Require two reviewer for test updates

Waiting for

  • #approved-reviews-by >= 2
This rule is failing.

When test data is updated, we require two reviewers

  • #approved-reviews-by >= 2

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)(?:\(.+\))?(!)?:

@github-actions github-actions Bot added ai:ci-needs-care AI triage: check CI-safety findings before you approve CI bug Something isn't working docx issue related to docx backend odf Issue related to the OpenDocument format (ODT, ODS, ODP) backend table structure xml issue related to supported schema-specific XML formats labels Oct 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

AI triage (advisory)

Checked commit ba9b91d5e2. The analysis read the diff only. It did not run code from this pull request.

The PR keeps subscript and superscript formatting inside table cells for DOCX, ODF, JATS XML and Chandra/Dots output. Table cells with scripts now become RichTableCell items that point to an inline group. The PR also guards a None internalDTD in the JATS backend.

Topic labels added: bug, docx, odf, xml, table structure.

CI safety: needs maintainer care before you approve CI.

  • .github/max-lines-ignore: changes CI workflows, actions, or CI scripts
1 related pull request(s) in the same code
PR State Signal Assessment
#4393 open changes the same code related: It changes DOCX table parsing in msword_backend.py to read rows and cells inside customXml or sdt. This PR changes how rich cell content is grouped. The two fix different problems.

Reference data changes

Change Files
structure 5
tables 4
text 8
  • structure tests/data/docx/groundtruth/docx_rich_cells.docx.json: reading order changed
  • structure tests/data/jats/groundtruth/elife-56337.nxml.json: text: 112 → 133
  • structure tests/data/jats/groundtruth/pntd.0008301.nxml.json: text: 109 → 113
  • structure tests/data/jats/groundtruth/pone.0234687.nxml.json: text: 435 → 648
  • structure tests/data/odf/groundtruth/text_document_03.odt.json: text: 26 → 44
  • tables tests/data/jats/groundtruth/elife-56337.nxml.md: +7 / -7 lines; Markdown table rows changed
  • tables tests/data/jats/groundtruth/pntd.0008301.nxml.md: +2 / -2 lines; Markdown table rows changed
  • tables tests/data/jats/groundtruth/pone.0234687.nxml.md: +49 / -49 lines; Markdown table rows changed
  • tables tests/data/odf/groundtruth/text_document_03.odt.md: +2 / -2 lines; Markdown table rows changed
  • text tests/data/docx/groundtruth/docx_rich_cells.docx.html: +2 / -16 lines
  • text tests/data/docx/groundtruth/docx_rich_cells.docx.itxt: +40 / -40 lines
  • text tests/data/docx/groundtruth/docx_rich_cells.docx.md: line or paragraph breaks changed
  • text tests/data/jats/groundtruth/elife-56337.nxml.itxt: +235 / -200 lines
  • text tests/data/jats/groundtruth/pntd.0008301.nxml.itxt: +196 / -188 lines
  • text tests/data/jats/groundtruth/pone.0234687.nxml.itxt: +852 / -525 lines
  • text tests/data/odf/groundtruth/text_document_03.odt.html: +5 / -5 lines
  • text tests/data/odf/groundtruth/text_document_03.odt.itxt: +95 / -71 lines

Assessment: expected. The changes match the code change. The JATS and ODF files gain text items and changed table rows because cells with scripts now get inline groups. The DOCX file changes reading order because cell content is now grouped differently. The diff content of these files was not available, so the exact text was not checked.

The ai:* labels are advisory. They do not approve CI and they do not add tests:full. A new push runs this check again.

@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.36508% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
docling/backend/xml/jats_backend.py 75.67% 6 Missing and 3 partials ⚠️
docling/backend/msword_backend.py 83.33% 1 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

This branch has not been deployed

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

Labels

ai:ci-needs-care AI triage: check CI-safety findings before you approve CI bug Something isn't working docx issue related to docx backend odf Issue related to the OpenDocument format (ODT, ODS, ODP) backend table structure xml issue related to supported schema-specific XML formats

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant