Java按順序提取Word內(nèi)容的方法步驟(文本+數(shù)學(xué)公式)
一、背景
因業(yè)務(wù)需求,目前正在實(shí)現(xiàn)一項(xiàng)需求,即將一份試卷的內(nèi)容提取出來,由非結(jié)構(gòu)化到結(jié)構(gòu)化的轉(zhuǎn)換。在試卷解析的時(shí)候在解析數(shù)學(xué)公式的時(shí)候花了一番功夫,當(dāng)成功把word中的數(shù)學(xué)公式提出來并且轉(zhuǎn)換為Latex之后已經(jīng)大功告成了呢,突然發(fā)現(xiàn)從word讀取到的公式轉(zhuǎn)換成的Latex不能放到準(zhǔn)確的位置,造成了順序錯(cuò)亂的問題。本方案只是我本人實(shí)踐的一種方法(不一定是最好的方法),于是寫下來分享給大家。
二、概述
從一份word格式的試卷中讀取內(nèi)容,使用POI讀取word文件,按照XWPFParagraph進(jìn)行遍歷,處理每一個(gè)XWPFParagraph,從XWPFParagraph獲取xmlText;開始ParserXMLText內(nèi)容(基于org.w3c.dom.Document);找到oMath節(jié)點(diǎn)后轉(zhuǎn)換為Latex,將Latex替換掉oMath節(jié)點(diǎn)后產(chǎn)生新的xmlText,將新的xmlText設(shè)置到XWPFParagraph,將XWPFDocument持久化成新的word文檔
三、正文
1、準(zhǔn)備一份原始word文件

2、使用POI讀取word文件,按照XWPFParagraph進(jìn)行遍歷
/**
* 提取公式并替換為唯一標(biāo)識(shí)符
* @param fis 原始Word文檔路徑
* @param outputPath 處理后Word文檔路徑
* @return 公式與標(biāo)識(shí)符的映射關(guān)系
*/
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、處理每一個(gè)XWPFParagraph,從XWPFParagraph獲取xmlText
/**
* 通過XML直接處理段落中的公式
*/
public void processParagraphViaXML(XWPFParagraph paragraph, Map<String, String> formulaMap) {
try {
CTP ctp = paragraph.getCTP();
// 獲取段落的XML內(nèi)容
String originalXml = ctp.xmlText();
// 處理XML,替換公式
String newXml = parserXML(originalXml, formulaMap);
// 用新的XML替換原來的段落內(nèi)容
CTP newCtp = CTP.Factory.parse(newXml);
paragraph.getCTP().set(newCtp);
} catch (Exception e) {
log.error("processParagraphViaXML Error: {0}", e);
}
}4、開始ParserXMLText內(nèi)容(基于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節(jié)點(diǎn)(使用命名空間)
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節(jié)點(diǎn),并且找到oMath節(jié)點(diǎn)后轉(zhuǎn)換為Latex,將Latex替換掉oMath節(jié)點(diǎn)后產(chǎn)生新的xmlText
private Element doHandleElement(Node oMathNode, org.w3c.dom.Document doc) throws TransformerException {
// 保存原始公式內(nèi)容(簡化處理,實(shí)際可能需要更復(fù)雜的序列化)
String formulaContent = nodeToString(oMathNode);
if(questionMathReader==null){
questionMathReader = new QuestionMathReader2();
}
log.debug("formulaContent:{}", formulaContent);
String latexContent = questionMathReader.convertFromMmlToLatex(formulaContent);
log.debug("LatexContent:{}", latexContent);
// 創(chuàng)建新的文本節(jié)點(diǎn)
Text textNode = doc.createTextNode("<KatexText value=\""+latexContent+"\"></KatexText>");
// 創(chuàng)建新的w:r節(jié)點(diǎn)(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 轉(zhuǎn)換為 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轉(zhuǎn)換為字符串
private static String docmentToString(org.w3c.dom.Document doc) throws TransformerException {
// 將修改后的DOM轉(zhuǎn)換回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設(shè)置到XWPFParagraph,將XWPFDocument持久化成新的word文檔
// 處理XML,替換公式
String newXml = parserXML(originalXml, formulaMap);
// 用新的XML替換原來的段落內(nèi)容
CTP newCtp = CTP.Factory.parse(newXml);
paragraph.getCTP().set(newCtp);8、還一個(gè)main函數(shù)也一起貼一下
public static void main(String[] args) throws IOException {
QuestionMathReplace2 extractor = new QuestionMathReplace2();
// 執(zhí)行提取并替換公式
Map<String, String> formulaMap = extractor.extractAndReplaceFormulas(
Files.newInputStream(Paths.get("F://test_source.docx")),
"F://test_target.docx"
);
// 輸出映射關(guān)系
for (Map.Entry<String, String> entry : formulaMap.entrySet()) {
System.out.println(entry.getKey() + " => " + entry.getValue());
}
}9、運(yùn)行一下,看一下控制臺(tái)

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

以上就是Java按順序提取Word內(nèi)容的方法步驟(文本+數(shù)學(xué)公式)的詳細(xì)內(nèi)容,更多關(guān)于Java按順序提取Word內(nèi)容的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Druid關(guān)閉監(jiān)控頁面關(guān)閉不了的問題及解決
這篇文章主要介紹了Druid關(guān)閉監(jiān)控頁面關(guān)閉不了的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝教程
這篇文章主要介紹了windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
java中關(guān)于getProperties方法的使用
這篇文章主要介紹了java中關(guān)于getProperties方法的使用,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12

