計算機システム実験 K-11:
Document Object Modelを用いた
XMLデータへのアクセス(2)

天笠俊之
2006年1月13日

○概要

XMLデータへプログラムからのアクセスを行うための規格である DOM (Document Object Model) を学習するとともに,XMLへの理解を一層深める.今回は前回に引き続き,DOMを扱うための基本的事項を学ぶ.

○前回の復習

前回は XML プロセッサ Xerces について,その考え方と基本的なプログラミングを学習した.以下は,指定された XML ファイルを読み込んで主記憶中に DOM 木を構築して終了する,単純な DOM プログラムである.

 1: import org.w3c.dom.*;
 2: import org.apache.xerces.parsers.*;
 3:
 4: class DomParserDemo {
 5:   public static void main(String[] args) {
 6:     try {
 7:       // DOM パーサの生成
 8:       DOMParser parser = new DOMParser();
 9:       // XML 文書の取得
10:       parser.parse(args[0]);
11:       // Document インスタンスの取得
12:       Document doc = parser.getDocument();
13:     } catch (Exception e) {
14:       e.printStackTrace();
15:     }
16:   }
17: }

プログラムの概要は以下の通りである. 1〜2行目は C 言語の include 文に相当するものであり,プログラム内で利用しているクラスのインタフェースに関する情報がどこにあるかを指定するものである. org.w3c.dom.* の * は,org.w3c.dom.Attr, org.w3c.Element などの複数のインタフェースを簡潔に一文で指定するための機能である. 1行目の org.w3c.dom は,XML データ用の Java のパッケージに関する import 文である. このパッケージの概要は,http://java.sun.com/j2se/1.4/ja/docs/ja/api/org/w3c/dom/package-summary.htmlなどで見ることができる. 2行目の org.apache.xerces.parser は,今回用いている Xerces のインタフェースを指定している.

4〜17行目が実際のプログラムである. main 関数は引数として文字列をとり(5行目),6〜15行目を実行する. try {...} catch {...} という構文は Java で基本となる構文である. 通常,何も問題がなければ try の中の文を実行してプログラムが終了する. しかし,例外(exception)が生じた場合には,catch の部分が実行される. このプログラムにおける例外は,DOM パーサ(Xerces)が何らかのエラーを検出した場合に発生する. catch の部分では,例外発生時の後始末などを書くことになるが,このプログラムでは,printStackTrace() を呼ぶことで,実行状況のスタックを表示している. プログラムの本体では,まず8行目で DOMParser オブジェクトを生成する. 10行目では,生成したパーサにより,第1引数で与えられた XML ファイルをパース(構文解析)する. この時点で XML が整形式(well-formed)であるかをチェックし,メモリ上にXML データに対する DOM の木構造を作成する. 12行目の getDocument() により,構築した木構造のルートとなるDocument オブジェクトを得る.

演習課題 1

上記プログラムに,整形式の XML データと,(終了タグ等を省略するなどして作成した)整形式でない XML データを入力し,何が起こるか確かめてみよう.

なお,関連するソースファイルは,これまでと同様 /home/lab/Denjo/amagasa/jikken/07 においてあるので,各自のディレクトリにコピーした上で使用すること.

○エラー処理

