Java解析word文檔


背景

在互聯網教育行業,做內容相關的項目經常碰到的一個問題就是如何解析word文檔。
因為系統如果無法智能的解析word,那么就只能通過其他方式手動錄入word內容,效率低下,而且人工成本和錄入出錯率都較高。


疑難點

word解析可以預見的困難主要有以下幾個方面:

  • word 結構問題 —— word不開源,且含有很多非文本內容,比如圖表,而已知的常規方法只能解析純文本內容,所以如果不知道word內部層級結構,解析將難以進行。
  • word 公式問題 —— word公式來源並非單一,可能是用MathType插件生成的latex公式,也可能是用word自帶公式編輯器生成的公式,還有可能公式部分手敲,部分使用搜狗輸入法或者其它編輯器輸入。不同來源處理方式是否一樣?且能否有效讀取文檔各種上下腳標?方便后期展示?
  • word 非文本問題 —— word含有很多的非文本內容,比如圖表。來源也多樣,圖表可能是用word自帶的畫圖工具生成的,也有可能是復制粘貼的,不同來源解析方式是否一樣?且讀取的時候是否能有效獲取圖片的位置及大小信息?方便文檔內容后期在PC端和移動端展示。無論最終方案是什么,肯定是將所有的且需要的非文本信息轉換為文本信息。
  • word 版本問題 —— word有03、07等好幾個版本,還有WPS版本,解析是否要全部兼容?后綴名有docx和doc,是否全部兼容?當然,前提是已經成功解析一種類型。
  • word 規范問題 —— 有些word可能是早期制作的,返工代價太大,所以格式內容多樣化。而且就算制定word格式規范,新制作的word也無法保證格式一定正確,除非是程序自動生成的文檔。舉個例子,試題的題序,肉眼無法區分的格式就有好幾種。程序只可能盡量覆蓋絕大部分情況,考慮的情況越多,解析正確率越高,當然程序也更復雜。

MathType公式編輯器

word自帶公式編輯器

word自帶圖表


Java解析word

以前曾用Java解析過word文檔,所以最先考慮用Java來解決問題,網上搜索方案主要有如下幾種:

  • jacob:網上資料較少,目前已經實現的是用jacob解析mathtype輸入的公式,然后調用word宏命令轉成latex,但jacob無法解析word自帶的公式。jacob也可以定位word圖片總數及word圖片位置,但目前沒找到將圖片另存本地的方法。
  • poi:情況與jacob類似。
  • Aspose.words:一個商業收費類庫,可以使應用程序處理大量的文件任務,支持word、pdf等各種格式操作。但是看文檔介紹沒有關於公式的處理方案。

Java使用以上幾種方案的確解決了部分問題,但很多異常情況還是無法處理,比如無法定位word的批注等。
以下是使用Java定位word圖片總數及其位置的代碼,更多解決方案請戳 http://www.cnblogs.com/x_wukong/p/4270867.html

package com.latex.test;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class test {
	public static void main(String[] args) {
		long time1 = System.currentTimeMillis();
		ActiveXComponent word = new ActiveXComponent("word.Application");
		Dispatch wordObject = (Dispatch) word.getObject();
		Dispatch.put((Dispatch) wordObject, "Visible", new Variant(false));
		Dispatch documents = word.getProperty("Documents").toDispatch();
		Dispatch document = Dispatch.call(documents, "Open", "D://test.docx").toDispatch();
		Dispatch wordContent = Dispatch.get(document, "Content").toDispatch();
		Dispatch paragraphs = Dispatch.get(wordContent, "Paragraphs").toDispatch();
		
		int paragraphCount = Dispatch.get(paragraphs, "Count").getInt();// 總行數
		for (int i = 1; i <= paragraphCount; i++) {
			Dispatch paragraph = Dispatch.call(paragraphs, "Item", new Variant(i)).toDispatch();
			Dispatch paragraphRange = Dispatch.get(paragraph, "Range").toDispatch();
			String paragraphContent = Dispatch.get(paragraphRange, "Text").toString();
			System.out.println(paragraphContent);//打印每行內容
			
			Dispatch imgDispatch = Dispatch.get(paragraphRange, "InlineShapes").toDispatch();//圖片
			int imgCount = Dispatch.get(imgDispatch, "Count").getInt();
			System.out.println("第" + i +"行圖片總數" + imgCount);
			
			for(int j=1;j<imgCount+1;j++){
				Dispatch shape = Dispatch.call(imgDispatch, "Item", new Variant(1)).toDispatch();
				Dispatch imageRange = Dispatch.get(shape, "Range").toDispatch();
				Dispatch.call(imageRange, "Copy");
				Dispatch.call(imageRange, "Paste");
			}
		}

		Dispatch.call(document, "SaveAs" , new Variant( "D://test1.docx"));
		Dispatch.call(document, "Close", new Variant(true));
		Dispatch.call(word, "Quit");
		long time2 = System.currentTimeMillis();
		double time3 = (time2 - time1)/1000;
		System.out.println(time3 + " 秒.");

	}
}

問題分析

用Java預研一段時間后,進展緩慢,很多非文本內容無法解析,歸根結底是不知道word內部層級結構。
如果能像html頁面那樣知道各個節點的構成,那么word解析成功按道理就只是時間問題。
但是word是微軟的項目,不開源,所以得去搜索下微軟本身是否提供了解析word層級結構的插件。
然后發現了個好東東,名為 Open XML SDK 2.0 Productivity Tool
下載安裝后,把一個word文檔拖進面板,就可以看見word層級結構了 ~(~ ̄▽ ̄)~

知道層級結構就可以着手解決解析問題了,其它核心細節這里不方便透露,感興趣的可以私聊,哈哈 ~~


其他

word中的公式處理是一個比較大的門檻,這里分享一篇不錯的文章:
菁優網、梯子網、猿題庫的數學公式是如何實現的?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM