Skip to content

fix(docx): skip non-element XML nodes - #4564

Open
chriscoveries wants to merge 1 commit into
docling-project:mainfrom
chriscoveries:fix/docx-xml-comment
Open

chriscoveries wants to merge 1 commit into
docling-project:mainfrom
chriscoveries:fix/docx-xml-comment

Conversation

@chriscoveries

@chriscoveries chriscoveries commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Problem

WordprocessingML bodies can contain XML comments or processing instructions between ordinary document elements. The DOCX backend passes every child node to etree.QName, but lxml represents these non-element nodes with callable tags. etree.QName raises ValueError, aborting the entire conversion.

Reproducer

Create a DOCX with a paragraph before and after an XML comment or processing instruction in word/document.xml, then convert it with MsWordDocumentBackend. Before this change, conversion fails while walking the document body.

The regression test constructs this DOCX entirely at test time and does not add a binary fixture.

Fix

Skip child nodes whose lxml tag is not a string before performing QName or XPath processing. This preserves existing handling for WordprocessingML elements while safely ignoring comments and processing instructions.

Tests

$ uv run pytest tests/test_backend_msword.py -k non_element_nodes -vv
tests/test_backend_msword.py::test_non_element_nodes_do_not_abort_conversion PASSED
1 passed, 68 deselected in 52.10s

$ make validate
trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
check yaml...........................................(no files to check)Skipped
check toml...........................................(no files to check)Skipped
check for merge conflicts................................................Passed
check for added large files..............................................Passed
Insert license header....................................................Passed
Ruff linter..............................................................Passed
Ruff formatter...........................................................Passed
ty.......................................................................Passed
Tach.....................................................................Passed
Tach module coverage.....................................................Passed
Check max lines per file.................................................Passed
Dprint check.........................................(no files to check)Skipped
uv-lock..............................................(no files to check)Skipped

Commit: f4c766cd178248e188312b9acd50bca372749528

Signed-off-by: chriscoveries 212684707+chriscoveries@users.noreply.github.com


Signed-off-by: chriscoveries <212684707+chriscoveries@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

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

@mergify

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

) -> tuple[DoclingDocument, list[RefItem]]:
added_elements = []
for element in body:
if not isinstance(element.tag, str):

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.

Should we have this text in a ContentLayer. I am generally not a fan of omitting text, unless it is format related.

@dolfim-ibm

Copy link
Copy Markdown
Member

@chriscoveries @loickouao @PeterStaar-IBM: #4564 and #4584 fix the same crash. XML comment and processing-instruction nodes in a DOCX part are not elements, so etree.QName(element) fails on them and the conversion stops. Only one of the two PRs can merge, so let's align on one.

#4564 #4584
Comment / PI nodes directly under w:body skipped in _walk_linear removed
Nodes nested in paragraphs, runs, cells, rows not handled removed
Comment text dropped kept in the NOTES content layer
Review request to keep the text in a ContentLayer open addressed

Proposal: continue with #4584 as the single fix, and close #4564, with credit to @chriscoveries for the first fix and the test case.

Before #4584 can merge, it still needs:

  • Replace getattr(part, "_element", None) with isinstance(part, XmlPart) and the public part.element (XmlPart from docx.opc.part). AGENTS.md asks to avoid attribute probing.
  • A rebase on main. The conflict is only in tests/test_backend_msword.py.

@chriscoveries: if the body-level test in #4564 covers a case that #4584 does not, please say so here, and it can move into #4584.
@PeterStaar-IBM: please confirm that this direction matches your review on both PRs.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants