SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

XQueryの制御構造の活用

XQueryの使い方の勘所

letコマンドの利用

 誰がどう考えても、このような複雑な式を繰り返し入力するのは面倒です。幸い、letコマンドを使用して、このシーケンスを保持する一時変数を作成することができます。

let $sorted-seq := for $employee in doc("employees.xml")/employees/employee 
    order by $employee/lastname ascending 
    return $employee

 この文は少々わかりにくいかもしれません。一般のプログラミング言語と同じ感覚で、letでは単一のスカラー値しか保持できないと考えてしまうと、この文の意味がすぐにはわからないでしょう。しかし、let文ではスカラー値だけでなくシーケンスも(さらに高度なデータ構造も)保持できるということを知れば、この式の意味合いがよくわかるはずです。また、作成されたシーケンスはXML構造内の特定の要素をポイントしているので、この並べ替えられたシーケンスは実体的にはポインタのシーケンスに過ぎず、(普通は巨大となる)XML構造そのものではありません。

 これにより、段階的なフィルタリング機構を驚くほど低コストで手際よく作成することができます。たとえば、従業員を姓でソートし、そのソート済みリストのレコード11から20までを出力するような式を作成するものとします。次のコードは、その1つの方法を示しています。

let $employees :=  doc("employees.xml")/employees/employee
let $sorted-employees := for $employee in $employees 
    order by $employee/lastname ascending 
    return $employee
let $paged-employees := subsequence($sorted-employees,10,10)
return $paged-employees

 この例の各let代入文では、実際にはノードのシーケンスが処理されています。具体的には、「employees.xml」ドキュメント内のノードの初期集合、同じコンテンツのソート済みシーケンス、そしてソート済み従業員リストから取り出したサブシーケンスです。いずれのケースについても、ここでは要素のポインタだけが抽出されます。このパラダイムは効率的なクエリを作成するのに非常に有効です。XMLデータの大きなブロックを移動したりXMLデータベースの配置を変更したりしないで、ポインタのリストを操作するだけで済むため、操作が桁違いに高速化されるからです。

 ただし、このやり方には1つ注意すべき点があります。このポインタ操作が成立するためには素の結果(たとえば$employee)が返されることが前提になることです。結果を変更するようなものがあれば、それは結局新しい情報ノードとなり、たとえ無意味な変更であってもXQueryエンジンはそれらのノードを効率的に逆参照する必要があります。

 上記のコードはまったく同じ結果を返しますが([]で括られた結果は、XQueryの式を評価して、ストリーム内で結果を置き換えることを意味する)、1つ目のreturn文で新しいコンテンツが作成されるため、かなりコストがかかり、ずっと低速の操作になります。

 一般に、データセットをできるだけ小さなシーケンスに絞り込むまでは、新しいコンテンツを作成するのを控えるべきです。実際、かなり大きくなる可能性のあるデータセットに対してクエリを実行するときは、検索結果のフィルタリングと表示のために案外普通の操作パターンが使われるものです。

  1. リソースの初期コレクションを取得し、それを作業変数に格納する。
  2. このコレクションの項目をフィルタリングして、関係する項目だけを取り出す。
  3. フィルタリングしたデータセットをソートする
  4. ソート済みのフィルタリングされたデータセットをページ単位で処理して加工可能なサブセットを取り出す。
  5. ページ単位のコンテンツを出力要件に応じて変換する。
  6. 変換されたコンテンツを出力する。

 データの取得は複数の場面で起こります。doc()関数は、絶対URLか相対URLを引数に取り、URLのコンテンツをXMLドキュメントとして解析しようとします。一方、collection()関数は、外部ソースからノードのコレクションを取得します。そのコレクションに親要素が存在する必要はありません。この違いはXMLファイルを取得するときはあまり意味を持ちませんが、多くのXMLデータベースは(単一の要素ではなく、コレクションに対応するURIを用いて)コレクションの概念に基づきセットアップされているので、collection()要素はXMLデータベース内から呼び出すときに特に役立ちます。

 eXistデータベースに個々の従業員のコレクションも作成できます(具体的な手順については、ここでは述べません)。そして作成したコレクションを特定のパス(通常はdb/employeesなどの形式)に割り当て、このコレクション内のすべての項目を次のようにして参照できます。

let $employees :=  collection("/db/employees")

 XQuery for Java(xqj)表記では次のようになります。

let $employees :=  collection("xmldb:exist:///db/employees")

 ここで、xmldb:exist:///は、使用プロトコルがxmldb:で、参照先サーバーがeXistであることを示しています。また、3重のスラッシュ(///)はプロトコルの完全パスの略記法であり、通常は次のような形式になります。

let $employees :=  collection("xmldb:exist://localhost:8080/db/employees")

 内部的には、取得されたコレクションは少なくともクエリに関する限り、シーケンスとして扱われます(本稿の範囲を超えますが、アップデートでは区別されます)。つまり、コレクションの結果に対してクエリを実行するときも、ドキュメントから取り出したXPathシーケンスの結果に対してクエリを実行するときも、コンテンツを同じ方法で操作することになります。

次のページ
フィルタリング

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Kurt Cagle(Kurt Cagle)

ライター、情報アーキテクト、XML News NetworkとMetaphorical Webのウェブマスター。カナダ、ブリティッシュコロンビア州のビクトリア在住。XMLToday.orgの編集長、O'Reilly Mediaの寄稿編集者。現在、XBRLに関する著書を執筆中。彼のTwitterはtw...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3011 2008/09/18 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー