XQueryのFLWR表現式を使いこなす
XMLの本格利用に向けた重要な技術の1つがXMLデータベースの発展だ。そのカギを握るのは、問い合わせ言語XQueryの標準化である。現在、XQueryは標準化目前のところまできており、実際にXQueryの実装も登場している。本記事は、そのXQueryの実践を目的とした。 |
戌亥稔
ビーコンIT
2002/12/10
■QuiPのバージョンアップ
第1回「XQueryを実体験してみる」では、QuiP v2.1.1を利用してXQueryを実行したが、2002年8月に独ソフトウェア・エージーが新バージョンのQuiP v2.2.1.1を公開したため、今回からはQuiPのv2.2.1.1を使って解説する。まだQuiP v2.1.1を使っているユーザーは、ソフトウェア・エージー、またはビーコンITのWebサイトから、最新版のQuiPのダウンロードをお勧めする。インストールなどの注意次項は基本的には同じなので割愛する。
QuiP v2.2.1.1はW3Cが策定中のXQueryの2002年4月30日版のワーキングドラフトに準拠している(2002年12月時点では、2002年11月15日版のワーキングドラフトが最新だ)。
筆者が今回の記事を執筆している間に、W3CはXQueryのワーキングドラフトを2回アップデートしている(2002年8月16日版、11月15日版)。11月15日版ではFLWR表現式はFLWOR表現式(同様にフラワーと読む)に変更された。これは従来のFLWR表現式のFor、Let、Where、Returnに、Order byが加えられたものである。しかし、この記事で使用しているQuiP v2.2.1.1は2002年4月30日版のワーキングドラフトに対応しているため、ここではFLWRのまま説明を続ける。 |
実は、前回作成した問い合わせの中にはQuiP v2.2.1.1でそのまま実行するとQuiPが暴走するものがある。そこで、QuiP v2.2.1.1で実行する場合は変更が必要である。例えばexample-2-2-2を以下に示す。
for $i in |
[ example-2-2-2] 2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧を作る |
この例では、count(members/member)>="2"と、数字にダブルクオーテーションを付けると、QuiP v2.2.1.1でも正しく動作するようになる。ビーコンITからダウンロードできるチュートリアルの例を含んだQuiP v2.2.1.1では、すでにこのような修正をしてあるので、可能ならばそちらをダウンロードすることを勧める。
QuiPの最新アーカイブファイルのダウンロードは下記から行える。
では、前回に続きビーコンIT版を前提にXQueryのチュートリアルを進めていこう。
■FLWR表現式をネストする
XQueryの問い合わせ式の1つであるFLWR表現式は、リレーショナルデータベースで用いられている問い合わせ言語SQLのSELECT句、FROM句、WHERE句のように、For、Let、Where、Returnの4つの句からなる、非常に高度で柔軟な演算をXML文書に対して実行できる表現式だ。
前回は、単純なFLWR表現式を解説してきたが、FLWR表現式では次のように、For句をReturn句の中でネストして記述することで、さまざまなXMLのアウトプットを作り出すことができる。
for $i in |
[ example-2-2-5] FLWR表現式で、For句をネストする |
example-2-2-5によって、下記のプロジェクトごとに整理されたXML文書のデータから、2人以上から構成されるプロジェクトだけを抜き出し、その構成員の名前を出力すると、画面7のような結果を取り出せる。
<?xml version="1.0" encoding="UTF-8"
?> |
リスト1(再録) 検索対象となるファイルProjects.xml |
画面7 2名以上の構成員からなるプロジェクト |
■Sort表現式
FLWR表現式でもPath表現式と同様にSort表現式を使うことによって、繰返し要素を並べ替えることが可能である。
for $i in document("Tutorial/data/projects.xml")//project
sortby (name ascending) |
[ example-2-2-6] FLWR表現式でSort表現式を使う |
画面8 プロジェクト名によってソート |
■FLWR表現式のコンストラクション機能で別の形式に変換する
ここまではFLWR表現式の特徴である、結果のコンストラクション(構築)について試してきた。このコンストラクションの特徴を用いて、今度は実際のアプリケーションで必要と思われる問い合わせを発行してみる。
これまで使ってきたprojects.xmlには、プロジェクトごとにどのようなメンバーが参加しているかが記述されていた。参加メンバーが複数人いる場合には、<members>の下の<member>がオカレンス(繰り返し)を持つ。これはアプリケーションとしてプロジェクト単位で管理する方が都合が良いからである。しかしながら、時には、だれがどのようなプロジェクトに参加しているのかを一覧表示したい場合もある(画面9)。
これは、従来のXPath式では記述できなかった問い合わせである。画面9は、アプリケーションが実際に獲得したい出力形式のイメージである。
従来のリレーショナルデータベースでは、格納するデータをすべて2次元の表形式(第1正規化)にするため、プロジェクトとメンバーの関係を持った表を作る必要があった。このおかげで、データをプロジェクトでくくってみるか、それとも構成メンバーでくくってみるか、いずれか2種類の見方(ビュー)を作成できる。
つまり、リレーショナルデータベースでは、テーブルをジョインしたビューを作成することで、プロジェクトと構成メンバーのどちらを軸としてみるかを切り替えてきたのである。逆にいえば、リレーショナルでは必ずジョインをしなければ、これまで記述してきたような情報を取り出すことができなかった。
その点XMLでは、プロジェクトとメンバーの関係を階層化して持つのが普通である。リレーショナルでは関係をテープルとして扱うのに対して、XMLでは関係を階層として表すことができるからだ。例えば発注伝票などもこのような形式をしている。
リレーショナルデータベースにおいては、発注伝票は伝票全体を表すテーブルとその明細を表すテーブルに分割する。明細のテーブルには、伝票と明細との関係(リレーション)が示されている。
一方XMLにおいては、1つのXML文書で発注伝票を表す。発注と発注明細を表すためには、わざわざ2つのXML文書を作らなくとも、1つの文書の中で階層化すれば十分に表現できるからだ。
画面9 メンバーごとに、どのプロジェクトに所属しているのかを示した結果 |
プロジェクトごとに整理されているオリジナルドキュメントの内容を、画面9のようなメンバーごとの形式に変換するには、下記のようなXQueryを発行すればよい。
let $in := document("Tutorial/data/projects.xml") |
[ example-2-3-1] メンバーごとに、所属しているプロジェクトを表示する |
example-2-3-1ではFor句がネストされており、外側のFor句にあるdistinct-values関数によって、プロジェクトに参加しているメンバーの一覧を作り出している。そして内側のFor句でそれぞれのメンバーの参加しているプロジェクトを拾い上げて、出力結果を作り出している。
■Let句を使い、要素を追加表示
次にプロジェクト名だけではなく、プロジェクトごとにどれぐらいの工数を計画しているかという、<manpower>の要素を同時に表示してみる。Let句を使い、<manpower>を$mpにバインドする。ここで、プロジェクト名の場合は$p/name/text()とプロジェクト名だけを取り出しているのに対して、$mpの場合は$p/members/member[…]/manpowerと、<manpower>のエレメント全体を取り出していることに注目してほしい。
let $in := document("Tutorial/data/projects.xml") |
[ example-2-3-2] manpower要素を同時に表示する |
この結果では、<manpower unit="hour">50</manpower>のように、オリジナルのドキュメントにあるアトリビュートもそのまま出力される(画面10)。これはW3Cの「XML Query Requirements(XML Queryの要件)」2001年2月15日版の中にあるStructural Preservation(構造維持)を、XQueryが忠実に実行しているのにほかならない。つまり、XQueryは結果のコンストラクション(上記XML Query Requirementsでは、Structural Transformation:構造変換として説明している)だけではなく、従来のXPathが持っていた、構造維持の特徴も持ち合わせているのである。
画面10 manpower要素も同時に出力された結果 |
■ForとLet句が作成するタプル
ForとLetの特徴を説明するためにもう1点注目してほしい個所がexample-2-3-2にある。以前に公開された記事「標準化目前:注目のXML問い合わせ言語『XQuery』」でも説明したように、ForとLetはタプル(結果の組)を形成する。example-2-3-2ではRetuenの中で記述されている、for $p in document(…)//project[…]と、let $mp:=$p/members/member[…]/manpowerがそれに当たる。$pと$mpはタプルを生成する。
最新のXQueryワーキングドラフトでは、ForとLetが作成したタプルをTuple Streamとして説明している。具体的には、example-2-3-2で外側のFor句(for $mn in distinct-values($in//member/name))の1回目のループ(川泉陽一のループ)で、内側(Result句の中の)のFor、LetのTupple Streamは、次のようなタプルを生成する。
{ |
これは1人目のメンバー川泉陽一の中に出てくる、プロジェクト名と予定工数のコンビネーションにほかならない。2人目の中田聡のケースは次のようになる。
{ |
中田聡の場合は、モバイルシステムの構築のプロジェクトには参加していないため、3つのタプルが生成される。同様に3人目の本岡欣也は、
{ |
と、タプルを1つ作成する。
■For句のフィルタをWhere句に変更
さてそれでは、example-2-3-2の問い合わせをexample-2-3-3のように変えてみる。
let $in := document("Tutorial/data/projects.xml") |
[ example-2-3-3] 下線のFor句のフィルタをWhere句として外に出した |
変更したのは、Resultの中のFor句(for $p indocument(…)//project[…])のフィルタ([…])をWhere句として外に出しただけである。これを実行しても結果は画面10と同様である。しかし、ForとLetによって生成されるTuple Streamは変わる。example-2-3-3のWhere句を取って実行してみれば一目瞭然である。
let $in := document("Tutorial/data/projects.xml") |
[ example-2-3-4] Where句をとってみると、タプルは変わる |
2人目の中田聡のタプルが次のように変わる。
{ |
同様に3人目の本岡欣也のタプルは次のようになる。
{ |
これは、「標準化目前:注目のXML問い合わせ言語『XQuery』」の記事で説明したように、For句は直積を取るからこのようになるのである。
次に、example-2-3-2の問い合わせをexample-2-3-5のように変えてみる。
let $in := document("Tutorial/data/projects.xml") |
[ example-2-3-5] 今度はLet句を変更する |
違う点はResultの中のLet句を$mp := $p/members/member/manpowerとフィルタ([…])を取り除いただけである。結果は画面11のように直積を取らずに、それぞれのタプルの後に加えられるだけである。
画面11 let句のフィルタを取る |
この2つの例は、For句とLet句の仕組みを理解しやすいように説明しただけで、実際にはexample-2-3-2またはexample-2-3-3のように記述するのが普通だ。このどちらを記述した方が良いかは実装によって変わるので一概にはいえないが、example-2-3-2のような記述をする方が無難である。
次回は、 XQueryであらかじめ定義されている関数とユーザー定義関数について解説する予定だ。
■参考:これまでに紹介した問い合わせファイルのリスト
Query名 | 説明 |
InstallTest.xquery | インストールテスト |
example-2-1-1.xquery | Projects.xmlの中から全てのプロジェクト名を取り出す |
example-2-1-2.xquery | プロジェクトの終了が遅い順番に並び替える |
example-2-1-3.xquery | プロジェクトの終了が遅い順番に並び替え、プロジェクト名のみ表示する |
example-2-1-4.xquery | プロジェクト名でソートし、プロジェクト名のみ表示する |
example-2-2-1.xquery | 2名以上メンバーが存在するプロジェクトを表示する |
example-2-2-2.xquery | 2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧を作る |
example-2-2-3.xquery | 2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧をつくる。但し、プロジェクト名は属性として作成する |
example-2-2-4.xquery | FLWR表現のWhere句を使い、2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧をつくる |
example-2-2-5.xquery | FLWR表現をネストし、2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧を作る |
example-2-2-6.xquery | FLWR表現をネストし、2名以上メンバーが存在するプロジェクトのプロジェクト名とメンバーの一覧をつくり、プロジェクト名でソートする |
example-2-3-1.xquery | projects.xmlをメンバー毎にどういうプロジェクトに参加しているかを表すメンバーリストを作成する |
example-2-3-2.xquery | メンバーリストにそれぞれのプロジェクト毎の計画(フィルタを使う) |
example-2-3-3.xquery | メンバーリストにそれぞれのプロジェクト毎の計画(Where文を使う |
example-2-3-4.xquery | プロジェクト計画の入ったメンバーリストのWhere句を取り除き、Tuple streamを確認する。これによりFor句がどのような働きをするか確認する |
example-2-3-5.xquery | プロジェクト計画の入ったメンバーリストのLet句のフィルタを取り除いて、let句がどのような働きをしているかを確かめてみる |
2/5 |
Index | |
連載:XQueryチュートリアル | |
XQueryを実体験してみる | |
XQueryのFLWR表現式を使いこなす | |
XQueryの関数を使う、定義する | |
XQueryによるXML文書の結合〜1 | |
XQueryによるXML文書の結合〜2 |
- QAフレームワーク:仕様ガイドラインが勧告に昇格 (2005/10/21)
データベースの急速なXML対応に後押しされてか、9月に入って「XQuery」や「XPath」に関係したドラフトが一気に11本も更新された - XML勧告を記述するXMLspecとは何か (2005/10/12)
「XML 1.0勧告」はXMLspec DTDで記述され、XSLTによって生成されている。これはXMLが本当に役立っている具体的な証である - 文字符号化方式にまつわるジレンマ (2005/9/13)
文字符号化方式(UTF-8、シフトJISなど)を自動検出するには、ニワトリと卵の関係にあるジレンマを解消する仕組みが必要となる - XMLキー管理仕様(XKMS 2.0)が勧告に昇格 (2005/8/16)
セキュリティ関連のXML仕様に進展あり。また、日本発の新しいXMLソフトウェアアーキテクチャ「xfy technology」の詳細も紹介する
|
|