[原]Wordドキュメント解析using Jacob&HtmlParser


JavaのWordの解析方法は、jacob呼び出しoffice comコンポーネントによるWordドキュメントオブジェクトの処理など、さまざまな方法が知られています.ここで紹介する方法は、jacobとHtmlParserを組み合わせてwordドキュメントの内容を解析することであり、この方法を利用してwordを解析するネットユーザーに役立つことを望んでいます.
1.wordをhtmlに変換
    ここではJacobを用いてwordからhtmlへの変換を実現する.Jacobの使用はここでは詳しくは述べませんが、サーバー側にマイクロソフトのOfficeをインストールする必要があることが前提です(もちろんオペレーティングシステムもマイクロソフトの家が必要です).wordをhtmlに変換する機能はツール類Word 2 Htmlに書かれており(同様のやり方はネットワーク上で多く紹介されている)、wordに対する解析はhtmlに対する解析に変換される.
 
2.htmlの解析(using HtmlParser)
    html解析を紹介する前に、wordドキュメントの内容構造を説明する必要があります.
    タイトル番号のあるwordドキュメントでは、トップページから末尾ページまで番号に基づいて深さ遍歴ツリーと見なすことができます.隣接する番号の間には親子または兄弟関係があり、番号のある階層はタイトルフォーマットで定義されています.また、文書内で構造化されていると考えられる内容には、各種の約定フォーマットのタイトル、表、約定フォーマットの段落、項目記号、番号が含まれる.htmlに変換すると,HtmlParserを用いてこれらの構造化されたデータを容易に解析できる.解析されたデータが親子関係の参照を維持する必要がある場合は、htmlドキュメント内の解析オブジェクトの位置を記録する必要があります.HtmlParserにはこれらの機能があります.
    HtmlParser APIでは、識別ノードは主にラベル名構築フィルタ(NodeFilter)によってNodeListを得るが、NodeListの中のNodeを処理し、HtmlParserの紹介についてはhttp://htmlparser.sourceforge.net/参照
    次に、抽象クラスAbstractHtmlParserにカプセル化されたHtmlParser解析htmlの一般的な要素を適用するいくつかの一般的な方法について説明します.次に、いくつかの一般的な方法について説明します.
    1.ノードの下にあるすべてのtextを取得する
    たとえば、次のhtmlクリップは、「ABC」を返します.
<td width=230 style='width:172.65pt;border-top:none;border-left:none;
  border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
  padding:0cm 5.4pt 0cm 5.4pt'>
  <p class=MsoNormal><span style='font-family:'>ABC</span></p>
 </td>
 
protected String getAllTextInNode(Node node) {
		StringBuffer sb = new StringBuffer();
		if (node instanceof TextNode) {
			TextNode textNode = (TextNode) node;
			String text = textNode.getText().trim();
			if (!StringUtil.isEmpty(text)) {
				sb.append(text.replace("&nbsp;", " ").replace("&gt;", ">")
						.replace("&lt;", "<").replace("&quot;", "\"").replace(
								"&amp;", "&").replace("&apos;", "'"));
			}
		} else if (node instanceof RemarkNode) {
			// do nothing
		} else if (node instanceof TagNode) {
			TagNode tagNode = (TagNode) node;
			NodeList nl = tagNode.getChildren();
			if (null != nl) {
				for (SimpleNodeIterator i = nl.elements(); i.hasMoreNodes();) {
					sb.append(getAllTextInNode(i.nextNode()));
				}
			}
		}
		return sb.toString();
	}
 
    2.ヘッダ付きテーブルを解析し、List>に戻る
エンコーディング
エンコーディング名
説明
1
8K
 
2
16K
 
3
32K
 
4
 
