Office中数学公式用Java解析,java解析word公式

2 篇文章 0 订阅
1 篇文章 0 订阅

公司正在做教育类产品,在遇到数学公式时,我们一般会使用latex表达式来做保存和渲染。
在其中一个项目上,遇到一个需求是要从office文档(WordExcel)中导入题目内容至数据库,题目内容中就有可能包括数学公式,而在文档中编辑希望使用office的公式插件来写公式元素。
其实公司之前的产品已经使用.net实现过此功能,不过现在公司全面转型Java,我们也要研究出一个适用Java的解决方案。

office文档中的公式编辑器

mathtype插件

mathtype是一个第三方的数学公式插件,它能在Office文档中启用编辑,并生成一个带有公式矢量图的ole对象插入到文档中。
原来.net的方案就是使用此种方式,使用mathtype提供的c#库包来解析ole对象,抽取LaTeX表达式。
但在纯Java环境下就无法做到了。

在楼主的不懈努力下,用谷歌谷到了一个解析Mathtype的工程,不过是go语言的

可以直接使用转化ole为latex公式文本,亲测有效----关注博主私信发你

https://download.csdn.net/download/qq_41536778/14156089

office自带公式编辑器

从2007版开始,Office也自带了一个公式编辑器。
在2007版中WordExcel之间不同的是,前者插入的公式对象是Office MathML节点,后者插入的还是ole
到了2010版开始,两个产品的公式编辑器插入的都是Office MathML节点了,但是两者对公式对象中的默认文字编码处理不同。
这些不同点可以看出就算同样属于Office的产品,他们之间也是有很多不统一的地方。

公式表达式

LaTeX

LaTeX是一种基于ΤΕΧ的排版系统,它非常适用于生成高印刷质量的科技和数学类文档。
例如勾股定理用LaTeX表达:

 

a^{2}+b^{2}=c^{2}

常用的LaTeX渲染组件是MathJax
我们在项目中使用的便是LaTeX,所以本次研究就是如何将Office中的公式对象转换成LaTeX表达式。

Mathml

全称为数学标记语言(Mathematical Markup Language),是一种基于XML的标准,用来在互联网上书写数学符号和公式的置标语言。
例如一个表达式:

 

<math xmlns="http://www.w3.org/1998/Math/MathML">
    <msup>
        <mi>n</mi>
    <mrow>
      <mi>p</mi>
      <mo>-</mo>
          <mn>1</mn>
    </mrow>
  </msup>
  <mspace width=".2em"/>
  <mo>≡</mo>
  <mspace width=".2em"/>
  <mn>1</mn>
  <mspace width=".2em"/>
  <mo>(</mo>
  <mi>mod</mi>
  <mspace width=".2em"/>
  <mi>p</mi>
  <mo>)</mo>
</math>

Office MathML (OMML)

office2007之后版本所编辑的公式对象便是OMMLOMMLoffice为了配合Office Open Xml制定的数学标记语言。
例如:

 

<m:oMathPara><!-- mathematical block container used as a paragraph -->
  <m:oMath><!-- mathematical inline formula -->
    <m:f><!-- a fraction -->
      <m:num><m:r><m:t>π</m:t></m:r></m:num><!-- numerator containing a single run of text -->
      <m:den><m:r><m:t>2</m:t></m:r></m:den><!-- denominator containing a single run of text -->
    </m:f>
  </m:oMath>
</m:oMathPara>

转换关系

我们在项目中使用到的三者之间转换关系是:OMML -> MathML -> LaTex
Office在安装目录中提供了将OMML转为MathMLxsl工具:MML2OMML.XSL
MathMLLaTex使用网上找到另一个xsl工具mmltex.xsl

Office文档Java解析

2007与之前的版本

用过一段Office的同学们都知道,Office文档分为wordwordx这两种类型,分别对应着2007之前与之后的版本格式。
2007之前版本使用的Office文档是二进制文件。而之后版本中x代表的意义是xml,表明新版的Office文档使用Office Open Xml规范定义文件格式。
如果我们把wordx文件的扩展名改为zip,就可以正常解压出Word文档包含的所有内容。

POI

相信用Java做过信息系统的同学都遇过生成统计Excel文档或解析Excel导入数据的功能。这时我们最常使用的开发库就是Apache POI
POI支持二进制与Office Open Xml文档,可以满足我们大部分的Office文档解析需求。

解析公式实例

首先要说明我们的功能限制:只针对Office2010及以上的Office Open Xml文档,WordExcel均可。 其中,Excel的公式数学字符需要转为普通字符,否则会出现Java无法识别的字符。
这里用Excel文档为例子来说明解析过程。

