DOCX Reference and Citation Extraction#
The DOCX backend (MsWordDocumentBackend in msword_backend.py) has no dedicated support for footnotes, endnotes, bibliographic references, or Word's built-in citation/bibliography feature. This is a current gap — not a design decision with a documented rationale — and it applies equally to:
-
Footnotes / endnotes — the
word/footnotes.xmlandword/endnotes.xmlZIP parts are never opened. Neitherw:footnoteReferencenorw:endnoteReferencerun elements are recognised. The document is loaded viaload_msword_file()which delegates to python-docx'sDocument()constructor, and the only ZIP parts ever accessed directly by the backend are_rels/.rels(Strict OOXML detection) and thenumberingpart . No enumeration of other parts happens. -
Legacy field codes — Word's citation/bibliography feature encodes references with
w:fldChar/w:instrTextfield instructions (e.g.ADDIN ZOTERO_CITATION,ADDIN EN.CITE). The backend never readsw:instrTextand has no code that parses field instructions of any kind.w:fldSimpleelements are stripped as transparent wrappers , forwarding their child nodes for text extraction but discarding the field semantics. -
Word's built-in Bibliography SDT — Word's Insert → Bibliography inserts a
w:sdtblock withw:sdtPr/w:bibliography. The block-level SDT handler walks thew:sdtContentrecursively to recover paragraphs as plain text items; it does not inspect the SDT'sw:sdtPrto identify or specially process bibliography blocks.
What Actually Happens at Runtime#
| Content type | OOXML element | Backend behaviour |
|---|---|---|
| Footnote / endnote body text | word/footnotes.xml, word/endnotes.xml | Silently skipped — parts never loaded |
| In-paragraph footnote anchor (superscript marker) | w:footnoteReference / w:endnoteReference inside w:r | Dropped — only w:t text inside runs is consumed; reference elements have no text and are ignored |
| Inline citation field result | w:fldChar+w:instrText+w:t sequence | Field result w:t text extracted as plain text; instruction text (w:instrText) silently discarded |
Inline w:sdt citation (e.g. [Smith 2020]) | w:sdt with w:sdtPr/w:citation | Text inside w:sdtContent//w:t extracted by inline-SDT path ; formatting from first run preserved; SDT type not inspected |
| Block bibliography list | w:sdt with w:sdtPr/w:bibliography | Paragraphs inside w:sdtContent extracted as plain TextItem nodes ; no DocItemLabel.REFERENCE label assigned |
The net effect: rendered citation markers (e.g. [1] or (Smith 2020)) and rendered bibliography entries appear in the output as ordinary text items — their source identity, DOI, author list, etc. are lost. Footnote and endnote bodies are completely absent from output.
Inline Citation SDT — Detail#
Word uses an inline w:sdt with w:sdtPr/w:citation to mark citation references. This path is handled by _iter_paragraph_content(): the XPath .//w:sdtContent//w:t/text() joins all text nodes inside the SDT into a single string, and formatting is taken from the first w:r child. The result is emitted as a (text, fmt, None) tuple indistinguishable from a regular run .
This path was broken before docling v2.87.0 — inline w:sdt elements were silently dropped entirely, so citation markers such as [1] or (Smith et al.) would disappear from text. The fix landed in PR #3280 (merged 2026-04-13).
Field Instruction Passthrough#
w:fldSimple is the only field-related element the backend touches, and it is handled as a transparent wrapper — its children are recursed into without reading the field instruction attribute . Complex fields (the three-element w:fldChar begin → w:instrText → w:fldChar end sequence) are never detected or unwrapped; their w:t field-result text leaks through as plain runs while instruction text is discarded because w:instrText has no w:t children.
Implications for Consumers#
- Academic / legal documents: expect footnote and endnote bodies to be absent; footnote anchors (superscript numbers) will be absent from body text too.
- Zotero / EndNote / Mendeley DOCX exports: citation markers survive as plain text only if the document was saved with rendered field results; bibliography blocks survive as unstructured text paragraphs if they use
w:sdt. - Workarounds: pre-process DOCX with LibreOffice (
soffice --headless --convert-to docx) to flatten fields to text before passing to Docling; or post-process the OOXML ZIP directly to promoteword/footnotes.xmlcontent into the body document before conversion. No open GitHub issues are currently tracking footnote/endnote support — filing a feature request with a reproduction DOCX would be the appropriate next step.
Primary Sources#
| Resource | Notes |
|---|---|
msword_backend.py | Full backend — search for fldSimple, sdt, footnote |
_iter_paragraph_content() lines 1473–1537 | Inline SDT / field / run dispatch |
_walk_linear() SDT branch lines 860–867 | Block-level SDT recursive walk |
load_msword_file() lines 533–545 | ZIP loading — which parts are read |
| PR #3280 | Inline SDT drop fix (v2.87.0) |
| DOCX SDT Handling KB | Broader SDT context including citation inline SDT fix |