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

如何使用POI获取嵌套在sdt/sdtContent中的Word文本Run?

递归获取Word段落中所有Run元素(含SDT嵌套内容)

在POI 5.2.5中,XWPFParagraph.getIRuns()只能获取段落直接嵌套的Run元素,对于嵌套在**内容控件(XWPFSDT)**里的Run,由于XWPFSDTContent的bodyElements是私有变量,无法直接访问,可通过以下两种方式递归获取所有Run:

方法一:利用底层XML结构(推荐,兼容性好)

通过XWPFSDTContent.getCTSdtContent()获取底层XML对象,遍历其中的段落节点并转换为XWPFParagraph,再递归收集Run元素:

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtContent;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import java.util.ArrayList;
import java.util.List;

public static List<XWPFRun> getAllRunsFromParagraph(XWPFParagraph paragraph) {
    List<XWPFRun> runs = new ArrayList<>();
    for (IRunElement runElement : paragraph.getIRuns()) {
        if (runElement instanceof XWPFRun run) {
            // 直接收集普通Run
            runs.add(run);
        } else if (runElement instanceof XWPFSDT sdt) {
            Object content = sdt.getContent();
            if (content instanceof XWPFSDTContent sdtContent) {
                CTSdtContent ctSdtContent = sdtContent.getCTSdtContent();
                // 遍历SDT内容中的所有段落节点
                for (CTP ctP : ctSdtContent.getPList()) {
                    // 将XML节点转换为XWPFParagraph对象
                    XWPFParagraph nestedPara = new XWPFParagraph(ctP, paragraph.getBody());
                    // 递归收集嵌套段落中的Run
                    runs.addAll(getAllRunsFromParagraph(nestedPara));
                }
                // 若SDT中包含表格等其他元素,可在此扩展处理逻辑
            }
        }
    }
    return runs;
}

使用示例:

final Iterator<XWPFParagraph> it = doc.getParagraphsIterator();
while (it.hasNext()) {
    XWPFParagraph paragraph = it.next();
    List<XWPFRun> allRuns = getAllRunsFromParagraph(paragraph);
    // 处理所有收集到的Run
    for (XWPFRun run : allRuns) {
        String text = run.getText(0);
        // 执行你的业务逻辑,比如打印文本、修改样式等
        if (text != null) {
            System.out.println(text);
        }
    }
}

方法二:反射获取私有变量(简洁但依赖内部实现)

通过Java反射机制直接访问XWPFSDTContent的私有bodyElements变量,适合快速开发,但需注意POI版本更新可能导致变量名变更:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xwpf.usermodel.*;

// 反射工具方法:获取XWPFSDTContent的私有bodyElements
private static List<IBodyElement> getSDTContentBodyElements(XWPFSDTContent sdtContent) throws Exception {
    Field field = XWPFSDTContent.class.getDeclaredField("bodyElements");
    field.setAccessible(true);
    return (List<IBodyElement>) field.get(sdtContent);
}

// 递归收集所有Run
public static List<XWPFRun> getAllRunsFromParagraph(XWPFParagraph paragraph) throws Exception {
    List<XWPFRun> runs = new ArrayList<>();
    for (IRunElement runElement : paragraph.getIRuns()) {
        if (runElement instanceof XWPFRun run) {
            runs.add(run);
        } else if (runElement instanceof XWPFSDT sdt) {
            Object content = sdt.getContent();
            if (content instanceof XWPFSDTContent sdtContent) {
                List<IBodyElement> bodyElements = getSDTContentBodyElements(sdtContent);
                for (IBodyElement element : bodyElements) {
                    if (element instanceof XWPFParagraph nestedPara) {
                        runs.addAll(getAllRunsFromParagraph(nestedPara));
                    }
                }
            }
        }
    }
    return runs;
}

使用时需处理反射可能抛出的异常(如NoSuchFieldException、IllegalAccessException)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:32:45