使用OpenXML替换Word文档文本时表格遍历导致替换失效如何解决
问题原因
核心冲突是混用了OpenXML SDK的强类型对象操作和底层流直接修改操作,触发了SDK的缓存覆盖机制:
- 当你调用
doc.MainDocumentPart.Document.Body以及遍历Descendants<Table>()时,OpenXML SDK会将整个文档的XML结构完整加载到内存中缓存,后续你对MainDocumentPart的流做的修改,在WordprocessingDocument对象释放时,会被内存中缓存的原始XML结构直接覆盖,所以修改内容不会生效。 - 移除表格遍历逻辑后,没有触发SDK的内存缓存加载,直接修改流的内容不会被覆盖,所以替换功能正常。
解决方案
有两种可行的修改方式:
方案1:调整操作顺序,先做流修改,再做强类型操作
把文本替换的流操作代码放到表格遍历逻辑之前,保证流修改完成后SDK才加载内存缓存,不会覆盖修改结果:
using System; using System.IO; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; namespace OpenXMLTests { class Program { static void Main(string[] args) { String document = "TestDoc.docx"; using (WordprocessingDocument doc = WordprocessingDocument.Open(document, true)) { // 先执行流修改 string docText = null; using (StreamReader sr = new StreamReader(doc.MainDocumentPart.GetStream())) { docText = sr.ReadToEnd(); } // 注意:如果要替换完整的$Hello$为Goodbye,这里替换规则要改成docText.Replace("$Hello$", "Goodbye") docText = docText.Replace("$", "Goodbye"); using (StreamWriter sw = new StreamWriter(doc.MainDocumentPart.GetStream(FileMode.Create))) { sw.Write(docText); } // 再执行表格遍历的强类型操作 Body body = doc.MainDocumentPart.Document.Body; foreach (Table t in body.Descendants<Table>()) { String tableName = t.GetFirstChild<TableProperties>().TableCaption.Val; Console.WriteLine(tableName); } } } } }
方案2:统一使用强类型API操作内容,不混合流操作
直接通过OpenXML的文本对象进行内容替换,避免缓存冲突,这种方式兼容性更强,不会因为特殊XML结构导致替换出错:
// 替换所有文本中的$Hello$为Goodbye foreach (var textNode in doc.MainDocumentPart.Document.Body.Descendants<Text>()) { textNode.Text = textNode.Text.Replace("$Hello$", "Goodbye"); }
内容的提问来源于stack exchange,提问作者West
相关产品推荐
相关产品推荐

