You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Apache POI解析Word重复节内的内容控件?

解决Apache POI获取Word重复节内嵌套内容控件的问题

我完全懂你遇到的困扰——当处理包含嵌套内容控件的重复节SDT时,你现有的遍历逻辑只能拿到合并后的文本,没法捕获到独立的嵌套SDT节点。这是因为重复节(Repeating Section)的内部结构在OOXML里比较特殊,嵌套的SDT并不是直接作为顶级的IBodyElement存在的,而是藏在重复节的XWPFSDTContent容器里。

下面是调整后的解决方案,核心是递归遍历SDT的内部内容,同时补上对表格等元素的处理(你的原代码没覆盖表格场景,这也是遗漏点):

完整实现代码

import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xwpf.usermodel.AbstractXWPFSDT;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.IRunElement;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFSDT;
import org.apache.poi.xwpf.usermodel.XWPFSDTContent;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;

private static List<AbstractXWPFSDT> extractSDTsFromBodyElements(List<IBodyElement> elements) {
    List<AbstractXWPFSDT> sdts = new ArrayList<>();
    for (IBodyElement e : elements) {
        if (e instanceof XWPFSDT) {
            XWPFSDT sdt = (XWPFSDT) e;
            sdts.add(sdt);
            // 递归处理当前SDT内部的所有嵌套SDT
            extractSDTsFromSDTContent(sdt.getContent(), sdts);
        } else if (e instanceof XWPFParagraph) {
            XWPFParagraph p = (XWPFParagraph) e;
            for (IRunElement e2 : p.getIRuns()) {
                if (e2 instanceof XWPFSDT) {
                    XWPFSDT sdt = (XWPFSDT) e2;
                    sdts.add(sdt);
                    // 处理段落内SDT的嵌套内容
                    extractSDTsFromSDTContent(sdt.getContent(), sdts);
                }
            }
        } else if (e instanceof XWPFTable) {
            XWPFTable table = (XWPFTable) e;
            // 遍历表格的所有单元格
            for (XWPFTableCell cell : table.getTableCells()) {
                // 递归处理单元格内的元素
                sdts.addAll(extractSDTsFromBodyElements(cell.getBodyElements()));
            }
        }
    }
    return sdts;
}

// 辅助函数:遍历SDT内容里的所有元素,递归查找嵌套SDT
private static void extractSDTsFromSDTContent(XWPFSDTContent content, List<AbstractXWPFSDT> sdts) {
    if (content == null) {
        return;
    }
    // 遍历SDT内容中的所有IBodyElement
    for (IBodyElement element : content.getBodyElements()) {
        if (element instanceof XWPFSDT) {
            XWPFSDT nestedSdt = (XWPFSDT) element;
            sdts.add(nestedSdt);
            // 继续递归处理嵌套SDT的内容
            extractSDTsFromSDTContent(nestedSdt.getContent(), sdts);
        } else if (element instanceof XWPFParagraph) {
            XWPFParagraph p = (XWPFParagraph) element;
            for (IRunElement runElement : p.getIRuns()) {
                if (runElement instanceof XWPFSDT) {
                    XWPFSDT inlineSdt = (XWPFSDT) runElement;
                    sdts.add(inlineSdt);
                    extractSDTsFromSDTContent(inlineSdt.getContent(), sdts);
                }
            }
        } else if (element instanceof XWPFTable) {
            XWPFTable table = (XWPFTable) element;
            for (XWPFTableCell cell : table.getTableCells()) {
                sdts.addAll(extractSDTsFromBodyElements(cell.getBodyElements()));
            }
        }
    }
}

关键改动说明

  1. 递归处理SDT内部内容
    当捕获到一个XWPFSDT时,调用extractSDTsFromSDTContent函数深入其XWPFSDTContent容器,遍历里面的所有元素(段落、表格、嵌套SDT等),确保不会遗漏任何层级的嵌套控件。

  2. 补充表格场景处理
    你的原代码只处理了段落和顶级SDT,而重复节里经常会包含表格,表格单元格内也可能有SDT,所以新增了表格的遍历逻辑,递归处理每个单元格内的元素。

  3. 修复泛型定义
    原函数的List没有指定泛型,调整为List<AbstractXWPFSDT>,让类型更安全。

使用验证

调用这个修改后的函数后,你会发现集合里不仅包含顶级的重复节SDT,还会包含重复节内部所有嵌套的独立SDT节点,每个节点都能单独获取其属性和内容,而不是合并成一段文本。

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

火山引擎 最新活动