JavaでDOMクラスライブラリを使用してプログラミングしてみる.
DOMとSAX
DOMとは
環境の準備
DOMでXML文書を読む
DOMとSAX
XMLパーサとして,DOMとSAXがある.これらは,XML文書をプログラムで扱う際の方式である.それぞれに対応したXMLパーサ(ライブラリ)が多くの言語で提供されている.DOMとSAXはどう違うのかは,本ページの「DOMとは」とJavaでSAXのページの「SAXとは」を参照.
DOMとは
DOMはData Object Modelの略である.JavaではSunがJAXP(Java API for XML Programing)というパッケージにDOMに対応したXMLパーサが入っている(このパッケージには,SAXに対応したXMLパーサも入っている).
DOMでは,XML文書を一気に読み込んで,要素のツリーを構築する.このツリーをランダムに行き来したり,削除したりすることができる.その代わり,要素のツリーを構築するために大きなXML文書を読み込むにはそれなりのメモリを必要とする.イメージとしてはDOMはXMLを大局的にとらえるのに向き,SAXは局所的にとらえるのに向く,と思う.
環境の準備
DOMのクラスライブラリを使うために.
apt-get install libcrimson-java libcrimson-java-doc
export CLASSPATH=/usr/share/java/xerces.jar
これでorg.apache.crimsonをimportできる.このパッケージやSAXのページで述べるパッケージのクラスのようにXML文書を扱うことのできるモジュールをXMLパーサと呼ぶ.apt-cache showによると,libcrimson-javaはJAXPをサポートしているらしい.
DOMでXML文書を読む
DOMでXML文書を読み込むと,ツリーが出来上がる.ツリーのノードとなるのは,タグやテキストなどである.DOMを使用すると,これらのノードを取得したり,子ノードに移動したりできる.もちろん要素の名前やノードの種類やノードの値などを取得できる.
DOMを使用したサンプルプログラムを以下に示す.
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.apache.crimson.tree.*;
class DomSample{
protected Document doc;
protected int tab;
public DomSample(String filename){
try{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
/* XML文書を読み込む.*/
doc=db.parse(new FileInputStream(filename));
}catch(Exception e){
e.printStackTrace();
}
tab=0;
}
public void getNodeInfo(Node node){
tabbing();
/* ノードの種類を出力 */
System.out.println("Node type= "+node.getNodeType());
tabbing();
/* ノード名を出力 */
System.out.println("Node name= "+node.getNodeName());
tabbing();
/* ノードの値を出力 */
System.out.println("Node value= "+node.getNodeValue());
}
/* 全ノードを探索 */
public void walkThrough(){
Node root=doc.getDocumentElement();
recursiveWalk(root);
}
private void recursiveWalk(Node node){
/*
これは,XML文書のインデントなどの空白のノードを読み飛ばすための処理.
Node.TEXT_NODE ノードがテキストで,ノードの値の空白を除いた文字列の長さが0の場合は読み飛ばす.
*/
if(node.getNodeType()==Node.TEXT_NODE && node.getNodeValue().trim().length()==0){
return;
}
getNodeInfo(node);
tab++;
/* node.getFirstChild : nodeの最初の子を得る */
/* child.getNextSibling : childの兄弟ノードを得る */
for(Node child=node.getFirstChild();child!=null;child=child.getNextSibling()){
recursiveWalk(child);
}
tab--;
}
protected void tabbing(){
for(int i=0;i<tab;i++){
System.out.print("\t");
}
}
public static void main(String args[]){
DomSample ds=new DomSample("sample.xml");
ds.walkThrough();
}
}
このプログラムに以下のXML文書sample.xmlを読み込ませる.
<?xml version="1.0" encoding="Shift_JIS" ?>
<drinks>
<drink type="soft">
<name>Apple</name>
<taste>Good</taste>
</drink>
<drink type="alcohol">
<name>Beer</name>
<taste>Bitter</taste>
</drink>
<drink type="alcohol">
<name>Whiskey</name>
</drink>
</drinks>
java DomSampleの実行結果を以下に示す.
Node type= 1
Node name= drinks
Node value= null
Node type= 1
Node name= drink
Node value= null
Node type= 1
Node name= name
Node value= null
Node type= 3
Node name= #text
Node value= Apple
Node type= 1
Node name= taste
Node value= null
Node type= 3
Node name= #text
Node value= Good
Node type= 1
Node name= drink
Node value= null
Node type= 1
Node name= name
Node value= null
Node type= 3
Node name= #text
Node value= Beer
Node type= 1
Node name= taste
Node value= null
Node type= 3
Node name= #text
Node value= Bitter
Node type= 1
Node name= drink
Node value= null
Node type= 1
Node name= name
Node value= null
Node type= 3
Node name= #text
Node value= Whiskey
うまく全ノード探索できた.
ここで述べたのはまだDOMのほんの入口に過ぎない.DOMでは要素,属性やテキストを読み込み,追加,削除,ツリーをXML文書として書き出すなどができるが,それらは以降に回す.