前置博文
请先阅读前期博文以便更好理解本篇博文
准备工作
需要安装一个第三方公式插件建
XML分析
先来分析一下xml
-
正常文本:
-
<w:r> 标签对应一个
XWPFRun
对象 - <w:t xml:space=“preserve”> 标签对应一段在 Word中的字符(也可以是一个字符) 公式:
-
<w:object> 标签对应一个公式(当然我们这里只讲公式,此标签中也可以是一个
Excel
也可以是一个PPT
等等) -
<v:shape> 标签中有个
style
属性,这里style
就是图片在 Word中显示的宽高 - <v:imagedata> 标签关联着显示的图片( <v:imagedata>为 <v:shape>子标签)
- <o:OLEObject>标签关联着图片显示公式对应的二进制文件(二进制文件也是最重要的文件,没有这个文件当你在word中双击时,是打不开第三方公式插件的)
注意:
xml中ProgID="Equation.AxMath"
属性标记着是使用的什么第三方插件(我用的是 AxMath, MathType的此属性为ProgID="Equation.DSMT4"
)
说了这么多估计还是迷糊的,下面上代码跟着代码的思路再去好好的捋一捋。
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:noProof/>
</w:rPr>
<w:t xml:space="preserve">公式前的文字 </w:t>
</w:r>
<w:r w:rsidR="00D23F9D" w:rsidRPr="0051191A">
<w:rPr>
<w:noProof/>
<w:position w:val="-10"/>
</w:rPr>
<w:object w:dxaOrig="912" w:dyaOrig="318" w14:anchorId="3B58962C">
<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
<v:stroke joinstyle="miter"/>
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0"/>
<v:f eqn="sum @0 1 0"/>
<v:f eqn="sum 0 0 @1"/>
<v:f eqn="prod @2 1 2"/>
<v:f eqn="prod @3 21600 pixelWidth"/>
<v:f eqn="prod @3 21600 pixelHeight"/>
<v:f eqn="sum @0 0 1"/>
<v:f eqn="prod @6 1 2"/>
<v:f eqn="prod @7 21600 pixelWidth"/>
<v:f eqn="sum @8 21600 0"/>
<v:f eqn="prod @7 21600 pixelHeight"/>
<v:f eqn="sum @10 21600 0"/>
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
<o:lock v:ext="edit" aspectratio="t"/>
</v:shapetype>
<v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:45.75pt;height:15.75pt" o:ole="">
<v:imagedata r:id="rId6" o:title=""/>
</v:shape>
<o:OLEObject Type="Embed" ProgID="Equation.AxMath" ShapeID="_x0000_i1025" DrawAspect="Content" ObjectID="_1626856759" r:id="rId7"/>
</w:object>
</w:r>
读取公式
- 首先看一下Word内容
- 再来看一下读取出来是的结果
读取出来的文件
@Test
public void test4() throws Exception {
XWPFDocument word = new XWPFDocument(new FileInputStream("D:\\Test\\word\\test1.docx"));
try {
List<XWPFParagraph> paragraphs = word.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
StringBuffer text = new StringBuffer();
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
Node runNode = run.getCTR().getDomNode();
text.append(getText(runNode));
String math = getMath(run, runNode);
text.append(math);
}
System.out.println("段落内容:".concat(text.toString()));
}
} finally {
word.close();
}
}
/**
* 获取字符串
*
* @param runNode
* @return
*/
private String getText(Node runNode) {
Node textNode = getChildNode(runNode, "w:t");
if (textNode == null) {
return "";
}
return textNode.getFirstChild().getNodeValue();
}
private String getMath(XWPFRun run, Node runNode) throws Exception {
Node objectNode = getChildNode(runNode, "w:object");
if (objectNode == null) {
return "";
}
Node shapeNode = getChildNode(objectNode, "v:shape");
if (shapeNode == null) {
return "";
}
Node imageNode = getChildNode(shapeNode, "v:imagedata");
if (imageNode == null) {
return "";
}
Node binNode = getChildNode(objectNode, "o:OLEObject");
if (binNode == null) {
return "";
}
XWPFDocument word = run.getDocument();
NamedNodeMap shapeAttrs = shapeNode.getAttributes();
// 图片在Word中显示的宽高
String style = shapeAttrs.getNamedItem("style").getNodeValue();
System.out.println("图片宽高:".concat(style));
System.out.println("--------------");
NamedNodeMap imageAttrs = imageNode.getAttributes();
// 图片在Word中的ID
String imageRid = imageAttrs.getNamedItem("r:id").getNodeValue();
// 获取图片信息
PackagePart imgPart = word.getPartById(imageRid);
System.out.println("图片名称".concat(imgPart.getPartName().getName()));
System.out.println(imgPart.getInputStream());
System.out.println("--------------");
NamedNodeMap binAttrs = binNode.getAttributes();
// 公式二进制文件在Word中的ID
String binRid = binAttrs.getNamedItem("r:id").getNodeValue();
// 获取二进制文件
PackagePart binPart = word.getPartById(binRid);
System.out.println("二进制文件名称:".concat(binPart.getPartName().getName()));
System.out.println(binPart.getInputStream());
System.out.println("--------------");
return "{公式#}";
}
private Node getChildNode(Node node, String nodeName) {
if (!node.hasChildNodes()) {
return null;
}
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if (nodeName.equals(childNode.getNodeName())) {
return childNode;
}
childNode = getChildNode(childNode, nodeName);
if (childNode != null) {
return childNode;
}
}
return null;
}
写入公式
- <v:shapetype>标签可以不用写入,公式正常显示,当然如果想写入进去也只需要第一个公式写就可以,其他公式直接饮用就好
- <o:OLEObject>标签中
ShapeID
属性需要与<v:shape>标签中的id
一致 - 写入公式后的Word
@Test
public void test5() throws Exception {
XWPFDocument word = new XWPFDocument();
OutputStream stream = null;
try {
XWPFParagraph paragraph = word.createParagraph();
XWPFRun run = paragraph.createRun();
XWPFDocument doc = run.getDocument();
InputStream imgIs = new FileInputStream("D:\\Test\\word\\image1.wmf");
InputStream binIs = new FileInputStream("D:\\Test\\word\\oleObject1.bin");
org.w3c.dom.Document document = createMathType(doc, imgIs, binIs, "width:45.75pt;height:15.75pt");
// 将公式写入run中
run.setEmbossed(true);
run.getCTR().set(XmlObject.Factory.parse(document.getDocumentElement(), POIXMLTypeLoader.DEFAULT_XML_OPTIONS));
stream = new FileOutputStream("D:\\Test\\word\\test5.docx");
word.write(stream);
} finally {
word.close();
if (stream != null) {
stream.close();
}
}
}
private org.w3c.dom.Document createMathType(XWPFDocument doc, InputStream imgIs, InputStream binIs, String style)
throws Exception {
// 添加图片获取rid
String imgRid = doc.addPictureData(imgIs, Document.PICTURE_TYPE_WMF);
int rid = Integer.parseInt(imgRid.replaceAll("[a-zA-Z]", ""));
// 添加二进制文件
final PackagePartName partName = PackagingURIHelper.createPartName("/word/embeddings/oleMath" + rid + ".bin");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(IOUtils.toByteArray(binIs));
doc.getPackage().createPart(partName, "application/vnd.openxmlformats-officedocument.oleObject", bos);
PackageRelationship prOle = doc.getPackagePart().addRelationship(partName, TargetMode.INTERNAL,
POIXMLDocument.OLE_OBJECT_REL_TYPE);
// 创建xml
String xml = createObjectXml(imgRid, prOle.getId(), rid, style);
InputSource is1 = new InputSource(new StringReader(xml));
return DocumentHelper.readDocument(is1);
}
private String createObjectXml(String imgRid, String binRid, int num, String style) {
String shapeId = "math".concat(String.valueOf(num));
StringBuffer xml = new StringBuffer();
xml.append("<w:object\n\t");
xml.append("xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"\n\t");
xml.append("xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n\t");
xml.append("xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"\n\t");
xml.append("xmlns:v=\"urn:schemas-microsoft-com:vml\">\n\t");
xml.append("<v:shape id=\"").append(shapeId);
xml.append("\" o:ole=\"\" style=\"").append(style).append("\" type=\"\">\n\t");
xml.append("<v:imagedata r:id=\"").append(imgRid).append("\" o:title=\"\" />\n\t");
xml.append("</v:shape>\n\t");
xml.append("<o:OLEObject DrawAspect=\"Content\" ObjectID=\"\" ProgID=\"Equation.DSMT4\" ShapeID=\"");
xml.append(shapeId);
xml.append("\" Type=\"Embed\" r:id=\"").append(binRid).append("\"/>");
xml.append("</w:object>");
return xml.toString();
}
最后
如果有什么不明白的可以留言。
欢迎大家留言讨论。