mb_language("uni"); mb_internal_encoding("utf-8"); mb_http_input("auto"); mb_http_output("utf-8"); ?>
前回は、Xprioriを利用したアプリケーションXML2CSVのソースコードから、XML DBプログラミングの基本的なポイントを学んだ。前回のポイントを押さえていれば、悩むことなくXML DBプログラミングを実践していけるはずだ。
今回は、もう少しXML DBプログラミングの幅を広げてみたい。問い合わせ言語であるXQueryの記述は、XML DBプログラミングにとって重要な要素となる。XML2CSVでは、XMLからCSVへの変換を定義するために、XQueryを自動生成するという特徴的な機能をもっている。XQueryを扱う1つのアプローチとして、自動生成の方法を学ぶことにする。
RDBプログラミングではデータベースとの通信はSQLを介して行われるように、XML DBプログラミングではXQueryを使う。どちらも問い合わせ(クエリ)言語の一種だ。以下は、SQLとXQueryの例である。
| SELECT * FROM my_table WHERE my_number > 10; |
for $order in /orders/order
let $price := $order/price/text()
where $price > 1000
return
<order>
<number>{$order/number/text()}</number>
<name>{$order/@name/text()}</name>
<price>{$price}</price>
</order>
|
XML DBプログラミングでは、XQueryの記述が多くの要素を占める。XMLデータへの問い合わせや更新の条件が複雑になればなるほど、XQueryも長く複雑になるだろう。XQueryをテキストの連結で直にプログラム中に書き込んでいくのが最も基本的な方法だが、別のアプローチもある。
XML2CSVが採用しているのは、XQueryのオブジェクトモデルを作ってXQueryを自動生成するアプローチだ。これなら、プログラム中にXQueryをあらかじめ用意しておかなくとも、条件入力に応じて動的にXQueryを発行することができる。
XQueryをプログラム中で自動生成するには、XQueryのオブジェクトモデルを作る必要がある。XML2CSVの中で使われているXQueryのオブジェクトモデルを、UMLのクラス図で表すと次のようなものになる。

▲XML2CSVのXQueryオブジェクトモデル
XQueryModelオブジェクトが、生成すべきXQuery全体を表す。このオブジェクトは、中にXQueryForModelオブジェクト、XQueryConditionModelオブジェクト、XQueryReturnModelオブジェクトのリストをもっている。XQueryForModelオブジェクトはXQueryのfor句、XQueryConditionModelオブジェクトはwhere句(の中の条件式)、XQueryReturnModelオブジェクトはreturn句を、それぞれ表している。このように、XQueryの文法が忠実にオブジェクト化されているわけだ。
XQueryの仕様に従ってオブジェクトモデルを一度作ってしまえば、別のアプリケーションでも再利用できるだろう。なお仕様自体はW3CからXQuery 1.0(http://www.w3.org/TR/xquery/)が公開されているが、まだ本稿執筆時点で勧告候補の段階である。
オブジェクトモデルを使って、XML2CSVが実際にどうやってXQueryを生成しているのかを見てみよう。以下は、上記オブジェクトモデルのXQueryModelクラス内部のソースコードだ。getQueryメソッドにて、オブジェクトモデルからXQueryの自動生成を行っている。
private List lstFor = null; // XQueryForModelオブジェクト
private List lstCondition = null; // XQueryConditionModelオブジェクト
private List lstReturn = null; // XQueryReturnModelオブジェクト
private boolean whereFlag = false;
...中略...
public String getQuery() {
StringBuffer sb = new StringBuffer();
// for句の生成
sb.append(getForStr(true));
if (this.whereFlag) {
// where句の生成
sb.append(getConditionStr());
...中略...
}
// return句の生成
sb.append(getReturnStr());
return sb.toString();
} |
やっていることは簡単だ。まずXQueryForModelオブジェクトからfor句を生成し、次にXQueryConditionModelオブジェクトを使ってwhere句を生成する。最後に、XQueryReturnModelオブジェクトを使ってreturn句を生成する。それらを組み合わせて、XQuery全体を構築している。
それぞれの句が、どうやって生成されているかを見てみたい。どの句についても、やるべきプログラミングの内容はそれほど変わりがないので、ここではfor句のみ見ることにする。XQueryModel#getQueryメソッドが呼び出しているgetForStrメソッドの詳細には立ち入らないが、最終的に以下のXQueryForModel#getForStrメソッドが呼び出される。
private String variable = null; // for句の変数
private String node = null; // for句のノード指定
...中略...
public String getForStr() {
StringBuffer sb = new StringBuffer();
sb.append("for ");
sb.append(this.getVariable());
sb.append(" in ");
sb.append(this.getNode());
return sb.toString();
} |
for句は基本的に、
| for $xxx in /yyy/zzz |
のように変数($xxx)とXPathノード指定(/yyy/zzz)とからなる。ここでは、それを素直にモデルから文字列に直している。
このようにして、XQueryに変換可能なオブジェクトモデルを構築しておけば、あとはそのオブジェクトモデルをプログラム実行中にカスタマイズするだけで、さまざまなXQueryを柔軟に発行できるようになるわけだ。重要なポイントは、XQueryのオブジェクトモデルを用意することである。
ただし注意点がある。上記の方法は、時として非常に大きなサイズのXQueryを生成してしまうことがある。Xprioriでは通常、XQueryのサイズに上限が設定されている。この上限値に引っ掛からないよう注意が必要である。また、自動生成されたXQueryは、パフォーマンスの面で最適化されているとは言い難い。パフォーマンスが重視される局面では、自動生成ではなく、直接にXQueryを記述することになる。XQueryを自動生成するか直接記述するかの選択には、柔軟さとパフォーマンスとのトレードオフがあることを覚えておいてほしい。
以上、XML DBプログラミングの重要な要素であるXQueryについて、それを動的に生成するというアプローチをXML2CSVのソースコードから読み解いた。高度なクエリを発行しようとすると、当然XQueryは長大で複雑になっていく。こうした場合に、XQueryを自動生成するアプローチもプログラミング上の選択肢の1つに入れておくとよいだろう。
▲このページのTOPへ