java - 使用 apache poi 将方程式从 Word (*.docx) 读取为 HTML 及其文本上下文

标签 java apache-poi position formula equation

我们正在构建一个 java 代码,以使用 apache POI 将 Word 文档 (.docx) 读入我们的程序。 当我们在文档中遇到公式和化学方程式时,我们会陷入困境。 然而,我们设法阅读了公式,但我们不知道如何在相关字符串中找到其索引..

输入(格式为*.docx)

公式之前的文本 **CHEMICAL EQUATION** 文本之后

我们设计的输出(格式为HTML)

公式之前的文本 **化学方程式**之后的文本

我们无法获取字符串并将其重建为原始形式。

问题

现在有什么方法可以定位图像和公式在剥离线内的位置,以便在重建字符串后可以将其恢复到原始形式,而不是附加它在字符串的末尾。?

最佳答案

如果所需格式为HTML,则将Word文本内容与Office MathML一起使用方程可以通过以下方式读取。

Reading equations & formula from Word (Docx) to html and save database using java我提供了一个示例,它将所有 Office MathML 方程从 Word 文档中获取到 HTML 中。它使用 paragraph.getCTP().getOMathList()paragraph.getCTP().getOMathParaList() 从段落中获取 OMath 元素。这会将 OMath 元素从文本上下文中取出。

如果想要将这些 OMath 元素与段落中的其他元素放在上下文中,则需要使用 org.apache.xmlbeans.XmlCursor 来循环所有元素段落中的不同 XML 元素。以下示例使用 XmlCursor 获取段落中与 OMath 元素一起运行的文本。

Office MathMLMathML 的转变使用与 Reading equations & formula from Word (Docx) to html and save database using java 中相同的 XSLT 方法来获取。还描述了 OMML2MML.XSL 的来源。

文件 Formula.docx 如下所示:

enter image description here

代码:

import java.io.*;
import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathPara;

import org.apache.xmlbeans.XmlCursor;

import org.w3c.dom.Node;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;

import java.awt.Desktop;

import java.util.List;
import java.util.ArrayList;

/*
needs the full ooxml-schemas-1.4.jar as mentioned in https://poi.apache.org/faq.html#faq-N10025
*/

public class WordReadTextWithFormulasAsHTML {

 static File stylesheet = new File("OMML2MML.XSL");
 static TransformerFactory tFactory = TransformerFactory.newInstance();
 static StreamSource stylesource = new StreamSource(stylesheet);

 //method for getting MathML from oMath
 static String getMathML(CTOMath ctomath) throws Exception {
  Transformer transformer = tFactory.newTransformer(stylesource);

  Node node = ctomath.getDomNode();

  DOMSource source = new DOMSource(node);
  StringWriter stringwriter = new StringWriter();
  StreamResult result = new StreamResult(stringwriter);
  transformer.setOutputProperty("omit-xml-declaration", "yes");
  transformer.transform(source, result);

  String mathML = stringwriter.toString();
  stringwriter.close();

  //The native OMML2MML.XSL transforms OMML into MathML as XML having special name spaces.
  //We don't need this since we want using the MathML in HTML, not in XML.
  //So ideally we should changing the OMML2MML.XSL to not do so.
  //But to take this example as simple as possible, we are using replace to get rid of the XML specialities.
  mathML = mathML.replaceAll("xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"", "");
  mathML = mathML.replaceAll("xmlns:mml", "xmlns");
  mathML = mathML.replaceAll("mml:", "");

  return mathML;
 }

 //method for getting HTML including MathML from XWPFParagraph
 static String getTextAndFormulas(XWPFParagraph paragraph) throws Exception {
  
  StringBuffer textWithFormulas = new StringBuffer();

  //using a cursor to go through the paragraph from top to down
  XmlCursor xmlcursor = paragraph.getCTP().newCursor();

  while (xmlcursor.hasNextToken()) {
   XmlCursor.TokenType tokentype = xmlcursor.toNextToken();
   if (tokentype.isStart()) {
    if (xmlcursor.getName().getPrefix().equalsIgnoreCase("w") && xmlcursor.getName().getLocalPart().equalsIgnoreCase("r")) {
     //elements w:r are text runs within the paragraph
     //simply append the text data
     textWithFormulas.append(xmlcursor.getTextValue());
    } else if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("oMath")) {
     //we have oMath
     //append the oMath as MathML
     textWithFormulas.append(getMathML((CTOMath)xmlcursor.getObject()));
    } 
   } else if (tokentype.isEnd()) {
    //we have to check whether we are at the end of the paragraph
    xmlcursor.push();
    xmlcursor.toParent();
    if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("p")) {
     break;
    }
    xmlcursor.pop();
   }
  }
  
