如何使用XPATH或Apache POI从XML中过滤提取水印文本?
Apache POI获取DOCX文档水印的实现方法
方法1:使用现有XPATH准确获取水印值
你写的XPATH本身逻辑正确,只需要补充命名空间声明即可正常执行,POI的XPATH查询要求显式声明所有用到的XML前缀对应的命名空间URI:
import org.apache.xmlbeans.XmlObject; import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFHeader; import java.io.File; import java.io.FileInputStream; public class WatermarkReader { public static void main(String[] args) throws Exception { File docxFile = new File("你的文档路径.docx"); XWPFDocument document = new XWPFDocument(new FileInputStream(docxFile)); XWPFHeaderFooterPolicy headerFooterPolicy = document.getHeaderFooterPolicy(); XWPFHeader defaultHeader = headerFooterPolicy.getDefaultHeader(); // XPATH开头声明v前缀对应的命名空间 String xpath = "declare namespace v='urn:schemas-microsoft-com:vml'; " + "string(//v:shape[contains(@id,'PowerPlusWaterMarkObject')]/v:textpath/@string)"; XmlObject[] results = defaultHeader._getHdrFtr().selectPath(xpath); if (results != null && results.length > 0) { String watermarkText = results[0].newCursor().getTextValue(); System.out.println("水印内容:" + watermarkText); } document.close(); } }
方法1注意事项:
- 命名空间URI必须和你打印的XML里
xmlns:v的取值完全一致,否则查询返回空 - 仅适配Word默认插入的文本水印,自定义插入的图形水印可能需要调整匹配条件
方法2:遍历Header节点获取水印(兼容性更好)
如果不想依赖XPATH,也可以直接遍历Header内的所有VML图形节点,通过POI封装的对象方法读取水印内容,同时支持覆盖所有页面类型的水印:
import com.microsoft.schemas.vml.CTShape; import com.microsoft.schemas.vml.CTTextPath; import org.apache.xmlbeans.XmlObject; import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFHeader; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; public class WatermarkReader { public static void main(String[] args) throws Exception { File docxFile = new File("你的文档路径.docx"); XWPFDocument document = new XWPFDocument(new FileInputStream(docxFile)); XWPFHeaderFooterPolicy headerFooterPolicy = document.getHeaderFooterPolicy(); // 收集所有类型的Header,避免遗漏首页、偶数页的特殊水印 List<XWPFHeader> allHeaders = new ArrayList<>(); if (headerFooterPolicy.getDefaultHeader() != null) allHeaders.add(headerFooterPolicy.getDefaultHeader()); if (headerFooterPolicy.getFirstPageHeader() != null) allHeaders.add(headerFooterPolicy.getFirstPageHeader()); if (headerFooterPolicy.getEvenPageHeader() != null) allHeaders.add(headerFooterPolicy.getEvenPageHeader()); for (XWPFHeader header : allHeaders) { XmlObject[] shapeObjs = header._getHdrFtr().selectPath("declare namespace v='urn:schemas-microsoft-com:vml'; //v:shape"); for (XmlObject shapeObj : shapeObjs) { CTShape shape = CTShape.Factory.parse(shapeObj.newInputStream()); // 匹配水印专属shape id前缀 if (shape.getId() != null && shape.getId().contains("PowerPlusWaterMarkObject")) { CTTextPath textPath = shape.getTextPath(); if (textPath != null) { String watermarkText = textPath.getString(); System.out.println("水印内容:" + watermarkText); } // 如需识别图片水印,可读取shape.getFill().getSrc()属性获取图片资源 } } } document.close(); } }
方法2优势:
- 覆盖所有页面类型的水印设置,不会遗漏特殊配置的首页、偶数页水印
- 同时支持文本水印、图片水印的识别,扩展性更强
- 直接调用POI封装的对象方法,稳定性高于纯XPATH字符串查询
内容的提问来源于stack exchange,提问作者Sahib Yar
相关产品推荐
相关产品推荐

