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

如何用Apache POI读取含MathML公式的docx并复制到新docx

用Apache POI读取并复制含MathML公式的docx段落(保留格式与公式)

在docx文件中,MathML公式并非普通文本,而是以Office Open XML的<m:oMath>或<m:oMathPara>节点嵌入在段落的底层XML结构(CTP,即org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP)中。XWPFParagraph的上层API不会直接暴露这些公式节点,所以直接提取文本会丢失公式内容。

要完整复制包含文本和MathML公式的段落并保留格式,核心思路是直接操作底层OOXML节点,完整复制段落的CTP结构,而非仅复制上层文本内容。

具体实现步骤与代码示例

确保使用的Apache POI版本不低于4.1.2(更高版本对MathML的支持更完善),依赖包至少包含poi、poi-ooxml、poi-ooxml-schemas。

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DocxMathMLCopy {
    public static void main(String[] args) throws IOException {
        // 读取源文档
        try (XWPFDocument sourceDoc = new XWPFDocument(new FileInputStream("source.docx"));
             // 创建目标文档
             XWPFDocument targetDoc = new XWPFDocument()) {

            // 遍历源文档所有段落
            for (XWPFParagraph sourcePara : sourceDoc.getParagraphs()) {
                // 获取源段落的底层CTP节点
                CTP sourceCTP = sourcePara.getCTP();
                
                // 在目标文档创建新段落
                XWPFParagraph targetPara = targetDoc.createParagraph();
                // 复制源CTP内容到目标CTP,避免直接引用源节点导致内存问题
                CTP targetCTP = targetPara.getCTP();
                targetCTP.set(sourceCTP.copy());
                
                // 同步段落样式:若源段落有自定义样式,需同步到目标文档
                String styleId = sourcePara.getStyleID();
                if (styleId != null) {
                    if (targetDoc.getStyles().getStyle(styleId) == null) {
                        XWPFStyle sourceStyle = sourceDoc.getStyles().getStyle(styleId);
                        if (sourceStyle != null) {
                            targetDoc.createStyle().setStyle(sourceStyle.getCTStyle());
                        }
                    }
                    targetPara.setStyle(styleId);
                }
            }

            // 写入目标文档
            try (FileOutputStream out = new FileOutputStream("target.docx")) {
                targetDoc.write(out);
            }
        }
    }
}

关键细节说明

  • 直接复制CTP节点:这是保留所有内容(文本、公式、格式)的核心,CTP包含了段落的全部底层XML结构,包括MathML的<m:oMath>节点,上层API无法完全覆盖这些内容。
  • 样式同步:如果源段落使用了自定义样式,必须将源文档的样式复制到目标文档,否则目标段落的格式会丢失。代码中包含基础样式复制逻辑,复杂样式可能需要额外处理。
  • 版本兼容性:低版本Apache POI对MathML支持有限,建议使用5.x以上稳定版本,避免节点解析异常。

额外:单独提取MathML内容

如果需要单独提取段落中的MathML代码,可以遍历CTP节点的子节点,判断是否为CTOMath类型:

import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;

// 遍历源段落CTP的所有子节点
for (int i = 0; i < sourceCTP.sizeOfAnyArray(); i++) {
    Object node = sourceCTP.getAnyArray(i);
    if (node instanceof CTOMath) {
        // 提取MathML的XML字符串
        String mathML = ((CTOMath) node).xmlText();
        // 后续处理MathML内容...
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:58:29