/**
	 *      (  thead  )    ,    List,    List Map key,        Map value。<br>
	 *              ,     。
	 * <p>
	 * @param table
	 * @return
	 */
	protected List<Map<String, String>> getListFromTheadTable(Node table) {
		List<Map<String, String>> result = new ArrayList<Map<String,String>>();
		TagNameFilter theadFilter = new TagNameFilter(TAG_THEAD);
		NodeList theadList = table.getChildren().extractAllNodesThatMatch(
				theadFilter);
		TagNode theadNode = null;
		if (theadList != null && theadList.size() > 0) {
			theadNode = (TagNode)theadList.elementAt(0);
		}
		if (theadNode == null) {
			return result;
		}
		
		// process rows following <thead>
		HasSiblingFilter theadSibFilter = new HasSiblingFilter(theadFilter);
		AndFilter andFilter = new AndFilter(new TagNameFilter(TAG_TR), theadSibFilter);
		NodeList trNodeList = table.getChildren().extractAllNodesThatMatch(new TagNameFilter(TAG_TR));
		String[] keys = getTdTextInRow(trNodeList.elementAt(0));
		for (int i=1; i<trNodeList.size(); i++) {
			Map<String, String> map = new HashMap<String, String>();
			String [] values = getTdTextInRow(trNodeList.elementAt(i));
			if (values.length != keys.length) {
				break; //              ,        
			}
			for (int k=0; k<keys.length; k++) {
				map.put(keys[k], values[k]);
			}
			result.add(map);
		}

		return result;
	}
 
    3.解析取得形式は次のTableのデータ対であり、Mapを返す.
番号付け
0001
名前
カードステータス
コード長
2
公開シーケンス
01
説明
 
/**
	 * @param table
	 * @return
	 */
	protected Map<String, String> getMapFormTable(Node table) {
		Map<String, String> result = new HashMap<String, String>();
		NodeList trNodeList = table.getChildren();
		for (SimpleNodeIterator trIter = trNodeList.elements(); trIter
				.hasMoreNodes();) {
			Node trNode = trIter.nextNode();
			if (!isNodeType(trNode, TAG_TR)) {
				continue;
			}
			NodeList tdNodeList = trNode.getChildren();
			Node tdKeyNode = tdNodeList.elementAt(0);
			Node tdValNode = null;
			while (true) {
				if (!isNodeType(tdKeyNode, TAG_TD)) {
					tdKeyNode = getNextSiblingNode(tdKeyNode, TAG_TD);
					continue;
				}
				tdValNode = getNextSiblingNode(tdKeyNode, TAG_TD);
				if (null == tdValNode) {
					break;
				}
				result.put(getAllTextInNode(tdKeyNode),
						getAllTextInNode(tdValNode));

				tdKeyNode = getNextSiblingNode(tdValNode, TAG_TD);
				if (null == tdKeyNode) {
					break;
				}
			}
		}
		return result;
	}

   
    4.1行のtdタグに含まれるtextを取得し、String[]に戻る
/**
	 *      td     text,  String[]
	 * 
	 * @param trNode
	 * @return
	 */
	protected String[] getTdTextInRow(Node trNode) {
		if (!isNodeType(trNode, TAG_TR)) {
			return null;
		}
		List<String> values = new ArrayList<String>();
		NodeList tdNodeList = trNode.getChildren().extractAllNodesThatMatch(
				new TagNameFilter(TAG_TD));
		for (SimpleNodeIterator it = tdNodeList.elements(); it.hasMoreNodes();) {
			values.add(getAllTextInNode(it.nextNode()));
		}
		return values.toArray(new String[] {});
	}
 
    5.指定した親ノードの下で、指定したTagNameの子孫ノードを検索し、最初のTagNameの子孫ノードを深さの遍歴で返します.
/**
	 *            TagName     ,           TagName     
	 * 
	 * @param parent
	 * @param tagName
	 * @return
	 */
	protected Node getNodeInChildren (Node parent, String tagName) {
		if (parent == null) {
			return null;
		}
		NodeList children = parent.getChildren();
		if (children == null) {
			return null;
		}
		for (SimpleNodeIterator it=children.elements(); it.hasMoreNodes(); ) {
			Node child = it.nextNode();
			if (child instanceof TagNode) {
				if (tagName.equalsIgnoreCase(((TagNode) child).getTagName())) {
					return child;
				} else {
					return getNodeInChildren(child, tagName);
				}
			}
		}
		return null;
	}

 
    JacobとHtmlParserを利用してWordのドキュメントを解析してここまで紹介して、HtmlParserの深い使い方について暇があればまたみんなと分かち合います.