You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用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>

问题原因分析

  1. 依赖版本不兼容:poi-ooxml-schemas版本4.1.2与poi/poi-ooxml的5.2.2版本不匹配,会导致XML对象解析异常,无法正确识别CTSimpleField类型。
  2. 遍历方式低效且易出错:使用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>

关键说明

  1. 依赖优化:用poi-ooxml-full替代poi-ooxml-schemas,包含完整的OOXML schema,解决版本兼容问题。
  2. 代码简化:直接调用CTP.getFldSimpleArray()获取所有简单域,无需手动遍历XML节点,高效且可靠。
  3. 资源管理:使用try-with-resources语法自动关闭流和文档对象,避免资源泄漏。

内容的提问来源于stack exchange,提问作者dominic_peng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:13:10