JSR 225: XQuery API for Java (XQJ)

XQueryは、XML形式のデータソースに対して問い合わせを行うための関数型言語であり、「XQuery 1.0: An XML Query Language」としてW3C勧告になっている。「JSR 225: XQuery API for Java(以下、XQJ)」は、JavaアプリケーションにおいてXQuery 1.0仕様に準拠したXML問い合わせを行えるようにするためのAPIだ。

リレーショナルデータベースをデータソースとする場合、その問い合わせ言語としては一般的にSQLが使用される。Javaでは、SQLを利用するための標準的なAPIとしてJDBCが用意されている。JSR 225は、SQLにおけるJDBCの位置づけを、XQueryに対して実現するための仕様と言える。

XQueryの使用例

XQuery 1.0の詳細についてはW3C勧告の仕様を参照してもらうことにし、ここでは一般的によく使われる表現式をXQueryの一例として紹介したい。データソースとなるXML文書としてはリスト1のようなものを考えることにする。

リスト1 books.xml - データソースとなるXML文書

<books>
    <book isbn="978-4-8399-2424-9">
        <title>Java逆引きクイックリファレンス Java5/6対応</title>
        <author>team-thoth</author>
        <publisher>毎日コミニュニケーションズ</publisher>
        <price>2940</price>
    </book>
    <book isbn="978-4-8399-1979-5">
        <title>Code Quality ~コードリーディングによる非機能特性の識別技法~</title>
        <author>Diomidis Spinellis</author>
        <author>(株)トップスタジオ</author>
        <author>鵜飼文敏</author>
        <author>後藤正徳</author>
        <author>平林俊一</author>
        <author>まつもとゆきひろ</author>
        <publisher>毎日コミニュニケーションズ</publisher>
        <price>5880</price>
    </book>
    <book isbn="4-8399-1777-9">
        <title>Light Weight Java</title>
        <author>岡本隆史</author>
        <author>吉田英嗣</author>
        <author>金子崇之</author>
        <author>権藤夏男</author>
        <publisher>毎日コミニュニケーションズ</publisher>
        <price>3360</price>
    </book>
</books>

ここから、著者()が2人以上の本を選択し、リスト2のようなXML文書を抽出したい。

リスト2 抽出したいXML文書

<book authorCount="6">
    <title>Code Quality ~コードリーディングによる非機能特性の識別技法~</title>
    <author>Diomidis Spinellis</author>
    <author>(株)トップスタジオ</author>
    <author>鵜飼文敏</author>
    <author>後藤正徳</author>
    <author>平林俊一</author>
    <author>まつもとゆきひろ</author>
</book>
<book authorCount="4">
    <title>Light Weight Java</title>
    <author>岡本隆史</author>
    <author>吉田英嗣</author>
    <author>金子崇之</author>
    <author>権藤夏男</author>
</book>

この場合、リスト3に示すようなクエリを発行すればよい。

リスト3 抽出クエリの例

for $b in fn:doc("books.xml")//book
let $bt := $b/title/text()
where fn:count($b/author) >= 2
return
    <book authorCount=="{ fn:count($p/author) }">
        <title>{ $bt } </title>
        <author>{ $b/author/text() }</author>
    </book>

ここで使われているのは「FLWR表現式」と呼ばれる表現式である。FLWR表現式は「for」「let」「where」「return」の4つの句から成る表現式で、SQLのselectを使った式とよく似ている。

for句は繰り返しを表し、in句で指定されたPath表現式の展開結果の各ノードに対してそれぞれ繰り返し処理を実行する。Path表現式はXPath 2.0仕様に準拠している。この例の場合、「fn:doc("books.xml")//book」は、books.xml中のノードを表している。抽出されたノードに対しては1つ以上の変数を割り当てることができる。この例ではノードに対して$bという変数を割り当てることになる。

let句では「[変数名]:=[Path表現式]」の形式で変数の割り当てを行う。この例で$bはforで抽出された各ノードに割り当てられるので、$btはそのサブノードであるのテキスト形式を表すことになる。

where句はforおよびletで抽出された結果を、指定された条件でフィルタするためのものだ。ここでは著者が2名以上のものを抽出している。

最後のreturn句は、このクエリの結果を生成する。return句はforとletで抽出されたタプルそれぞれに対して1回ずつ実行される。したがってこの例の場合は、を2つ以上持つノードに対して1回ずつ呼び出され、結果としてをリスト2のようなXML文書が生成される。

XQJによるプログラミング

では上記のようなXQueryをXQJではどのように扱うのだろうか。JSR 225は2007年6月よりPublic Draftが公開されている。そこにはXQJを使ってXML問い合わせを行う例としてリスト4のようなコードが紹介されている。

リスト4 XQJを利用したコード例

// XMLデータソースオブジェクトを取得
XQDataSource xqds = ...;
// XQueryエンジンへ接続
XQConnection conn = xqds.getConnection();
// クエリを実行するためのXQExpressionオブジェクトを生成
XQExpression expr = conn.createExpression();

// 実行するクエリ
String es = "for $n in fn:doc('catalog.xml')//item " + "return fn:data($n/name)";

// クエリを実行し、結果をXQResultSequenceに格納
XQResultSequence result = expr.executeQuery(es);
// 結果を解析して表示
while (result.next()) {
// retrieve the current item of the sequence as a String
   String str = result.getAtomicValue();
   System.out.println("Product name: " + str);
}

// コネクションのクローズ処理
result.close();
expr.close();
conn.close();

詳細は、同時に公開されているXQJのjavadocと照らし合わせるとわかりやすい。XQConnectionはXQueryエンジンへの接続を保持するクラスであり、そのインスタンスはXQDataSourceオブジェクトから取得できる。XQDataSourceはXMLデータソースを表すクラスで、実際のデータソースはJNDIなどから取得する。

実際にクエリを発行するためには、XQConnectionからXQExpressionを生成する。XQExpressionにはクエリ発行のためのexecuteQuery()メソッドが用意されており、ここにXQuery仕様に則った式を渡せば結果がXQResultSequenceとして返ってくる。あとはこれを解析すれば、クエリの結果を取得することができる。

この一連の手順はJDBCを用いてRDBMSに問い合わせする場合とよく似ており、JDBCに慣れ親しんだ開発者にとっても理解しやすい。ただし、それならば同様の機能をJDBCで提供すれば新たなAPIを定義する必要はないのではないかという意見もある。IBMはJSR 225のPublic Draftに対して「JDBC仕様と分ける積極的な理由な見つからない」として承認投票を棄権している。Java EE 6への採用が見送られたこともあり、今後の動向が気になるところだ。