功能实现思路

这个功能的关键点在于如何获得Office文档中的公式节点(OMML),得到OMML后我们就可以使用上述的两个工具转换为LaTeX

获得OMML

既然我们知道Excel文档是一个xml,那只需要使用xml解析工具读出OMML节点就行了。
先用POI得到操作的XSSFSheet

 

String basePath = "f:\\";
FileInputStream fis = new FileInputStream(basePath + "math.xlsx");
OPCPackage pack = OPCPackage.open(fis);
XSSFWorkbook workbook = new XSSFWorkbook(pack);
XSSFSheet sheet = workbook.getSheetAt(0);

插入在Excel文档中的图片、公式及其他元素,它都是存放在一个叫drawing的单独xml文件中,其中的节点记录了元素摆放的位置信息。用POI得到drawing元素:

 

XSSFDrawing dr = sheet.getDrawingPatriarch();
CTDrawing drawing = dr.getCTDrawing();
CTOneCellAnchor[] oneCells = drawing.getOneCellAnchorArray();   //所有的图片、公式等元素

每个CTOneCellAnchorxml里包含元素的位置信息,包括X坐标、Y坐标,所在行、所在列等,更重要的是图片或公式的描述节点。OMML节点名为m:oMathPara,这里我们就使用dom4jxpath来获得OMML

 

CTOneCellAnchor c = oneCells[0];
String xml = c.xmlText();   //得到xml串

//dom4j解析器的初始化
SAXReader reader = reader = new SAXReader(new DocumentFactory());
Map<String, String> map=new HashMap<String, String>();
map.put("xdr","http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing");
map.put("m","http://schemas.openxmlformats.org/officeDocument/2006/math");
reader.getDocumentFactory().setXPathNamespaceURIs(map); //xml文档的namespace设置

InputSource source = new InputSource(new StringReader(xml));
source.setEncoding("utf-8");
Document doc = reader.read(source);
Element root = doc.getRootElement();
Element e = (Element)root.selectSingleNode("//m:oMathPara");    //用xpath得到OMML节点
String omml = e.asXML();    //转为xml

转换OMML为Mathml及LaTeX

顺利得到OMML后,就可以使用xsl转换工具得到MathmlLaTeX了。
这里先写一下xsl转换工具方法,使用javax.xml.transform工具包实现:

 

/**    
 * <p>Description: xsl转换器</p>
 */
public static String xslConvert(String s, String xslpath, URIResolver uriResolver){
    TransformerFactory tFac = TransformerFactory.newInstance();
    if(uriResolver != null)  tFac.setURIResolver(uriResolver);
    StreamSource xslSource = new StreamSource(MathmlUtils.class.getResourceAsStream(xslpath));
    StringWriter writer = new StringWriter();   
    try {
        Transformer t = tFac.newTransformer(xslSource);
        Source source = new StreamSource(new StringReader(s));
        Result result = new StreamResult(writer);   
        t.transform(source, result);
    } catch (TransformerException e) {
        logger.error(e.getMessage(), e);
    }
    return writer.getBuffer().toString();
}

/**
 * <p>Description: 将mathml转为latx </p>
 * @param mml
 * @return
 */
public static String convertMML2Latex(String mml){
    mml = mml.substring(mml.indexOf("?>")+2, mml.length()); //去掉xml的头节点
    URIResolver r = new URIResolver(){  //设置xls依赖文件的路径
        @Override
        public Source resolve(String href, String base) throws TransformerException {
            InputStream inputStream = MathmlUtils.class.getResourceAsStream("/conventer/mml2tex/" + href);
            return new StreamSource(inputStream);
        }
    };
    String latex = xslConvert(mml, "/conventer/mml2tex/mmltex.xsl", r);
    if(latex != null && latex.length() > 1){
        latex = latex.substring(1, latex.length() - 1);
    }
    return latex;
}

/**
 * <p>Description: office mathml转为mml </p>
 * @param xml
 * @return
 */
public static String convertOMML2MML(String xml){
    String result = xslConvert(xml, "/conventer/OMML2MML.XSL", null);
    return result;
}

至此我们就可以将OMML转成MathmlLaTeX表达式了:

 

String mml = convertOMML2MML(omml);
String latex = convertMML2Latex(mml);

一些心得体会

