已添加MAVEN依赖时如何解决XPATH相关java.lang.RuntimeException报错
问题根本原因
该XPath执行失败的核心原因有两点:
- XPath中用到的
v:命名空间未提前注册,xmlbeans无法识别对应的前缀,导致路径解析失败 - 你引入的
xmlbeans-xpath 2.6.0版本和主流POI版本依赖的xmlbeans版本不兼容,额外引入的Saxon-HE也不是该场景的必要依赖
可行解决方案
第一步:调整POM依赖
首先删除你之前手动引入的xmlbeans-xpath和Saxon-HE依赖,POI 4.x及以上版本自带的xmlbeans依赖已经内置XPath支持,不需要额外引入扩展包,确保核心POI依赖版本稳定即可,示例如下:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency>
第二步:修改水印读取代码
在XPath中补充命名空间声明后再执行查询,修改后的代码如下:
private String getWaterMark(XWPFDocument document) { try { XWPFHeader defaultHeader = document.getHeaderFooterPolicy().getDefaultHeader(); if(defaultHeader == null) { return ""; } // 提前声明v命名空间 final String xpathFilter = "declare namespace v='urn:schemas-microsoft-com:vml'; data(//v:shape[contains(@id,'PowerPlusWaterMarkObject')]/v:textpath/@string)"; XmlObject[] xmlobjects = defaultHeader._getHdrFtr().selectPath(xpathFilter); if(xmlobjects != null && xmlobjects.length > 0) { return xmlobjects[0].toString(); } return ""; } catch (Exception ex) { logger.error("Error while getting Watermark content from document: ", ex); return ""; } }
高兼容备选方案
如果上述方案依然不生效,可以不用XPath,直接遍历节点获取水印内容,适配性更强:
private String getWaterMark(XWPFDocument document) { try { XWPFHeader defaultHeader = document.getHeaderFooterPolicy().getDefaultHeader(); if(defaultHeader == null) { return ""; } QName shapeQName = QName.valueOf("urn:schemas-microsoft-com:vml", "shape"); QName idQName = QName.valueOf("", "id"); QName textpathQName = QName.valueOf("urn:schemas-microsoft-com:vml", "textpath"); QName stringQName = QName.valueOf("", "string"); XmlObject[] shapes = defaultHeader._getHdrFtr().selectChildren(shapeQName); for (XmlObject shape : shapes) { XmlObject idAttr = shape.selectAttribute(idQName); if (idAttr != null && idAttr.getStringValue().contains("PowerPlusWaterMarkObject")) { XmlObject[] textPaths = shape.selectChildren(textpathQName); if (textPaths.length > 0) { XmlObject stringAttr = textPaths[0].selectAttribute(stringQName); if (stringAttr != null) { return stringAttr.getStringValue(); } } } } return ""; } catch (Exception ex) { logger.error("Error while getting Watermark content from document: ", ex); return ""; } }
内容的提问来源于stack exchange,提问作者Sahib Yar
相关产品推荐
相关产品推荐

