diff --git a/crates/rdocx-oxml/src/text.rs b/crates/rdocx-oxml/src/text.rs index c2f7b66..4156db8 100644 --- a/crates/rdocx-oxml/src/text.rs +++ b/crates/rdocx-oxml/src/text.rs @@ -174,6 +174,11 @@ impl CT_R { .and_then(|a| std::str::from_utf8(&a.value).ok()?.parse::().ok()) .unwrap_or(0); content.push(RunContent::EndnoteRef { id }); + } else { + // Capture unknown empty child elements (e.g. + // w:commentReference) as raw XML, mirroring the + // Event::Start fallback above. + extra_xml.push(capture_empty_element(e)?); } } Ok(Event::End(ref e)) if matches_local_name(e.name().as_ref(), b"r") => { @@ -652,6 +657,27 @@ mod tests { assert_eq!(parsed.hyperlinks[0].run_end, 2); } + #[test] + fn unknown_empty_run_children_roundtrip() { + // Unknown empty elements inside a run (e.g. w:commentReference) + // must be captured and re-emitted, not silently dropped. + let p = parse_paragraph( + r#"flagged"#, + ); + assert_eq!(p.runs.len(), 2); + assert_eq!(p.runs[1].extra_xml.len(), 1); + + let mut output = Vec::new(); + let mut writer = Writer::new(&mut output); + p.to_xml(&mut writer).unwrap(); + let xml = String::from_utf8(output).unwrap(); + assert!( + xml.contains(r#""#), + "comment reference must survive round-trip: {xml}" + ); + assert!(xml.contains("flagged")); + } + #[test] fn parse_fld_simple_page() { let p = parse_paragraph(