標準化目前:注目のXML問い合わせ言語
XQuery
 〜中編

XQueryでは、単にデータベースに格納されたXML文書に対して検索が行えるだけではなく、射影、選択、繰り返しといった、リレーショナルモデルのような演算も可能になっている。今回は、そのXQueryの問い合わせ言語の詳細に迫ってみる。もしもSQLのことを基礎知識としてご存じであれば、より一層理解が深まるはずだ。

戌亥稔
ビーコンIT
2002/3/15


2つの表現式、PathとFLWR

 XQueryは、「表現式(Expression)」が基本単位となっていて、いくつかの表現式を組み合わせたり入れ子にしたりしながら記述する「関数型言語(Functional Language)」です。また、データの型を確認しながら実行される、強く型付けされた言語(Strongly-Typed Language)でもあります。

 XQueryの代表的な表現式としては、「Path Expression(Path表現式)」と「FLWR Expression(FLWR表現式、フラワー表現式と読みます)」の2つがあります。この2つを覚えておけば、後はその応用でほとんどの機能を記述できます。そこで、今回は特にこの2つの表現式を詳しく説明します。そのほかの表現式に関しては、この解説を読んだ後にW3Cの「XQuery 1.0: An XML Query Language」(2002年3月現在、ワーキングドラフト)で確認することをお勧めします。

表現式はシーケンスで表される

 表現式は常にシーケンス(sequence)で表されます。シーケンスとは、順番を持った0個以上のアイテムの集まりです。アイテムは、単純な値か、もしくはノード(要素や属性)を表しています。単純な値とはXML Schemaの中の基本データ型(Primitive Datatypes)によって表される値のことで、基本データ型には例えばstring、 boolean、decimal、float、double、duration、date time、time、dateなどが当たります。具体的な例として「1,2,3」や「<one/>、<two/>、<three/>」のような値が、シーケンスと呼ばれます。表現式はこのような基本データタイプの集まりか、もしくはノードの集まりを値として取ります。

表現式の例
1,2,3
<one/>、<two/>、<three/>

 表現式の詳細について説明を始める前に、説明で使うサンプルデータ(projects.xml)を紹介しておきます。サンプルデータには、各プロジェクトとそれに属するメンバーが示されています。それぞれのメンバーは、そのプロジェクトにどれだけの工数(時間)を使う予定であるかが表されています。それぞれのプロジェクトには1人以上のメンバーが参加し、各メンバーは複数のプロジェクトに参加できるものとします(分かりやすいように色を付けました)。

<projects>
  <project code="200200020" start="2002/01/20" end="2002/03/31">
    <name>XMLによる文書管理システム</name>
    <members>
      <member>
        <name>川泉陽一</name>
        <manpower unit="hour">100</manpower>
      </member>
      <member>
        <name>中田聡</name>
        <manpower unit="hour">50</manpower>
      </member>
    </members>
  </project>
  <project code="200200025" start="2002/02/15" end="2002/03/25">
    <name>XMLによるB2Bシステム構築</name>
    <members>
      <member>
        <name>本岡欣也</name>
        <manpower unit="hour">100</manpower>
      </member>
      <member>
        <name>川泉陽一</name>
        <manpower unit="hour">50</manpower>
      </member>
    </members>
  </project>
  <project code="200200031" start="2002/03/15" end="2002/03/31">
    <name>モバイルシステムの構築</name>
    <members>
      <member>
        <name>川泉陽一</name>
        <manpower unit="hour">10</manpower>
      </member>
    </members>
  </project>
</projects>

Path表現式

 XQueryの代表的な表現式として、「Path表現式」と「FLWR表現式」の2つがあることを紹介しました。まずはPath表現式について説明しましょう。

 XQueryのPath表現式は、「注目の問い合わせ言語「XQuery」〜前編」で説明したXPathやXQLから、XQueryに引き継がれたものです。Path表現式は大きく分けて2つの操作をデータに対して行います。1つは特定のノード(要素や属性)を指定することであり、もう1つはフィルタをかけてマッチする文書を取り出すことです。これは後述する、リレーショナルの演算でいうところの、射影(Projection)と選択(Selection)と同じ役割を持っています。

 XQuery 1.0のPath表現式はXPath 2.0と同じです。実際にXPath 2.0とXQuery 1.0ワーキングドラフトには、「XQuery 1.0はXPath 2.0をサブセット(部分集合)として含んでいる」と書かれており、「XPath 2.0とXQuery 1.0の両方において同じ構文を実行した場合は、同じ結果を返す」とも書かれています。XPath 2.0はXPath 1.0をかなり拡張して作られていますが、ここでは基本的なPath表現式のみを説明しますので、XPath 1.0をご存じの方は、この部分を読み飛ばしても構いません。

 XML文書は階層構造を持っているため、特定のノードを指定するには親子関係を示すことが必要です。例えば