上に示したプログラムでは,パーサがエラーを検出した場合には,例外をcatch 文内で処理していた.しかし,エラーハンドラを用いてよりきめ細かいエラー処理を行うことが可能である. エラーハンドラによるエラー処理を含めたプログラムを以下に示す.

 1: import org.w3c.dom.*;
 2: import org.apache.xerces.parsers.*;
 3: import org.xml.sax.*;
 4:
 5: class DomParserDemo2 {
 6:   public static void main(String[] args) {
 7:     try {
 8:       // DOM パーサの生成
 9:       DOMParser parser = new DOMParser();
10:       // エラーハンドラの登録
11:       parser.setErrorHandler(new MyHandler());
12:       // XML 文書の取得
13:       parser.parse(args[0]);
14:       // Document インスタンスの取得
15:       Document doc = parser.getDocument();
16:     } catch (Exception e) {
17:       e.printStackTrace();
18:     }
19:   }
20: }
21:
22: class MyHandler implements ErrorHandler {
23:   public void warning(SAXParseException e) {
24:     System.out.println("警告: " + e.getLineNumber() + "行目");
25:     System.out.println(e.getMessage());
26:   }
27:   public void error(SAXParseException e) {
28:     System.out.println("エラー: " + e.getLineNumber() + "行目");
29:     System.out.println(e.getMessage());
30:   }
31:   public void fatalError(SAXParseException e) {
32:     System.out.println("深刻なエラー: " + e.getLineNumber() + "行目");
33:     System.out.println(e.getMessage());
34:   }
35: }

エラーハンドラを使うには org.xml.sax.ErrorHandler というインタフェースの規定にしたがってハンドラを実装することになる. このインタフェースは,本来 SAX に対するエラー処理を規定したものであるが,DOM でも同様のエラー処理を行うため,このインタフェースを共用している. 3行目の org.xml.sax.* により, org.xml.sax.ErrorHandler のインタフェース情報をを読み込むようにしている. org.xml.sax.ErrorHandler には,以下の3つのメソッドが定義されている. どれも,引数として SAXParseException 型のオブジェクトを値にとる.

warning がもっとも軽いエラーであり,fatalError がもっとも深刻なエラーに対応する. プログラム本体部の違いは,11行目で MyHandler というエラーハンドラを登録している点のみである. そのエラーハンドラの実体は22〜35行目にある.それぞれのエラーの種類に応じてメソッドが定義されている.この場合はほとんど内容が同じであるが,この内容を場合に合わせて加工することで,きめ細かなエラー処理が可能となる.

演習課題 2

上記プログラムに,意図的にエラーを起こすような XML データを入力し,何が起こるか確かめてみよう.

○妥当性の検証

Xerces の DOM パーサはデフォルトでは妥当性の検証(DTD に XML 文書がしたがっているかどうかのチェック)は行わない.したがって DomParserDemo2.java で発生する例外は,

というような場合に限られる.

妥当性検証を行いたい場合には,以下のようにプログラムを修正すればよい.

 1: import org.w3c.dom.*;
 2: import org.apache.xerces.parsers.*;
 3: import org.xml.sax.*;
 4:
 5: class DomParserDemo3 {
 6:   public static void main(String[] args) {
 7:     try {
 8:       // DOM パーサの生成
 9:       DOMParser parser = new DOMParser();
10:       // エラーハンドラの登録
11:       parser.setErrorHandler(new MyHandler());
12:       // 妥当性検証の設定
13:       parser.setFeature("http://xml.org/sax/features/validation", true);
14:       // XML 文書の取得
15:       parser.parse(args[0]);
16:       // Document インスタンスの取得
17:       Document doc = parser.getDocument();
18:     } catch (Exception e) {
19:       e.printStackTrace();
20:     }
21:   }
22: }
23:
24: class MyHandler implements ErrorHandler {
25:   // 先の例と同じなので省略
26: }

具体的には,13行目で妥当性検証を行うフィーチャを true に設定することで, 妥当性検証を行うことを指示する. このようなXerces のフィーチャには他にも種類がある. 代表的なフィーチャは以下の通りである.

演習課題 3

上記プログラムに,意図的にエラーを起こすような XML データを入力し,正しくフィーチャーが認識され,XML プロセッサの動作が変わったかどうかを確かめよう.

課題レポートの提出

演習課題 2 と 3 について,合計 4 通り以上のケースについて,入力 XML データおよびプログラムの出力を示し,簡単な考察を加えよ.

提出期限は 1/17(火).メールの作成には以下のテンプレートを利用すると良い.