poi处理word内容的公式_Office中数学公式⽤Java解析
公司正在做教育类产品,在遇到数学公式时,我们⼀般会使⽤latex表达式来做保存和渲染。
在其中⼀个项⽬上,遇到⼀个需求是要从office⽂档(Word或Excel)中导⼊题⽬内容⾄数据库,题⽬内容中就有可能包括数学公式,⽽在⽂档中编辑希望使⽤office的公式插件来写公式元素。
其实公司之前的产品已经使⽤实现过此功能,不过现在公司全⾯转型Java,我们也要研究出⼀个适⽤Java的解决⽅案。
office⽂档中的公式编辑器
mathtype插件
mathtype是⼀个第三⽅的数学公式插件,它能在Office⽂档中启⽤编辑,并⽣成⼀个带有公式⽮量图的ole对象插⼊到⽂档中。
原来的⽅案就是使⽤此种⽅式,使⽤mathtype提供的c#库包来解析ole对象,抽取LaTeX表达式。
但在纯Java环境下就⽆法做到了。
office⾃带公式编辑器
从2007版开始,Office也⾃带了⼀个公式编辑器。
在2007版中Word与Excel之间不同的是,前者插⼊的公式对象是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的标准,⽤来在互联⽹上书写数学符号和公式的置标语⾔。
例如⼀个表达式:
n
p
-
1
1
(
mod
p
)
Office MathML (OMML)
在office2007之后版本所编辑的公式对象便是OMML。OMML是office为了配合Office Open Xml制定的数学标记语⾔。
例如:
π
2
转换关系
我们在项⽬中使⽤到的三者之间转换关系是:OMML -> MathML -> LaTex
Office在安装⽬录中提供了将OMML转为MathML的xsl⼯具:MML2OMML.XSL
MathML转LaTex使⽤⽹上到另⼀个xsl⼯具mmltex.xsl。
Office⽂档Java解析
2007与之前的版本
⽤过⼀段Office的同学们都知道,Office⽂档分为word与wordx这两种类型,分别对应着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⽂档,Word和Excel均可。 其中,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 = SheetAt(0);
插⼊在Excel⽂档中的图⽚、公式及其他元素,它都是存放在⼀个叫drawing的单独xml⽂件中,其中的节点记录了元素摆放的位置信息。⽤POI得到drawing元素:
XSSFDrawing dr = DrawingPatriarch();
CTDrawing drawing = dr.getCTDrawing();
CTOneCellAnchor[] oneCells = OneCellAnchorArray(); //所有的图⽚、公式等元素
每个CTOneCellAnchor的xml⾥包含元素的位置信息,包括X坐标、Y坐标,所在⾏、所在列等,更重要的是图⽚或公式的描述节点。OMML节点名为m:oMathPara,这⾥我们就使⽤dom4j的xpath来获得OMML:
CTOneCellAnchor c = oneCells[0];
String xml = c.xmlText(); //得到xml串
//dom4j解析器的初始化
SAXReader reader = reader = new SAXReader(new DocumentFactory());
Map map=new HashMap();
map.put("xdr","/drawingml/2006/spreadsheetDrawing");
map.put("m","/officeDocument/2006/math");
InputSource source = new InputSource(new StringReader(xml));
source.setEncoding("utf-8");
Document doc = ad(source);
Element root = RootElement();
Element e = (Element)root.selectSingleNode("//m:oMathPara"); //⽤xpath得到OMML节点
String omml = e.asXML(); //转为xml
转换OMML为Mathml及LaTeX
顺利得到OMML后,就可以使⽤xsl转换⼯具得到Mathml与LaTeX了。
这⾥先写⼀下xsl转换⼯具⽅法,使⽤ansform⼯具包实现:
/**
*
Description: xsl转换器
*/
public static String xslConvert(String s, String xslpath, URIResolver uriResolver){
TransformerFactory tFac = wInstance();
if(uriResolver != null) tFac.setURIResolver(uriResolver);
StreamSource xslSource = new StreamSource(ResourceAsStream(xslpath));
StringWriter writer = new StringWriter();
try {
Transformer t = wTransformer(xslSource);
Source source = new StreamSource(new StringReader(s));
Result result = new StreamResult(writer);
} catch (TransformerException e) {
<(e.getMessage(), e);
}
Buffer().toString();
}
/**
*
Description: 将mathml转为latx
* @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 = ResourceAsStream("/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;
}
/**
*
Description: office mathml转为mml
* @param xml
* @return
*/
public static String convertOMML2MML(String xml){
String result = xslConvert(xml, "/conventer/OMML2MML.XSL", null);
return result;
}
⾄此我们就可以将OMML转成Mathml与LaTeX表达式了:
使用dom4j解析xml文件String mml = convertOMML2MML(omml);
String latex = convertMML2Latex(mml);
⼀些⼼得体会
实现这个功能的时候,⼿上真的也没太多直接的资料可以参考,⾛过好⼏个弯路,⽹上查到的信息很多也是过时或者把话说⼀半的。在与同事的交流下,使⽤不同思路,查阅许多api⽂档,再加上不断的尝试,也算完成了这个不算实⽤的功能。
就算你⾃⼰本⾝不够优秀,在⼀个好的团队也能不断推着你向前⾛。⼀个⼈最终能前⾏到多远,还是要看与你同⾏的⼈。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。