java使用poi读写word中的公式(三)

文章目录

    • 前置博文
    • 准备工作
    • XML分析
    • 读取公式
    • 写入公式
    • 最后

前置博文

请先阅读前期博文以便更好理解本篇博文

  • java使用poi读取word(一)
  • java使用poi读写word中的图片(二)

准备工作

需要安装一个第三方公式插件建

  1. AxMath官网
  2. MathType中文官网(国内某公司代理)

XML分析

先来分析一下xml

正常文本:
标签对应一个 XWPFRun对象
标签对应一段在 Word中的字符(也可以是一个字符)
公式:
标签对应一个公式(当然我们这里只讲公式,此标签中也可以是一个 Excel也可以是一个 PPT等等)
标签中有个 style属性,这里 style就是图片在 Word中显示的宽高
标签关联着显示的图片( 子标签)
标签关联着图片显示公式对应的二进制文件(二进制文件也是最重要的文件,没有这个文件当你在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内容
    java使用poi读写word中的公式(三)_第1张图片
  • 再来看一下读取出来是的结果
    java使用poi读写word中的公式(三)_第2张图片
    读取出来的文件
    在这里插入图片描述
	@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;
	}

写入公式

  • 标签可以不用写入,公式正常显示,当然如果想写入进去也只需要第一个公式写就可以,其他公式直接饮用就好
  • 标签中ShapeID属性需要与标签中的id一致
  • 写入公式后的Wordjava使用poi读写word中的公式(三)_第3张图片
	@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(");
		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(").append(shapeId);
		xml.append("\" o:ole=\"\" style=\"").append(style).append("\" type=\"\">\n\t");
		xml.append(").append(imgRid).append("\" o:title=\"\" />\n\t");
		xml.append("\n\t");
		xml.append(");
		xml.append(shapeId);
		xml.append("\" Type=\"Embed\" r:id=\"").append(binRid).append("\"/>");
		xml.append("");
		return xml.toString();
	}

最后

如果有什么不明白的可以留言。
欢迎大家留言讨论。

你可能感兴趣的:(java,poi,word,公式,AxMath,MathType)