/projects/project/name

はプロジェクト名だけを取り出すことを表しますが、最初のスラッシュ“/”はルートノードを表し、中間のスラッシュ“/”(“projects/project”や“project/name”)は親子関係を表します。

 アトリビュートノードはアットマーク“@”で表されますので、

/projects/project/@code

  はプロジェクトコードを表します。また、アスタリスク“*”はすべてのノードを表します。例えば、

/projects/project/*

はprojectノードの子要素すべてを表し、

/projects/project/@*

はprojectノードのアトリビュートノードすべてを表します。

 また、Path表現式ではシーケンスの順番を表すインデックスを付けることができます。例えば、1人目のプロジェクトメンバーを表すためには、

/projects/project/member[1]

と記述すればよいのです。最後のメンバーは、

/projects/project/member[last()]

で表すことが可能です。

 また、“//”は子孫関係を表します。

//name

はプロジェクト名(/projects/project/name)とメンバーの名前(/projects/project/member/name)の両方を示します。

 “[ ]”を使うと、Path表現式の中でフィルタをかけることができます。

/projects/project[member]

は、プロジェクトメンバーが存在する(project要素の子要素memberが存在する)場合のprojectのみを抽出します。下記の、

/projects/project[@start >= "2002/01/01"]

は2002年1月1日以降に始まったプロジェクトを抽出します。

/projects/project[member[1]/name="中田聡"]

は、最初のメンバーが「中田聡」であるプロジェクトのみ抽出します。

/projects/project[@start >=
"2002/01/01" and @end <= "2002/03/31"]

は、2002年1月1日以降に始まり2002年3月31日以前に終了するプロジェクトを抽出します。

FLWR表現式

 FLWR表現式は、リレーショナルデータベースで用いられている問い合わせ言語SQLのSelect節、From節、Where節のように、for、let、where、returnの4つの句からなります。

 簡単な例をまず見てみましょう。下記のFLWR表現式は「プロジェクトメンバーが2名以上参加しているプロジェクトの名前を取り出す」ものです。

for $p in document("data\projects.xml")//project
let $pn := $p/name/text()
where count($p//member) >= 2
return <project> <title>{ $pn }</title> <count> {count($p//member)} </count>
<member>{ $p//member/name } </member>
</project>

 それぞれの句について解説していきます。

  for句の説明

 上記のFLWR表現式の、for句について解説しましょう。for句は次のように記述されます。

for [変数名] in [Path表現式] , [変数名] in [Path表現式] …

 for句は繰り返し(iteration)を表します。for句の中のin句のPath表現式で作成されたシーケンスに対して繰り返し実行され、1以上の変数をバインド(割り当て)することができます。バインドされた変数はタプル(結果の組)を作ります。作成されたタプルは順番を持ったシーケンスとなります。上記の例では、変数$pにin句で指定されたPath表現式、すなわちdocument("data\projects.xml")//projectがバインドされ、次のような3つのタプルが作成されます。

上記の例で作成される3つのタプル
( $p ) = {
<project code="200200020" …> … </project> ,
<project code="200200025" …> … </project> ,
<project code="200200031" …> … </project> ,
}

 for句に2つ以上の変数が関連なくバインドされた場合、変数は直積(Cartesian Product)を作成します。直積について初めて聞く方は、次回の「XQueryにおけるリレーショナルの演算」をぜひお待ちください。

 上記構文を次のように書き換えると直積を取ります。結果として15タプルを生成します。

for $p in document("data\projects.xml")//project,
$mn in document("data\projects.xml")//member/name

上記の例で、直積により作成される15のタプル
( $p , $mn ) = {
(<project code="200200020" > </project>, <name>川泉陽一</name>),
(<project code="200200020" > </project>, <name>中田聡</name>),
(<project code="200200020" > </project>, <name>本岡欣也</name>),
(<project code="200200020" > </project>, <name>川泉陽一</name>),
(<project code="200200020" > </project>, <name>川泉陽一</name>),
(<project code="200200025" > </project>, <name>川泉陽一</name>),
(<project code="200200025" > </project>, <name>中田聡</name>),
(<project code="200200025" > </project>, <name>本岡欣也</name>),
(<project code="200200025" > </project>, <name>川泉陽一</name>),
(<project code="200200025" > </project>, <name>川泉陽一</name>),
(<project code="200200031" > </project>, <name>川泉陽一</name>),
(<project code="200200031" > </project>, <name>中田聡</name>),
(<project code="200200031" > </project>, <name>本岡欣也</name>),
(<project code="200200031" > </project>, <name>川泉陽一</name>),
(<project code="200200031" > </project>, <name>川泉陽一</name>)
}

  let句の説明

 続いてはlet句の説明です。let句は、次のように記述されます。for句とそっくりです。

let [変数名] := [Path表現式] , [変数名] := [Path表現式] …

 let句は変数をバインドします。let句ではシーケンスを丸ごと変数にバインドします。for句が存在する場合は、for句で作成されたタプルにその変数を追加します。for句が存在しない場合は1つのタプルを作成するだけです。最初の例ではprojectにproject/name/text()を追加し、次のようにプロジェクト要素とプロジェクト名のタプルを作成します。

最初の例によって作成される3つのタプル
($p,$pn) = {
( <project code="200200020" …> …</project>,
  XMLによる文書管理システム ),
( <project code="200200025" …> …</project>,
  XMLによるB2Bシステム構築 ),
( <project code="200200031" …> …</project>,
  モバイルシステムの構築 )
}

 for句とlet句の違いは直積を取るかどうかです(let句は直積を取りません)。そのため、上記構文を次のように書き換えたとしても、タプル数は3となります。

for $p in document("data\projects.xml")//project
let $mn := document("data\projects.xml")//member/name

上記の例によって作成される3つのタプル
($p,$mn) = {
( <project code="200200020" ... > ...</project> ,
( <name>川泉陽一</name>
  <name>中田聡</name>
  <name>本岡欣也</name>
  <name>川泉陽一</name>
  <name>川泉陽一</name> ) ,
( <project code="200200025" ... > ...</project> ,
( <name>川泉陽一</name>
  <name>中田聡</name>
  <name>本岡欣也</name>
  <name>川泉陽一</name>
  <name>川泉陽一</name> ) ,
( <project code="200200031" ... > ...</project> ,
( <name>川泉陽一</name>
  <name>中田聡</name>
  <name>本岡欣也</name>
  <name>川泉陽一</name>
  <name>川泉陽一</name> )
}

  where句の説明

 続いてはwhere句の説明です。where句は次のように記述されます。

where [比較式]

 where句はfor句とlet句で作成されたタプルに対してフィルタをかけます。前述のPath表現式のフィルタは、オリジナルのXML文書にかけられたのに対して、このwhere句ではfor句およびlet句で作成されたタプルに対してフィルタをかけます。上の例では、for句、let句で作成されたタプルに対して、where句によってメンバーが2名以上のものだけが選ばれた結果「モバイルシステムの構築」が削除され、次のようになります。

最初の例によって作成される3つのタプル
($p,$pn) = {
( <project code="200200020" ...> ...</project> ,
   XMLによる文書管理システム ),
( <project code="200200025" ...> ...</project> ,
   XMLによるB2Bシステム構築 )
}

  return句の説明

 FLWR表現式の最後は、return句の説明です。return句は次のように記述されます。

return [コンストラクタ]

 return句は結果の作成をします。return句はfor句とlet句で作成された1タプルに対して1回呼び出されます。上の例では、次のように2つのprojectノードを加工して、XML文書にします。

最初の例のreturn句で生成されるXML文書
<?xml version="1.0" encoding="UTF8" ?>
<xql:result xmlns:xql="http://metalab.unc.edu/xql/">
  <project>
    <title>XMLによる文書管理システム</title>
    <count>2</count>
    <member>
      <name>川泉陽一</name>
      <name>中田聡</name>
    </member>
  </project>
  <project>
    <title>XMLによるB2Bシステム構築</title>
    <count>2</count>
    <member>
      <name>本岡欣也</name>
      <name>川泉陽一</name>
    </member>
  </project>
</xql:result>

3/6

Index
注目のXML問合せ言語「XQuery」
  XML問い合わせ言語とデータモデル
・問い合せ言語の役割
・XML問い合わせ言語が求められる理由
・XML問い合わせ言語とデータモデル
・XMLの基本データモデルはツリー構造
  XQuery以前に提案された問い合わせ言語
・XML-QL
・XQL
・XML問い合せ言語として必要な機能
・QuiltとXQuery
2つの表現式、PathとFLWR
・表現式はシーケンスで表される
・Path表現式
・FLWR表現式
  FLWR表現式の詳細
・XQueryを試せるアプリケーション
・for句とlet句の違いは繰り返し
・Path表現式とFLWR表現式の違い
コラム:複数のXML文書をXMLデータベースでどう扱うか?
  SQLとXQueryはどう違う?
・リレーショナルモデルの演算とは
・XQueryの演算
  XQueryにおけるリレーショナルの演算
・リレーショナルモデルの演算とは
・XQueryの演算
・トランスフォーメーション
・次の課題は更新系の命令


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間