求助:使用Apache POI获取Word文档域的可行示例代码
问题:Apache POI无法读取Word文档中的域
我正在学习用Apache POI提取Word文档里的域,基于ChatGPT生成的代码做了微调,但代码无法正常进入CTSimpleField的判断分支。下面是我的演示代码、依赖配置,需要能成功读取Word域的示例代码。
演示代码
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.xmlbeans.XmlCursor; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSimpleField; import java.io.FileInputStream; import java.util.List; public class FindSimpleFieldInDocx { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("/Users/pengbo/word/template1.docx"); XWPFDocument document = new XWPFDocument(fis); List<XWPFParagraph> paragraphs = document.getParagraphs(); for (XWPFParagraph para : paragraphs) { System.out.println(para.getText()); XmlCursor cursor = para.getCTP().newCursor(); cursor.selectPath("./*"); while (cursor.toNextSelection()) { XmlCursor.TokenType tokenType = cursor.currentTokenType(); if (tokenType.equals(XmlCursor.TokenType.START)) { if (CTSimpleField.type.getName().getLocalPart().equals(cursor.getName().getLocalPart())) { //无法进入此分支........ CTSimpleField simpleField = (CTSimpleField) cursor.getObject(); String fieldCode = simpleField.getInstr(); System.out.println("找到CTSimpleField: " + fieldCode); } } } cursor.dispose(); } document.close(); fis.close(); } catch (Exception e) { e.printStackTrace(); } } }
依赖配置
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.2</version> </dependency> <!-- Apache POI OOXML --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.2</version> </dependency> <!-- Apache POI OOXML Schemas --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> <!-- 或使用与你的POI版本匹配的最新版本 --> </dependency> <!-- XMLBeans --> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.17.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.17.2</version> </dependency>
问题原因分析
- 依赖版本不兼容:
poi-ooxml-schemas版本4.1.2与poi/poi-ooxml的5.2.2版本不匹配,会导致XML对象解析异常,无法正确识别CTSimpleField类型。 - 遍历方式低效且易出错:使用
XmlCursor遍历节点时,仅比较本地名称未考虑XML命名空间,同时./*的选择路径可能遗漏部分节点。
修正后的可运行代码
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSimpleField; import java.io.FileInputStream; import java.util.List; public class FindSimpleFieldInDocx { public static void main(String[] args) { // 使用try-with-resources自动管理资源,避免泄漏 try (FileInputStream fis = new FileInputStream("/Users/pengbo/word/template1.docx"); XWPFDocument document = new XWPFDocument(fis)) { List<XWPFParagraph> paragraphs = document.getParagraphs(); for (XWPFParagraph para : paragraphs) { System.out.println("段落文本: " + para.getText()); CTP ctp = para.getCTP(); // 直接获取段落中所有简单域节点 CTSimpleField[] simpleFields = ctp.getFldSimpleArray(); for (CTSimpleField field : simpleFields) { String fieldCode = field.getInstr(); System.out.println("找到域指令: " + fieldCode); // 读取域显示的结果文本 if (field.sizeOfRArray() > 0) { String fieldResult = field.getRArray(0).getT(); System.out.println("域显示结果: " + fieldResult); } } } } catch (Exception e) { e.printStackTrace(); } } }
修正后的依赖配置
确保所有POI相关依赖版本一致,使用完整schema包避免缺失:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.2</version> </dependency> <!-- 替换为poi-ooxml-full,包含完整OOXML schema定义 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-full</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.17.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.17.2</version> </dependency>
关键说明
- 依赖优化:用
poi-ooxml-full替代poi-ooxml-schemas,包含完整的OOXML schema,解决版本兼容问题。 - 代码简化:直接调用
CTP.getFldSimpleArray()获取所有简单域,无需手动遍历XML节点,高效且可靠。 - 资源管理:使用try-with-resources语法自动关闭流和文档对象,避免资源泄漏。
内容的提问来源于stack exchange,提问作者dominic_peng
相关产品推荐
相关产品推荐

