当前位置: 代码网 > it编程>编程语言>Java > Java按顺序提取Word内容的方法步骤(文本+数学公式)

Java按顺序提取Word内容的方法步骤(文本+数学公式)

2025年09月26日 Java 我要评论
一、背景因业务需求,目前正在实现一项需求,即将一份试卷的内容提取出来,由非结构化到结构化的转换。在试卷解析的时候在解析数学公式的时候花了一番功夫,当成功把word中的数学公式提出来并且转换为latex

一、背景

因业务需求,目前正在实现一项需求,即将一份试卷的内容提取出来,由非结构化到结构化的转换。在试卷解析的时候在解析数学公式的时候花了一番功夫,当成功把word中的数学公式提出来并且转换为latex之后已经大功告成了呢,突然发现从word读取到的公式转换成的latex不能放到准确的位置,造成了顺序错乱的问题。本方案只是我本人实践的一种方法(不一定是最好的方法),于是写下来分享给大家。

二、概述

从一份word格式的试卷中读取内容,使用poi读取word文件,按照xwpfparagraph进行遍历,处理每一个xwpfparagraph,从xwpfparagraph获取xmltext;开始parserxmltext内容(基于org.w3c.dom.document);找到omath节点后转换为latex,将latex替换掉omath节点后产生新的xmltext,将新的xmltext设置到xwpfparagraph,将xwpfdocument持久化成新的word文档

三、正文

1、准备一份原始word文件

2、使用poi读取word文件,按照xwpfparagraph进行遍历

 
    /**
     * 提取公式并替换为唯一标识符
     * @param fis 原始word文档路径
     * @param outputpath 处理后word文档路径
     * @return 公式与标识符的映射关系
     */
    public map<string, string> extractandreplaceformulas(inputstream fis, string outputpath) {
        map<string, string> formulamap = new hashmap<>();
 
        try {
            try (xwpfdocument document = new xwpfdocument(fis)) {
 
                // 遍历所有段落
                for (xwpfparagraph paragraph : document.getparagraphs()) {
                    processparagraphviaxml(paragraph, formulamap);
                }
 
                // 保存处理后的文档
                try (fileoutputstream fos = new fileoutputstream(outputpath)) {
                    document.write(fos);
                }
            }
        } catch (exception e) {
            log.error("extractandreplace formulas: {0}", e);
        }
 
        return formulamap;
    }

3、处理每一个xwpfparagraph,从xwpfparagraph获取xmltext

    /**
     * 通过xml直接处理段落中的公式
     */
    public void processparagraphviaxml(xwpfparagraph paragraph, map<string, string> formulamap) {
        try {
            ctp ctp = paragraph.getctp();
 
            // 获取段落的xml内容
            string originalxml = ctp.xmltext();
 
            // 处理xml,替换公式
            string newxml = parserxml(originalxml, formulamap);
 
            // 用新的xml替换原来的段落内容
            ctp newctp = ctp.factory.parse(newxml);
            paragraph.getctp().set(newctp);
        } catch (exception e) {
            log.error("processparagraphviaxml error: {0}", e);
        }
    }

4、开始parserxmltext内容(基于org.w3c.dom.document)

    private string parserxml(string originalxml, map<string, string> formulamap)
            throws ioexception, saxexception, parserconfigurationexception, transformerexception {
        documentbuilderfactory factory = documentbuilderfactory.newinstance();
        factory.setnamespaceaware(true); // 启用命名空间支持
        documentbuilder builder = factory.newdocumentbuilder();
        org.w3c.dom.document doc = builder.parse(new bytearrayinputstream(originalxml.getbytes()));
 
        // 查找m:omath节点(使用命名空间)
        nodelist omathnodes = doc.getelementsbytagnamens("http://schemas.openxmlformats.org/officedocument/2006/math", "omath");
 
        map<element,node> map = new hashmap<>();
 
        for (int i = 0; i < omathnodes.getlength(); i++) {
            node omathnode = omathnodes.item(i);
            element relement = dohandleelement(omathnode, doc);
            map.put(relement, omathnode);
        }
 
        map.foreach((relement, omathnode) -> omathnode.getparentnode().replacechild(relement, omathnode));
 
        return docmenttostring(doc);
    }

5、处理node节点,并且找到omath节点后转换为latex,将latex替换掉omath节点后产生新的xmltext

 
    private element dohandleelement(node omathnode, org.w3c.dom.document doc) throws transformerexception {
        // 保存原始公式内容(简化处理,实际可能需要更复杂的序列化)
        string formulacontent = nodetostring(omathnode);
 
        if(questionmathreader==null){
            questionmathreader = new questionmathreader2();
        }
 
        log.debug("formulacontent:{}", formulacontent);
        string latexcontent = questionmathreader.convertfrommmltolatex(formulacontent);
        log.debug("latexcontent:{}", latexcontent);
 
        // 创建新的文本节点
        text textnode = doc.createtextnode("<katextext value=\""+latexcontent+"\"></katextext>");
 
        // 创建新的w:r节点(word中的文本需要包装在r中)
        element relement = doc.createelementns("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:r");
        element telement = doc.createelementns("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w:t");
        telement.appendchild(textnode);
        relement.appendchild(telement);
        return relement;
    }
 
    // 辅助方法:将 node 转换为 xml 字符串
    private string nodetostring(node node) throws transformerexception {
        transformerfactory tf = transformerfactory.newinstance();
        transformer transformer = tf.newtransformer();
        transformer.setoutputproperty(outputkeys.omit_xml_declaration, "yes");
        stringwriter writer = new stringwriter();
        transformer.transform(new domsource(node), new streamresult(writer));
        return writer.tostring();
    }

6、将org.w3c.dom.document转换为字符串

    private static string docmenttostring(org.w3c.dom.document doc) throws transformerexception {
        // 将修改后的dom转换回xml字符串
        transformerfactory transformerfactory = transformerfactory.newinstance();
        transformer transformer = transformerfactory.newtransformer();
        transformer.setoutputproperty(outputkeys.omit_xml_declaration, "yes");
        transformer.setoutputproperty(outputkeys.indent, "no");
 
        stringwriter writer = new stringwriter();
        transformer.transform(new domsource(doc), new streamresult(writer));
 
        return writer.tostring();
    }

7、将新的xmltext设置到xwpfparagraph,将xwpfdocument持久化成新的word文档

            // 处理xml,替换公式
            string newxml = parserxml(originalxml, formulamap);
 
            // 用新的xml替换原来的段落内容
            ctp newctp = ctp.factory.parse(newxml);
            paragraph.getctp().set(newctp);

8、还一个main函数也一起贴一下

    public static void main(string[] args) throws ioexception {
        questionmathreplace2 extractor = new questionmathreplace2();
 
        // 执行提取并替换公式
        map<string, string> formulamap = extractor.extractandreplaceformulas(
                files.newinputstream(paths.get("f://test_source.docx")),
                "f://test_target.docx"
        );
 
        // 输出映射关系
        for (map.entry<string, string> entry : formulamap.entryset()) {
            system.out.println(entry.getkey() + " => " + entry.getvalue());
        }
    }

9、运行一下,看一下控制台

10、最后看一下生成的word文件

以上就是java按顺序提取word内容的方法步骤(文本+数学公式)的详细内容,更多关于java按顺序提取word内容的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com