Apache POI生成带水印Docx文件打开报错:header4.xml XML声明问题
问题分析与解决方案
问题现象
使用Apache POI 3.10 + Java 1.6生成带水印的Docx文件,下载后用Word打开时提示:
Office Open XML文件无法打开,因为内容存在问题
具体描述为“text/xml声明只能出现在输入的最开头”,位置为word/header4.xml
但浏览器的Docx查看器可正常显示内容、页眉及水印。
原因分析
Apache POI 3.10版本较老旧,其XWPFHeaderFooterPolicy.createWatermark()方法在生成或修改页眉XML时,可能出现XML声明位置错误(比如声明前有空白字符)或重复声明的情况。Word的XML解析器对格式要求严格,会触发报错;而浏览器查看器容错性较高,能正常解析。
解决方案
方案1:手动修复页眉XML格式
通过代码获取页眉的XML内容,确保XML声明仅出现一次且位于内容最开头:
XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy(); headerFooterPolicy.createWatermark("Watermark"); // 遍历所有页眉,修复XML声明问题 for (XWPFHeader header : headerFooterPolicy.getHeaders()) { String xml = header.getHeaderElement().getXML(); // 移除开头的空白字符 xml = xml.trim(); // 移除重复的XML声明(只保留第一个) int declEndIndex = xml.indexOf("?>") + 2; String validXmlStart = xml.substring(0, declEndIndex); String xmlRest = xml.substring(declEndIndex).replaceAll("<\\?xml[^>]*\\?>", ""); xml = validXmlStart + xmlRest; // 更新页眉XML header.getHeaderElement().setXML(xml); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); doc.write(baos); PortletResponseUtil.sendFile(request, res, outputFile, baos.toByteArray(), contentType);
方案2:升级Apache POI版本
如果Java 1.6环境允许,可升级到Apache POI 3.17(支持Java 1.6的最后稳定版本之一),新版本修复了此类XML生成的兼容性问题,无需手动修改代码即可解决报错。
内容的提问来源于stack exchange,提问作者FireHe4d
相关产品推荐
相关产品推荐

