克隆/编辑DOCX保存后wpg命名空间丢失,Word提示“无法读取内容”怎么办?
问题
使用docx4j(docx4j-JAXB-MOXy v11.4.9)向DOCX文件添加图片后,通过OnlyOffice编辑该文件。后续执行加载DOCX、克隆文件、清空正文、复制部分原始内容并保存的操作时,图片依赖的wpg命名空间被移除,导致Word打开文件时提示“无法读取内容”。
原始文件的document.xml顶部包含以下命名空间,保存后的文件中该命名空间缺失:
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
document.xml中wpg命名空间用于图片备用内容的代码片段:
<w:r> <w:rPr> <w:color w:val="000000"/> </w:rPr> <w:t xml:space="preserve">Image :</w:t> <mc:AlternateContent> <mc:Choice Requires="wpg"> <w:drawing> ... </w:drawing> </mc:Choice> <mc:Fallback> <w:pict> ... </w:pict> </mc:Fallback> </mc:AlternateContent> </w:r>
可复现问题的示例代码:
InputStream mergedDocStream = new BufferedInputStream(new FileInputStream("c:\\tmp\\original.docx"), 8 * 1024 * 1024); WordprocessingMLPackage mergedDoc = WordprocessingMLPackage.load(mergedDocStream); mergedDocStream.close(); List<Object> mergedDocContentList = mergedDoc.getMainDocumentPart().getContent(); // 获取包含样式、方向、页眉页脚的节属性 SectPr finalSectionProperties = mergedDoc.getMainDocumentPart().getJaxbElement().getBody().getSectPr(); // 用原文件创建空白目标文档 ObjectFactory objectFactory = new ObjectFactory(); mergedDoc.getMainDocumentPart().getJaxbElement().setBody(objectFactory.createBody()); WordprocessingMLPackage outputDoc = (WordprocessingMLPackage) mergedDoc.clone(); // 遍历原始内容并添加到目标文档 for (Object content : mergedDocContentList) { outputDoc.getMainDocumentPart().addObject(content); } // 添加节属性以保留原样式 outputDoc.getMainDocumentPart().getJaxbElement().getBody().setSectPr(finalSectionProperties); // 保存文档 File outputFile = new File("c:\\tmp\\output.docx"); outputDoc.save(outputFile);
解决方案
方法1:手动向目标文档的Document元素添加命名空间
在克隆outputDoc之后,直接给目标文档的Document对象添加wpg命名空间声明:
// 克隆outputDoc后插入这段代码 Document outputDocDocument = outputDoc.getMainDocumentPart().getJaxbElement(); if (outputDocDocument.getNamespaceDecls() == null) { outputDocDocument.setNamespaceDecls(new HashMap<>()); } outputDocDocument.getNamespaceDecls().put("wpg", "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup");
方法2:保留原始文档的命名空间上下文
避免直接清空原始文档的body再克隆,而是创建新的文档包并复制原始文档的所有命名空间声明:
// 替换原代码中创建outputDoc的逻辑 WordprocessingMLPackage outputDoc = WordprocessingMLPackage.createPackage(); // 复制原始文档的命名空间映射 Document originalDocument = mergedDoc.getMainDocumentPart().getJaxbElement(); Document outputDocDocument = outputDoc.getMainDocumentPart().getJaxbElement(); if (originalDocument.getNamespaceDecls() != null) { outputDocDocument.setNamespaceDecls(new HashMap<>(originalDocument.getNamespaceDecls())); } // 后续继续添加内容和节属性
方法3:确保JAXB序列化时保留命名空间
由于docx4j使用MOXy作为JAXB实现,若文档内容中存在依赖wpg的元素(如<mc:Choice Requires="wpg">),MOXy理论上会自动保留该命名空间。但如果克隆过程中丢失了上下文,需确保复制内容时完整保留包含mc:AlternateContent的元素,同时可通过手动添加命名空间的方式强制保留。
内容的提问来源于stack exchange,提问作者BenHT
相关产品推荐
相关产品推荐

