From 0559e4214e5f4b30c2b02aff22c4813b6f30d2e4 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sat, 14 Nov 2026 04:48:57 +0000 Subject: [PATCH] Read conventional footnote and endnote parts --- crates/docx/src/read.rs | 2 ++ crates/docx/tests/it/note_comments.rs | 31 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/crates/docx/src/read.rs b/crates/docx/src/read.rs index d50625285..5ea11dbd8 100644 --- a/crates/docx/src/read.rs +++ b/crates/docx/src/read.rs @@ -210,6 +210,8 @@ fn read_opened_in(pkg: &Package, chunks: ChunkState) -> Result<(Document, usize, let fallback = match t { rt::STYLES => "word/styles.xml", rt::NUMBERING => "word/numbering.xml", + rt::FOOTNOTES => "word/footnotes.xml", + rt::ENDNOTES => "word/endnotes.xml", _ => return None, }; pkg.get(fallback).map(|_| fallback.to_string()) diff --git a/crates/docx/tests/it/note_comments.rs b/crates/docx/tests/it/note_comments.rs index d333c6adb..749f65897 100644 --- a/crates/docx/tests/it/note_comments.rs +++ b/crates/docx/tests/it/note_comments.rs @@ -17,6 +17,10 @@ fn note(tag: &str, mark: &str, comment: u32, text: &str) -> String { } fn read_doc() -> Document { + read_doc_with_note_relationships(true) +} + +fn read_doc_with_note_relationships(with_note_relationships: bool) -> Document { let doc = format!( r#"Body"# ); @@ -25,10 +29,15 @@ fn read_doc() -> Document { let comments = format!( r#"On the footnoteOn the endnote"# ); + let doc_rels = if with_note_relationships { + DOC_RELS + } else { + r#""# + }; let bytes = zip(&[ ("_rels/.rels", ROOT_RELS.as_bytes()), ("word/document.xml", doc.as_bytes()), - ("word/_rels/document.xml.rels", DOC_RELS.as_bytes()), + ("word/_rels/document.xml.rels", doc_rels.as_bytes()), ("word/footnotes.xml", footnotes.as_bytes()), ("word/endnotes.xml", endnotes.as_bytes()), ("word/comments.xml", comments.as_bytes()), @@ -36,6 +45,26 @@ fn read_doc() -> Document { craft_docx::read(&bytes).unwrap() } +#[test] +fn conventional_note_parts_are_read_without_relationships() { + let d = read_doc_with_note_relationships(false); + let body = d.body[0].as_para().unwrap(); + let refs: Vec<(NoteKind, u32)> = body + .objects + .iter() + .filter_map(|o| match o { + InlineObject::NoteRef { kind, id, .. } => Some((*kind, *id)), + _ => None, + }) + .collect(); + assert_eq!(refs.iter().map(|(kind, _)| *kind).collect::>(), [NoteKind::Footnote, NoteKind::Endnote]); + for ((kind, id), wanted) in refs.into_iter().zip(["Foot.", "End."]) { + let part = d.parts.get(&id).unwrap_or_else(|| panic!("missing {kind:?} part {id}")); + let text = part.blocks[0].as_para().unwrap().plain_text(); + assert!(text.contains(wanted), "{kind:?}: {text:?}"); + } +} + /// comments.xml has to be read before the notes: a note's `w:commentRangeStart` resolves its id /// against the comments already read, and was dropped when the notes came first. #[test]