Skip to content

fix(docx): keep hyperlink runs nested in a wrapper - #4576

Merged
PeterStaar-IBM merged 1 commit into
docling-project:mainfrom
Yuilona:fix/docx-hyperlink-wrapped-runs
Oct 5, 2026
Merged

PeterStaar-IBM merged 1 commit into
docling-project:mainfrom
Yuilona:fix/docx-hyperlink-wrapped-runs

Conversation

@Yuilona

@Yuilona Yuilona commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

The Word backend dropped hyperlink text that sits in a wrapper inside the w:hyperlink. A tracked insertion made inside link text (<w:hyperlink><w:ins><w:r>…) is the common case, and smart tags, custom XML and simple fields behave the same way.

_iter_paragraph_content already reads runs inside w:ins, w:smartTag, w:customXml and w:fldSimple when they wrap runs directly in the paragraph. A hyperlink's text, however, came from python-docx's Hyperlink.text, and its formatting from Hyperlink.runs. Both only read the direct w:r children (CT_Hyperlink.text is "".join(r.text for r in self.xpath("w:r"))). This PR collects the hyperlink's runs with the same _get_children_recursive helper, so text and formatting come from all of its runs, in document order. The hyperlink target is unchanged.

<w:hyperlink> content Before After
[the ] <w:ins>[docs]</w:ins> the the docs
<w:smartTag>[docs]</w:smartTag> (empty) docs
<w:customXml>[docs]</w:customXml> (empty) docs
<w:fldSimple>[docs]</w:fldSimple> (empty) docs

This touches a different part of _iter_paragraph_content from #4369, which adds moveTo, dir and bdo to the paragraph-level wrappers. Once both are in, those wrappers will be read inside hyperlinks too. #4455 covers wrapped runs in plain table cells, which take a separate path.

Issue resolved by this Pull Request:
Resolves #4575

Testing (Linux, Python 3.11):

  • I added test_hyperlink_keeps_runs_nested_in_a_wrapper, parametrized over the four wrappers. It checks that the link item reads the docs and keeps its https://example.com/ target. All four cases fail on main and pass with the change.
  • tests/test_backend_msword.py passes, and the DOCX ground-truth files are unchanged.
  • I ran the other backend suites as well: html, mhtml, epub, email, markdown, xlsx, pptx, odf, jats, uspto, mets-gbs, vtt, asciidoc, csv, latex and docling-json. 523 passed. One test, test_email_backend_collapses_line_breaks_in_headers, fails the same way on main in my environment.
  • ruff format and ruff check are clean. ty check on the file gives the same diagnostics as on main.

Checklist:

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

Disclosure: this PR is AI-assisted. Claude Code found the bug while converting randomly generated DOCX files and checking that every word survived, then wrote the fix and the tests and ran the checks above.

🤖 Generated with Claude Code

python-docx's Hyperlink.text and Hyperlink.runs only read the direct w:r
children of a w:hyperlink, so text in a tracked insertion, smart tag,
custom XML or simple field inside the link was dropped. Read the
hyperlink's runs through the same wrappers that paragraph runs already
go through.

Resolves docling-project#4575

Signed-off-by: Yuilona <143536279+Yuilona@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

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

@mergify

mergify Bot commented Oct 5, 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)(?:\(.+\))?(!)?:

@PeterStaar-IBM PeterStaar-IBM left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@PeterStaar-IBM
PeterStaar-IBM merged commit 7833b32 into docling-project:main Oct 5, 2026
25 checks passed
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.

DOCX: hyperlink text inside a tracked insertion, smart tag, custom XML or field is dropped

2 participants