实现这个功能的时候,手上真的也没太多直接的资料可以参考,走过好几个弯路,网上查到的信息很多也是过时或者把话说一半的。
在与同事的交流下,使用不同思路,查阅许多api文档,再加上不断的尝试,也算完成了这个不算实用的功能。
就算你自己本身不够优秀,在一个好的团队也能不断推着你向前走。一个人最终能前行到多远,还是要看与你同行的人。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答1: 要使用Java解析Word文件的表格,可以使用Apache POI和Apache Tika库。 以下是一些基本步骤: 1. 导入Apache POI和Apache Tika库。 ``` <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>2.0.0</version> </dependency> ``` 2. 使用Tika解析Word文件。 ``` FileInputStream inputStream = new FileInputStream(new File("file.docx")); Parser parser = new AutoDetectParser(); ContentHandler handler = new BodyContentHandler(); Metadata metadata = new Metadata(); parser.parse(inputStream, handler, metadata); String content = handler.toString(); ``` 3. 使用POI解析表格。 ``` XWPFDocument doc = new XWPFDocument(new FileInputStream("file.docx")); List<XWPFTable> tables = doc.getTables(); for (XWPFTable table : tables) { // 处理表格数据 for (XWPFTableRow row : table.getRows()) { List<XWPFTableCell> cells = row.getTableCells(); for (XWPFTableCell cell : cells) { // 处理单元格数据 System.out.print(cell.getText() + "\t"); } System.out.println(); } } ``` 这些步骤可以帮助您开始解析Word文件的表格。您可以根据自己的需求进行调整和扩展。 ### 回答2: 用Java解析Word文件的表格可以使用Apache POI库来实现。Apache POI是一个开源的Java API库,提供了访问和操作Microsoft Office格式文件(如Word、Excel和PowerPoint)的功能。 首先需要导入Apache POI库的相关jar包,然后可以使用以下步骤来解析Word文件的表格: 1. 创建一个Word文档对象,使用POIFSFileSystem类加载Word文件: ``` FileInputStream fis = new FileInputStream("path/to/word.doc"); POIFSFileSystem fileSystem = new POIFSFileSystem(fis); HWPFDocument document = new HWPFDocument(fileSystem); ``` 2. 获取文档的表格数量和表格内容: ``` Range range = document.getRange(); int tableCount = range.numTables(); for (int i = 0; i < tableCount; i++) { Table table = range.getTable(i); int rowCount = table.numRows(); for (int j = 0; j < rowCount; j++) { TableRow row = table.getRow(j); int cellCount = row.numCells(); for (int k = 0; k < cellCount; k++) { TableCell cell = row.getCell(k); String cellText = cell.text(); // 可以在这里对表格的内容进行处理或输出 } } } ``` 3. 解析完表格后,记得关闭文件流: ``` document.close(); fis.close(); ``` 通过上述步骤,我们可以使用Java解析Word文件的表格内容,并对表格内容进行处理或其他操作。请注意,以上代码仅适用于旧版的Word文档(.doc格式),如果是新版的Word文档(.docx格式),可以使用XWPFDocument类来解析。希望可以帮助到你! ### 回答3: 要用Java解析Word文件的表格,可以使用Apache POI库来处理。Apache POI是一个开源的Java库,用于访问和操作各种Office文档,包括Word文件。 首先,需要引入Apache POI的相关依赖包,例如poi、poi-ooxml和poi-ooxml-schemas。然后,可以通过XWPFDocument类加载Word文件,并使用XWPFTable类来获取表格。 以下是一个简单的代码示例,演示如何解析Word文件的表格: ```java import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFTable; import java.io.FileInputStream; import java.io.IOException; public class WordTableParser { public static void main(String[] args) { try { FileInputStream file = new FileInputStream("word.docx"); // Word文件的路径 XWPFDocument document = new XWPFDocument(file); // 获取文档的所有表格 for (XWPFTable table : document.getTables()) { // 解析表格数据 for (int i = 0; i < table.getRows().size(); i++) { for (int j = 0; j < table.getRow(i).getTableCells().size(); j++) { String cellText = table.getRow(i).getCell(j).getText(); System.out.print(cellText + "\t"); } System.out.println(); } } document.close(); file.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 在这个示例,首先使用 FileInputStream 来读取Word文件,然后使用 XWPFDocument 加载文件。然后,使用 document.getTables() 方法获取文档的所有表格,并使用嵌套循环遍历每个单元格获取表格的数据。 这只是一个简单的示例,实际的需求可能会更加复杂,例如处理合并单元格、设置表格样式等。但通过这个示例可以了解如何使用Java解析Word文件的表格。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刹那的娜娜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值