Updated: 2003-03-24 07:16:25 - [ Home | Wiki Home | Index | Changes ]
DigesterでXMLを読もう
Jakarta Commonsプロジェクトの一つとして開発されているDigesterは、XMLデータからJavaオブジェクトの生成とセットアップを行うためのライブラリです。SAXやDOMを使って自前でハンドリングするよりも、ずっと簡単にXMLファイルの読み込みが実現できます。
JAXB、Castor、Relaxerといったデータバインディングのツールと比べると、非常にシンプルである点が特徴です。スキーマからクラスを自動生成したり、オブジェクトからXMLを出力したりすることはできませんが、そのぶん、手軽にロードの処理だけを行うことができます。
Digesterを使ってXMLをロードするのに必要なことは、基本的に3つだけです。
これだけです。
1と3には、あまり面白いところはありません。1は、ごく普通にnewでインスタンスを作成するだけです。3のparseメソッドは、XMLの入力(InputStreamや、File、Readerなど)を引数にして呼び出します。parseメソッドの戻り値が、ほしかったオブジェクトになっています。
ポイントは、2の「パターンとルール」です。具体的なサンプルを見る前に、「パターンとルール」、それから最も重要な「スタック」について学んでおきましょう。
XMLを自由にロードするには、「XMLにどんなことが書かれていたら」「何をするか」を指定する必要があります。例えば、「textという要素に、colorという属性があったら」「TextオブジェクトのsetColor()メソッドを呼びなさい」という条件と動作の指定が必要です。
Digesterは、この「XMLにどんなことが書かれていたら」「何をするか」を表現するのに、パターンとルールという考え方を使います。「どんなことが書かれていたら」の部分を表現するのが、パターンです。「何をするか」を指定するのは、ルールです。
XML要素がパターンにマッチ → ルールでJavaオブジェクトに対する処理を実行
パターンは、どんな要素が出現したらルールを起動するかを、文字列で表現します。例えば、
html/body/p
といった具合です。これは、予想どおり、html要素の子の、body要素の子の、p要素を表現しています。ワイルドカードも使えます。例えば、
*/p/a
といった具合です。
XML要素がパターンにマッチすると、対になるルールが起動します。ルールは、抽象クラスRuleのサブクラスです。Ruleには、
という4つのメソッドがあり、パースの各段階でそれぞれのメソッドが呼ばれます。
Ruleの実装クラスによって処理の内容を決めていくわけですが、ほとんどの場合、あらかじめ提供されたクラスを使用すれば事が足ります。たとえば、CallMethodRule(メソッドを呼び出すルール)や、SetPropertiesRule (プロパティをセットするルール)などが準備されています。
ここで、少し不安になった方もいるかもしれません。いったい「メソッドを呼び出すルール」というのは、どのオブジェクトのメソッドを対象にしているのでしょうか。「プロパティ」というのは、どのオブジェクトのプロパティのことなのでしょう。さらに言えば、オブジェクト同士を関連付けるには、どういった複雑なルールが必要になるのでしょうか。
Digesterは、オブジェクトのスタックを持つことで、とてもスマートにこの問題を解決しています。
Digesterインスタンスは、内部に一つスタックを持っています。このスタックを使って、生成したオブジェクトを保持したり、ルールの対象となるオブジェクトを決めたり、オブジェクト同士の親子関係を設定したりします。
では、そろそろ実際のコードを見ていきましょう。
import org.apache.commons.digester.*;
public class DigesterSample1 {
public static void main(String[] args) throws Exception {
// まずはdigesterインスタンスを作成します。
Digester digester = new Digester();
// 次にパターンとルールのペアをセットします。
// ObjectCreateRuleは、指定したクラスのオブジェクトを生成してスタックに積みます。
digester.addRule("html/body",
new ObjectCreateRule(Body.class));
digester.addRule("html/body/p",
new ObjectCreateRule(Paragraph.class));
// SetPropertiesRuleは、スタックの一番上にあるオブジェクトのsetterを呼びます。
// 以下のXMLの場合、setId()メソッドが呼ばれます。
digester.addRule("html/body/p",
new SetPropertiesRule());
// SetNextRuleは、スタックの上から二番目のオブジェクトのメソッドを、
// スタックの一番上にあるメソッドを引数にして呼び出します。
// この時スタックは上から順にparagraph, bodyと積まれているので
// body.setParagraph(paragraph) が実行されます。
digester.addRule("html/body/p",
new SetNextRule("setParagraph"));
// test.xmlファイルをパースして、Bodyオブジェクトを取得します。
Body body = (Body)digester.parse("test.xml");
System.out.println(body);
}
}
以下のtext.xmlを、このクラスで処理してみます。
<?xml version="1.0" encoding="EUC-JP"?> <html> <body> <p id="text1">いろはに</p> <p id="text2">ほへと</p> </body> </html>
パース中に、スタックは以下のように変化します。
「パターン」と「ルール」、それから「スタック」によって、わかりやすさと柔軟性が自然に両立していることがわかります。
ルールは、大きく分けて4種類あります。
バージョン1.3で提供されている全ルールは以下のとおりです。
まだ途中……