  return textWithFormulas.toString();
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument(new FileInputStream("Formula.docx"));

  //using a StringBuffer for appending all the content as HTML
  StringBuffer allHTML = new StringBuffer();

  //loop over all IBodyElements - should be self explained
  for (IBodyElement ibodyelement : document.getBodyElements()) {
   if (ibodyelement.getElementType().equals(BodyElementType.PARAGRAPH)) {
    XWPFParagraph paragraph = (XWPFParagraph)ibodyelement;
    allHTML.append("<p>");
    allHTML.append(getTextAndFormulas(paragraph));
    allHTML.append("</p>");
   } else if (ibodyelement.getElementType().equals(BodyElementType.TABLE)) {
    XWPFTable table = (XWPFTable)ibodyelement;
    allHTML.append("<table border=1>");
    for (XWPFTableRow row : table.getRows()) {
     allHTML.append("<tr>");
     for (XWPFTableCell cell : row.getTableCells()) {
      allHTML.append("<td>");
      for (XWPFParagraph paragraph : cell.getParagraphs()) {
       allHTML.append("<p>");
       allHTML.append(getTextAndFormulas(paragraph));
       allHTML.append("</p>");
      }
      allHTML.append("</td>");
     }
     allHTML.append("</tr>");
    }
    allHTML.append("</table>");
   }
  }

  document.close();

  //creating a sample HTML file 
  String encoding = "UTF-8";
  FileOutputStream fos = new FileOutputStream("result.html");
  OutputStreamWriter writer = new OutputStreamWriter(fos, encoding);
  writer.write("<!DOCTYPE html>\n");
  writer.write("<html lang=\"en\">");
  writer.write("<head>");
  writer.write("<meta charset=\"utf-8\"/>");

  //using MathJax for helping all browsers to interpret MathML
  writer.write("<script type=\"text/javascript\"");
  writer.write(" async src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=MML_CHTML\"");
  writer.write(">");
  writer.write("</script>");

  writer.write("</head>");
  writer.write("<body>");

  writer.write(allHTML.toString());

  writer.write("</body>");
  writer.write("</html>");
  writer.close();

  Desktop.getDesktop().browse(new File("result.html").toURI());

 }
}

结果:

enter image description here

<小时/>

刚刚使用 apache poi 5.0.0 测试了此代码,它可以工作。您需要用于 apache poi 5.0.0poi-ooxml-full-5.0.0.jar。请阅读https://poi.apache.org/help/faq.html#faq-N10025哪个 apache poi 版本需要哪些 ooxml 库。

关于java - 使用 apache poi 将方程式从 Word (*.docx) 读取为 HTML 及其文本上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59414033/

相关文章:

java - line = reader.readline() 结果与文字 "F"的行为不同

Bat 和 Eclipse 之间的 Java 文件同步

java - SXSSFWorkbook写入xlsm文件

objective-c - 在 Objective-C 中确定屏幕位置 (NSScreen)

html - 图像未加载/飞走按钮

javascript - 如何使用 JavaScript 动态设置 DIV 元素的左侧和顶部 CSS 定位

java - 错误: on a null object reference

java - 为什么这个关于组合框的代码不起作用?

java - 无法使用 WorkBook Factory 打开西里尔文密码保护的 xlsx 文件

java - 多个单元格在同一行中对齐(Apache POI)