XQLチュートリアル(日本語チョー訳)

by Hippo2000(1999/8/18)

XQLのチュートリアルなのです。基本はXML::XQLモジュールの説明なのですが、XQLの使い方もわかる(かも?)

なおこのドキュメントではXML::XQLモジュールで配布されるtutorial.podにpod2htmlを実行して作成されたファイルをベースにして、編集をくわえて日本語に訳そうとしたものです。わかりにくい部分は本物を見てください。(^^;

原本の著作権はEnno Derksen 氏がお持ちです(詳しくは作者の部分を見てください)。
Enno Derksenさんにはメールで了解をいただきました。

なお内容等が間違っていたら修正します。ご連絡ください。


目次


名前

XQL Tutorial - XQL問い合わせの文法についての説明


説明

このドキュメントはXML問い合わせ言語(XQL)の基本的な機能について説明します。XML問い合わせ言語(XQL)の仕様のためのプロポーザルは1998年9月にXSLワーキンググループに提出されています。その仕様は以下のアドレスで見ることが出来ます: http://www.w3.org/TandS/QL/QL98/pp/xql.html。 現時点では単なるプロポーザルであるために、変更になる可能性はあります。しかし最終版はプロポーザルにかなり近いものになるものと思われます。このドキュメントの大半は仕様からそのままコピーしています。

XML::XQL マニュアルページもご覧下さい。


はじめに

XQL (XML 問い合わせ言語)はXSLパターン言語に自然な拡張を提供します。XSLがノードのクラス識別のために提供した能力に、ブール値のロジック、フィルタ、ノードのコレクションのインデックス化などを加えることによって構築されています。

XQL は特にXML文書のために設計されています。問い合わせ、アドレッシング、パターンに使うことが出来る1つの文法を提供することは問い合わせ言語の一般的な目的です。XQLは簡潔で、簡単で、そして強力です。

XQLは多くのコンテクストで使われるように設計されています。XSLパターンのスーパーセットではありますが、リポジトリを検索したり、他のアプリケーションのために、ノードへのリンクを提供することにも適しています。

XQLという言葉はこのプロポーザルで記述されている言語のために動く言葉であるとに注意してください。この言葉が永遠に使われることを意図していません。同時に、他の問い合わせ言語XML-QLというSQLに非常によく似た文法を使うものもあることに注意してください。

XML::XQLモジュールはXQL仕様にXQL+という機能を加えています。 仕様で記述されているXQLの機能だけを許可するためにはXML::SQL::Strictモジュールをお使い下さい。XQL仕様はコアXQLとXQL拡張とを区別しています。この実装では区別していません、このためStrictモジュールではXQL仕様で記述されている全てを実装しています。Strictモジュールについてのさらに詳しい情報は、XML::XQLのマニュアルページをご覧下さい。このチュートリアルでは、XQL+を参照するときには明示します。


XQL パターン

このセクションではコアXQL記法について説明します。これらの機能は全てのXQL実装の一部となり、異なるテクノロジーで使われるための機能の基本的なレベルとして提供されなければなりません。

XQLの基本的な文法はURIディレクトリ・ナビゲーションの文法を真似ていますが、物理的なファイル構造を通したナビゲーションの代わりにXMLツリーでの要素を通したナビゲーションを指定します。

例えば、以下のURIはbarディレクトリにあるfoo.jpgを見つけることを意味します:

     bar/foo.jpg

同様に、XQLでは以下の文は要素bazのなかの要素fuzのコレクションを見つけることを意味します:

     baz/fuz

このドキュメントを通して、たくさんのサンプルがあります。それらはこのマニュアルページの最後にあるサンプル・ファイルで表されるデータを参照しています。


コンテキスト

コンテキスト(context)は問い合わせ演算の対象となるノードの集合体です。Exprオプションを通してXML::XQL::Queryコンストラクタに渡される、完全な問い合わせにとっては、コンテキストはquery()メソッドに渡される入力ノードのリストです。

XQL は入力コンテキトとして、現在のコンテキストを使うのか、「ルート・コンテキスト」を使うのかを選択することが出来ます。「ルート・コンテキスト」はドキュメントの最も根幹となる要素だけをもつコンテキストです。XML::DOMを使うときには、これはDocumentオブジェクトとなります。

デフォルトでは問い合わせは現在のコンテキストを使います。'/'(スラッシュ)が頭に付いた問い合わせはルート・コンテキストを使います。問い合わせはオプションで'./'(ドット、スラッシュ)を使うことによって現在のコンテキストを使うことを明示的に宣言することも出来ます。どちらの書き方もファイルシステムでのディレクトリをナビゲートするために使われる書き方に似ています。

'./'を頭に付けるのは、ある1つの状況でしか必要ありません。問い合わせは再帰的な子孫を示すために'//'演算子を使うことができます。この演算子が問い合わせの先頭にあると、最初の'/'によって、ドキュメントまたはリポジトリのルートの子孫に対して実行されるようになってしまいます。'.//'を前につけることで、現在のコンテキストの子孫に対して問い合わせが実行されます。

:
現在のコンテキストのなかの全ての要素authorを見つける。ピリオドが単独で使われているわけではないので、この例は他の機能の前方参照です:
     ./author

以下のものと同じであることに注意してください:

     author

このドキュメントのルート要素(bookstore)を見つける:

     /bookstore

現在のドキュメントのなかにある、位置に関係なく全てのauthor要素を見つける:

     //author

そのbookのstyle属性の値がドキュメントのルートにあるbookstore要素のspecialty属性の値と同じである全てのbookを見つける:

     book[/bookstore/@specialty = @style]

問い合わせ結果

XQL式により返されるコレクションは、ドキュメントでの順序、階層、アイデンティティを保ちます。そしてこれらの拡張が定義されています。つまり要素のコレクションは常にドキュメントでの順に繰り返しなしに返されます。

仕様では要素の中の属性の順序については不定であるとしていていますが、この実装では属性もドキュメントでの順序であることに注意してください。さらに詳しい情報についてはXML::XQLマニュアルページのドキュメントでの順序(Document Order)をご覧下さい。


コレクション - 要素名と'.'

あるタグ名である全ての要素のコレクションはタグ名そのものを使って表すことが出来ます。これについては、'./'で現在のコンテキストからそれらの要素を選択することを示すことによって修飾することができますが、現在のコンテキストが想定されており、明示的に示す必要はあまりありません。

例:
全てのfirst-name要素を見つけます。以下の例は同等です:
     ./first-name
     first-name

修飾されていない全てのbook要素:

     book

全てのfirst.name要素:

     first.name

子供と子孫 - '/' と '//'

あるタイプの要素のコレクションはパス演算子('/'や'//')を使うことで、指定すること出来ます。これらの演算子は、そこから要素を問い合わせるコレクション(左辺)と、選択する要素を示すコレクション(右辺)を引数として取ります。

子供演算子('/')は左辺のコレクションの直属の要素を選択し、子孫演算子('//')は左辺のコレクションの任意の子孫を選択します。実際において'//'演算子は階層の1つ以上のレベルを置き換えたものと考えることが出来ます。パス演算子は問い合わせが行われるコンテキストを変更することに注意してください。これらを一緒に指定することによってドキュメントを「ドリルダウン」することができるのです。

例:
author要素の中の全てのfirst-name 要素を見つけます。現在のコンテキストのauthorの子供が見つかること、first-nameはauthor要素のコンテキストに関連して見つかることに注意してください:

  author/first-name

bookstoreでの1つ以上のレベルが下(任意の子孫)の全てのtilte要素を見つけます:

     bookstore//title

これは上記の問い合わせとは違うことに注意してください。これはbookstore要素の孫である全てのtitle要素を見つけます:

     bookstore/*/title

bookstoreの中のどこかにあるbook,excerptの中のどこかにあるemph要素を見つけます:

     bookstore//book/excerpt//emph

現在のコンテキストでの1つ以上下のレベルにある全てのtitleを見つけます。基本的には、これがピリオドを書かなければならない唯一の状況です:

     .//title

要素の子供を集める - '*'

名前を使うことなく、'*'コレクションに置き換えることによって、要素を参照することが出来ます。'*'コレクションは、そのタグ名に関係なく、現在のコレクションの全ての子供を返します。

例:
author要素の子供要素を全て見つける:
     author/*

booksの孫である全てのlast-nameを見つける:

     book/*/last-name

現在のコンテキストの全ての孫要素を見つける:

     */*

specialty属性を持っている全ての要素を見つける。この例は副問い合わせを使っていることに注意。これはフィルターと属性でカバーされ、「属性を探す」で説明しています。

     *[@specialty]

属性を探す - '@'

属性名の前には記号'@'をつけます。XQLは属性とサブ要素を公平に扱うように設計され、2つの種類で機能は可能な限り同等です。

注意:属性はサブ要素を持てません。このため問い合わせの中で、属性にパス演算子を適用することはできません。そのような表現は文法エラーになります。XQL仕様は、属性は階層的に、順序はなく、インデックスは適用できないとしています。しかしこの実装ではそれを許しています。

例:
現在の要素コンテキストのstyle 属性を見つけます:
     @style

現在のコンテキストのなかの、price要素のexchange属性を見つけます:

     price/@exchange

以下の例は正しくありません:

     price/@exchange/total

style属性を持った全てのbookを見つけます。この例では副問い合わせを使っていることに注意してください。これは「フィルター」でカバーしています。

     book[@style]

全てのbook要素のstyle属性を見つけます:

     book/@style

XQLリテラル

XQL問い合わせ式にはリテラル値(つまり定数)を入れることができます。数値(=Number 整数、浮動小数点)はXML::XQL::Numberオブジェクトにラップされ、文字列はXML::XQL::Textオブジェクトにラップされます。ブール値 (true()false()として返される) はXML::XQL::Booleanオブジェクトにラップされます。

文字列はシングルまたはダブル・クォートで囲まれなければなりません。XQL は特殊文字をエスケープすることを許していないので、シングルとダブル・クォートの両方が入った文字列を作ることは不可能です。これに対応するため、XQL+はq//とqq//というPerlと同じように機能する文字列区切りを加えています。

数値(Numbers)に指数記法は許されていません。この問題を解決するためにはXQL+関数eval()をお使い下さい。詳細はXML::XQLのマニュアルページをご覧下さい。

この実装では、空リストまたは(つまり、空配列へのリファレンス)undefを[]で示します。

整数値:
     234
     -456

浮動小数点数値:

     1.23
     -0.99

文字列:

     "some text with 'single' quotes"
     'text with "double" quotes'

許されていないもの:

     1.23E-4         (XQL+で eval("1.23E-4", "Number") を使ってください)          
     "can't use \"double \"quotes"  (XQL+で q/can't use "double" quotes/ を使ってください) 

グループ化 - '()'

括弧はわかりやすくするため、または通常の優先順位が操作を表すのに適していないところで使われるグループ化演算子として使うことができます。


フィルター - '[]'

フィルターの括弧'[]'をそのコレクションにつけることによって、どんなコレクションにも制約と分岐を適用することが出来ます。フィルタは副問い合わせと呼ばれ、中に問い合わせが入っており、ANYがついたSQLでのWHERE節に似ています。

副問い合わせはブール値に評価され、検査されます。フィルターはコレクションのなかの要素を検査し、副問い合わせの検査に失敗すれば結果のコレクションからはずされます。

簡単にするために、もしコレクションがフィルターの中にあるとき、コレクションになにかメンバーがあればブール値TRUEが生成され、コレクションが空であればFALSEが生成されます。

実際にはauthor/degreeのような式は、以下のような架空の'there-exists-a'メソッドのような、コレクション−ブール値変換関数を適用します。

     author[.there-exists-a(degree)]

ある式の与えられたレベルにフィルターはいくつあってもかまいません。空のフィルターは許されません。

例:
少なくとも1つのexcerpt要素が入っているbookを見つける:
     book[excerpt]

少なくとも1つのexcerpt要素が入っているbookの全てのtitleを見つける:

     book[excerpt]/title

少なくとも1つのexcerpt要素が入っているbookの全てのauthorのうち少なくとも1つのdegreeを持っているauthorを見つける:

     book[excerpt]/author[degree]

少なくとも1つのdegreeを持っているauthorを持っている全てのbookを見つける:

     book[author/degree]

excerptとtitleを持っている全てのbookを見つける:

     book[excerpt][title]

Any と All の意味 - '$any$' と '$all$'

$any$と$all$キーワードを通じて、利用者はany(いずれか1つでも)もしくはall(全ての)のどちらの意味を使うかを明示的に示すことが出来ます。

$any$は集合体のうちのいずれかの要素が条件に合えば、その条件はtrueになることを示します。$all$ではその条件がtrueになるためには、集合体の全ての要素が条件に合わなければいけないということを意味します。

$any$ と $all$ はフィルターの中の副問い合わせの前に現れるキーワードです。

例:
last-nameの1つがBobである全てのauthor要素を見つける:
     author[last-name = 'Bob']
     author[$any$ last-name = 'Bob']

全てのlast-name要素がBobでない、全てのauthor要素を見つける:

     author[$all$ last-name != 'Bob']

最初のlast-nameがBobである、全てのauthor要素を見つける:

     author[last-name[0] = 'Bob']

コレクションにインデックスをつける- '[]' と '$to$'

XQLはノードの集合体での特定のノードを見つけることを簡単にします。簡単にインデックス番号をカギ括弧で囲みます。番号は0が基準です。

ある範囲の要素を返すことが出来ます。そうするためには、サブスクリプト演算子(カギ括弧)の内側に1つの値ではなく、式を指定します。そのような式は、以下のいずれかをカンマで区切ったものになります:

  n             n番目の要素を返す
  -n            最後の要素からn-1番目の要素を返す
                つまり、-1は最後の要素。-2は最後の次の要素。
  m $to$ n      mからn番目の要素。両端は含まれます。
例:
author要素の先頭 :
     author[0]

first-nameを持っている3番目のauthor要素:

     author[first-name][2]

インデックスは親からの相対であることに注意して下さい。言い換えれば、以下のデータを考えてみて下さい:

     <x>
       <y/>
       <y/>
     </x>
     <x>
       <y/>
       <y/>
     </x>

以下の式はそれぞれのxの最初のyを返します:

     x/y[0]

以下は、全てのxでのyの中からの最初のyを返します:

     (x/y)[0]

以下は、最初のxでの最初のyを返します:

     x[0]/y[0]
 
最初と4番目のauthor要素を見つけます:
     author[0,3]

最初から4番目までのauthor要素を見つけます:

     author[0 $to$ 3]

最初、3番目から5番目、そして最後のauthor要素を見つけます:

     author[0, 2 $to$ 4, -1]

最後のauthor要素を見つけます:

     author[-1]

論理式

論理式は副問い合わせの中で使うことが出来ます。例えば論理式を使って、特定の値のノードの全てを見つけたり、ある範囲のノードを持っている全てのノードを見つけたりすること出来ます。

論理式は${op}$という形式をとります。「{op}」のところには{b|a}という形の式がはいるかもしれません。つまり演算子は左辺値と右辺値を引数に取り、ブール値を返します。

XQL拡張のセクションで追加の論理演算子が定義されていることに注意してください。


論理 AND と OR - '$and$' と '$or$'

$and$ と $or$ はブール値のandとorとして機能します。

論理演算子はグループ化の括弧と組み合わせることで、非常に洗練された論理式を構築することが出来ます。

空白は重要ではなく、省略することができ、もしくは以下に示すように分かりやすくするためにいれることができることに注意して下さい。

例:
少なくとも1つのdegreeとawardを持っている全てのauthor要素を見つけます:
     author[degree $and$ award]

少なくとも1つのdegreeまたはawardを持ち、少なくとも1つのpublicationを持つ全てのauthor要素を探します:

     author[(degree $or$ award) $and$ publication]

論理 NOT - '$not$'

$not$ は、副問い合わせの中の式の値を否定する論理演算子です。

例:
少なくとも1つのdegree要素を持ち、publication要素を全く持たない全てのauthor要素を見つけます:
     author[degree $and$ $not$ publication]

publication要素は持っているが、degree要素やaward要素を持たない全てのauthor要素を見つけます:

     author[$not$ (degree $or$ award) $and$ publication]

結合と交差 - '$union$', '|' そして'$intersect$'

$union$ 演算子(ショートカットは'|')は左辺と右辺の問い合わせからの値の集合体を結合させて返します。重複するものは除かれます。結果のリストはドキュメントでの順序にソートされます。

注意:結合(union)であるので、返される集合体には0もしくは、それ以上のリストの中でのそれぞれの要素タイプの要素を含みます。返される集合体にリストの中に少なくとも1つの要素が入っているように制限するためには、フィルターの節で説明しているフィルターを使って下さい。

$intersect$ 演算子は、2つの集合体に共通の要素の集合体を返します。

例:
すべてのfirst-name と last-nameを見つけます:
     first-name $union$ last-name

bookstoreから、すべてのbookとmagazineを見つけます:

     bookstore/(book | magazine)

すべてのbookとすべてのauthorを見つけます:

     book $union$ book/author

bookまたはmagazineのなかのauthorからfirst-name、 last-name、degreeを見つけます:

     (book $union$ magazine)/author/(first-name $union$ last-name $union$ degree)

author/first-nameがBobであるすべてのbookとpriceが10未満であるすべてのmagazineを見つけます:

     book[author/first-name = 'Bob'] $union$ magazine[price $lt$ 10]

等号 - '$eq$', '=', '$ne$' そして '!='

記号'='は等号のために使われます。 '!=' は等号の否定です。代わりに $eq$ と $ne$を等号と等号の否定に使うことが出来ます。

シングルまたはダブル・クォートを式の中での文字列区切りとして使うことが出来ます。これによって、スクリプト言語のなかからXMLを構築し、渡すことがより簡単に出来るようになります。

要素を比較する値のために、value()メソッドが適用されます。つまり、last-name < 'foo' は本当はlast-name!value() < 'foo'ということを意味します。

フィルターは常にコンテキストを考慮していることに注意して下さい。つまりbook[author]という式は、authorという子供の要素を持っている見つかったすべてのbook要素を意味します。さらにbook[author='Bob']は、その値が'Bob'であるauthorという子供の要素を持っている見つかったすべてのbook要素を意味します。.(ピリオド)を使うことによって、コンテキストの値も検証することが出来ます。たとえばbook[. = Trenton'] はその値が'Trenton'であるすべてのbookを意味します。

例:
last-nameがBobである全てのauthor要素を見つけます:
     author[last-name = 'Bob']
     author[last-name $eq$ 'Bob']

from属性がHarvardではない、全てのauthorを見つけます:

     degree[@from != 'Harvard']
     degree[@from $ne$ 'Harvard']

last-nameが/guest/last-name要素と同じである全てのauthorを見つけます:

     author[last-name = /guest/last-name]

テキストが'Mattherw Bob'である全てのauthorを見つけます:

     author[. = 'Matthew Bob']
     author = 'Matthew Bob'

比較- '<', '<=', '>', '>=', '$lt', '$ilt$' 等

数値や文字列を比較し、ブール値の結果を返すために、いくつかのバイナリ比較演算子を使うことが出来ます。$lt$, $le$, $gt$, $ge$は未満、以下、より大きい、以上に使われます。大文字/小文字を無視したこれらと同じ演算子があります:$ieq$, $ine$, $ilt$, $ile$, $igt$, $ige$。

<, <=, > そして >= は、ショートカットとして $lt$, $le$, $gt$ そして $ge$ を許しています。

例:
last-nameがBobでpriceが>50である全てのauthor要素を見つける:
     author[last-name = 'Bob' $and$ price $gt$ 50]

from属性が'Harvard'でない全てのauthorを見つける:

     degree[@from != 'Harvard']

last-nameがMまたはそれ以上の文字で始まる全てのauthorを見つける:

     author[last-name $ge$ 'M']

last-nameが'M'、'm'またはそれ以上の文字で始まる全てのauthorを見つける:

     author[last-name $ige$ 'M']

最初の3つのbookを見つける:

     book[index() $le$ 2]

10個以上のpublicationを持っている全てのauthorを見つける:

     author[publications!count() $gt$ 10]

XQL+ マッチ演算子 - '$match$', '$no_match$', '=~' そして '!~'

XQL+ はパターン・マッチのための追加の演算子を定義しています。$match$ 演算子(ショートカットは'=~')は、右辺値で記述されているパターンに左辺値がマッチしていればTRUEを返します。 $no_match$ 演算子(ショートカットは'!~')はマッチすればFALSEを返します。右辺値、左辺値ともに文字列(string)にキャストされます。

右辺値の文字列はPerlでの右辺値の文法に従わなくてはいけません。つまり区切り文字は含まれ、修飾子は許されものでなければなりません。スラッシュ(/)以外の区切り文字を使うときには、'm'を付けなければなりません。右辺値は文字でなければならず、そのためクォートを忘れてはいけません!(そうなければXQL+でのq//またはqq//区切り文字を使って下さい。XML::XQLマニュアルページをご覧下さい)

ここではPerlの置換演算子 s///は使うことが出来ないことに注意して下さい。代わりにXQL+のsubst()関数を使ってみてください。

例:
first-nameがbobまたはBobである全てのauthorを見つける:
    author[first-name =~ '/[Bb]ob/']

titleに(大文字、小文字を無視して)'Trenton'が入っていない全てのbookを見つける:

    book[title !~ 'm!trenton!i']

他の XQL+ 比較演算子 - '$isa', '$can$'

XQL+で利用できる他の演算子については、XML::XQLマニュアルページをご覧下さい。


比較とベクトル

比較の左辺値にはベクトルとスカラーが指定できます。比較の右辺値はスカラーまたは実行時にスカラーにキャストできる値でなければなりません。

比較の左辺値が集合体であった場合、比較の演算子はany(いずれかが)という意味で使われます。つまり、その集合体のいずれかの要素が条件にあえばtrueになります。


比較とリテラル

仕様では式の左辺にはリテラルを許してはいません。つまり '1' = a は許されていません。この実装ではこれを許していますが、これがどれくらい便利なのかよくわかりません。


比較時のリテラルのキャスト

要素(Element)、属性(attribute)そしてその他のXMLノードタイプは、value()メソッドを適用されることによってテキスト(Text)にキャストされます。value()メソッドはデフォルトではtext()メソッドを呼びます。しかしこの動きはユーザによって変更することが出来ます。value()メソッドは他のXQLデータ型で返すかもしれません。

2つの値を比較するとき、まず最初に同じ型にキャストされます。キャストでの詳細はXML::XQLマニュアルページをご覧下さい。

XQL仕様は、比較時のための値がどのようにキャストされるべきなのかについてあまりはっきりしていません。XQL仕様の執筆者たちとの議論したところ、いくつかの点で合意せず、この点で彼らの実装は食い違っています。この実装はwebMethods社からのJoe Lapp氏のものに一番近くなっています。


メソッド - 'method()' または 'query!method()'

XQLは関数(function)とメソッド(method)を区別しています。詳細についてはXML::XQLマニュアルページをご覧下さい。

XQLはコレクションを取り扱う進んだメソッドを提供しています。 これらのメソッドは、集合体とノードについての情報と同様に、特定のノードのコレクションに提供されています。(コレクションメソッドをご覧下さい)

メソッドはmethod(arglist) という形式を取ります。

問い合わせbook[author]について考えてみて下さい。これはauthorを持っている全てのbookを見つけます。形式的には、特定のauthorに関連するbookを、そのauthorのための参照ノードを呼びます。つまり検査されるそれぞれのauthor要素は、book要素のものです。(参照ノードや他の用語の定義についてのより詳細については、付属のXQL BNF Appendixをご覧下さい。XML::XQLマニュアルページもご覧下さい)。メソッドは参照ノードに適用されます。

たとえば、text()メソッドはノードに入っているテキストを構造をはずして返します。(つまり要素その子孫に入っている全てのテキストノードをつなげたものになります)。以下の式は'Bob'という名前のすべてのauthorを返します:

     author[text() = 'Bob']

以下は、テキストが'Bob'であるfirst-nameを持っているすべてのauthorを返します:

     author[first-name!text() = 'Bob']

以下は'Bob'と名付けられた子供をもつ、すべてauthorを返します:

     author[*!text() = 'Bob']

メソッド名は大文字・小文字が区別されます。独自のメソッド、関数を定義する方法についてはXML::XQLマニュアルページをご覧下さい。


情報メソッド

以下のメソッドがコレクションのなかのノードについての情報を提供します。これらのメソッドは文字列または数値を返し、副問い合わせでの比較演算子と一緒に使うことも出来ます。

メソッド: text()
text() メソッドは空白を正規化(normalize)しながら、ノードの子孫のテキストを結合させます。ノードが'preserve'に設定されているxml:space属性を持っているか、最も近い先祖が'preserve'に設定されているxml:space属性を持っていれば、空白は保存されます。空白が正規化されるとき、文字列全体が正規化されます。空白はノードの間でテキストを分けます。エンティティ・リファレンスがドキュメントで使われていると、それが展開されたとき、エンティティ・リファレンスの周りに空白は入りません。

この実装では、メソッドは要素ノードのtext()にその要素の子孫のtext()を含むかどうかを示すオプションのパラメータを受け取ることが出来ます。詳細についてはXML::XQLマニュアルページをご覧下さい。

例:

last-nameが'Bob'であるauthorを見つけます:

     author[last-name!text() = 'Bob']

これは以下のものと同じです:

     author[last-name = 'Bob']

'Matthew Bob'という値をもったauthorを見つけます:

     author[text() = 'Matthew Bob']
     author[. = 'Matthew Bob']
     author = 'Matthew Bob'
メソッド: rawText()
rawText()メソッドはtext()メソッドに似ていますが、空白を正規化しません。

この実装では、メソッドは要素ノードのrawText()にその要素の子孫のrawText()を含むかどうかを示すオプションのパラメータを受け取ることが出来ます。詳細についてはXML::XQLマニュアルページをご覧下さい。

 
メソッド: value()
ノードの値の型キャストされたものを返します。データ型が与えられなければ、text()と同じものを返します。
ショートカット
比較のときには、もし省略されたらvalue()が適用されます。言い換えれば、2つの要素が比較されるとは、2つの要素の値の間の比較です。型情報がないとき、value()はtext()を返すことを忘れないで下さい。

以下の例は同じです:

     author[last-name!value() = 'Bob' $and$ first-name!value() = 'Joe']
     author[last-name = 'Bob' $and$ first-name = 'Joe']
     price[@intl!value() = 'canada']
     price[@intl = 'canada']
メソッド: nodeType()
ノードの型を示す数値を返します。DOMでのノード型の値を基本としています:
        element         1
        attribute       2
        text            3
        entity          6       (XQL仕様にはありません)
        PI              7
        comment         8
        document        9
        doc. fragment   10      (XQL仕様にはありません)
        notation        11      (XQL仕様にはありません)

DOMではCDATASectionノードは4、EntityReferenceノードは5を返すのに、XQLでは、CDATASectionノードとEntityReferenceノードのどちらも3を返すことに注意して下さい。DOMでのノード型の値を取得するには、XQL+のDOM_nodeType()メソッドをお使いください。ノードの型についてはXML::DOMマニュアルページをご覧下さい。ここでは触れません。

 
メソッド: nodeTypeString
小文字または空の文字列でノード型の名前を返します。現在以下のノードをサポートしています。1 (element), 2 (attribute), 3 (text), 7 (processing_instruction), 8 (comment), 9 (document)
メソッド: nodeName()
要素(Element)ノードはタグ名を、属性(attribute)ノードでは属性名を返します。
 

コレクション・インデックスメソッド

メソッド: index()
検索コンテキストでの値の(つまり副問い合わせの入力リストでの)インデックスを返します。これは必ずしもその親でのノードのインデックスと同じではありません。XQL仕様はこれについてうまく説明していないことに注意して下さい。
 
例:
最初の3つのdegreeを見つけます:
     degree[index() $lt$ 3]

degree要素の間に存在するかもしれない他のノードはとばされることに注意してください。

以下のようなデータを考えてみて下さい:

     <x>
       <y/>
       <y/>
     </x>
     <x>
       <y/>
       <y/>
     </x>

以下の式は各xの最初のyを返します:

     x/y[index() = 0]

これは以下のようにしても達成できます(コレクションにインデックスをつけるをご覧下さい):

     x/y[0]
メソッド: end()
end()メソッドは検索コンテキストで最後の要素であればtrueを返します。再び、XQL仕様はこれについてうまく説明していません。
 
例:
最後のbookを見つける:
     book[end()]

各bookの最後のauthorを見つける:

     book/author[end()]

bookのauthorの集合全体から最後のauthorを見つける:

     (book/author)[end()]

集合メソッド

メソッド: count( [QUERY] )
検索コンテキストのなかにある値の数。XQL+では、オプションのQUERYパラメータを指定することができます。それはQUERYによって返される値の数を返します。

名前空間メソッド

以下のメソッドが名前空間情報を返すためにノードへ適用できます。

メソッド: baseName()
ノードの接頭辞を除いて、ローカル名部分を返します。ローカル名は要素(element)ノードと属性(attribute)ノードにだけ定義されます。要素(element)ノードのローカル名はノードの要素型名のローカル部分です。属性ノードのローカル名はノードの属性名のローカル部分です。もしローカル名がその参照ノードに定義されていなければ、メソッドは空セットに評価します。
 
メソッド: namespace()
ノードの名前空間のためのURIを返します。名前空間URIは要素ノードと属性ノードにだけ定義されます。要素ノードの名前空間URIはノードの要素型名に関連づけられた名前空間URIです。属性ノードの名前空間URIはノードの属性名に関連づけられた名前空間URIです。もし名前空間URIがその参照ノードに定義されていなければ、メソッドは空セットに評価します。
 
メソッド: prefix()
ノードの接頭辞を返します。名前空間接頭辞は要素ノードと属性ノードにだけ定義されます。要素ノードの名前空間接頭辞はノードの要素型名の名前空間を短くした名前です。属性ノードの名前空間接頭辞はノードの属性名の名前空間を短くした名前です。もし名前空間接頭辞がその参照ノードに定義されていなければ、メソッドは空セットに評価します。

仕様では以下のように言っています:ノードの名前空間接頭辞は問い合わせ式の中で、問い合わせ対象のドキュメントの中で、あるいは問い合わせ式と問い合わせ対象のドキュメントの中の両方で定義することが出来ます。もし両方の場所で定義されたならば、その接頭辞は合わないかもしれません。この場合、問い合わせ式で与えられた接頭辞が優先されます。

この実装では問い合わせのために名前空間を定義することは出来ません。したがってこれが起きることはありません。

 
例:
何も修飾されていないすべてのbook要素を見つけます。これはmy:book要素を返さないことに注意して下さい:
     book

接頭辞myがついたすべてのbook要素を見つけます。この問い合わせは修飾されていないbook要素は返しません:

     my:book

authorをサブ要素に持った接頭辞myがついたすべてのbook要素を見つけます:

     my:book[author]

接頭辞myがついたauthorをサブ要素に持った接頭辞myがついたすべてのbook要素

     my:book[my:author]

接頭辞myがついたすべての要素を見つける:

     my:*

すべての名前空間のすべてのbook要素を見つける:

     *:book

すべての名前空間からすべての要素を見つける:

     *

book要素の中にある接頭辞myがついているstyle属性を見つけます:

     book/@my:style

ある要素のすべての属性は@*を使うことによって返されます。これは属性をレコードの中のフィールドとして扱うアプリケーションにとっては、潜在的に便利です。

 
例:
現在の要素コンテキストのすべての属性を見つける:
     @*

すべての名前空間のstyle属性を見つける:

     @*:style

名前空間myからの要素にある修飾されていない属性も含めて、名前空間myからすべての属性を見つける。

     @my:*

関数

このセクションはXQLの関数について定義します。仕様では以下のように言っています:XQLは2種類の関数を定義します。コレクション関数は実施インスタンスの検索コンテキストを使いますが、純粋関数は関数のパラメータを評価するときを除いて、検索コンテキストを無視します。コレクション関数は検索コンテキストの一部に評価しますが、純粋関数は定数値あるいは関数のパラメータにだけ依存する値のどちらかに評価します。

分からなくても気にしない!使ってみて下さい!


コレクション関数

コレクション関数はドキュメントのなかのノードのさまざまな型へのアクセスを提供します。これらコレクションはいずれも制約を付けたりインデックスを付けたりすることが出来ます。コレクションは特定の制約に合う参照ノードの子供の集合体を返します。

関数: textNode()
テキストノードのコレクション
関数: comment()
コメントノードのコレクション
関数: pi()
処理命令(processing instruction)ノードのコレクション
関数: element( [NAME] )
すべての要素(element)ノードのコレクション。オプションの文字列パラメータが指定されると、指定された名前にマッチする子供要素だけが返されます。
関数: attribute( [NAME] )
すべての属性(attribute)ノードのコレクション。もしオプションの文字列のパラメータが指定されると、特定の名前にマッチする属性だけが返されます。
関数: node()
すべての属性でない(non-attribute)ノードのコレクション。
例:
現在のコンテキストでの各p要素の2番目のテキストノード:
     p/textNode()[1]

ドキュエメントのどこかにある2番目のコメント。ドキュメント・ルートへのコンテキストの設定についての詳細についてはコンテキストをご覧下さい:

     //comment()[1]

他のXQL関数

関数: ancestor(QUERY)
与えられた問い合わせにマッチするもっとも近い先祖(ancester)を捜します。1つの要素か空集合[]のどちらかを返します。このノードはそのノード自身へのリファレンスではないことに注意して下さい。
 
例:
現在の要素にbookの一番近い先祖を見つけます:
     ancestor(book)

book要素に含まれている、一番近いauthorの先祖を見つけます:

     ancestor(book/author)
関数: id(NAME)
集合体に評価する純粋関数。集合体は、その値がテキストパラメータがクォートする文字列と同じである'id'属性をもった要素ノードが入ります。要素ノードは問い合わせの対象となっているドキュメントのどこにあってもかまいません。もし1つ以上のノードがこの条件に合えば、関数はドキュメントでのノードの出現順での最初のノードが入った集合体に評価します。
関数: true() と false()
ブール値に変換する純粋関数。"true()"はtrueに、"false()"はfalseに評価します。副問い合わせのインスタンスで必要とされる文法の 副問い合わせのインスタンスで見つかった式を置き換えるかもしれないので、
これらの関数は、エンティティへのリファレンスまたは変数置き換えを使う式を構築するときに便利です。XML::XQL::Boolean型のオブジェクトを返します。
 
関数: date(QUERY)
"date"は、そのパラメータを日付の集合体に型キャストする純粋関数です。もしパラメータが1つの文字列にマッチすれば、関数の値は1つの日付をもつ集合体になります。もしパラメータがQUERYにマッチすれば、この関数の値は、パラメータが評価された集合体の各メンバーの日付の値が入った日付の集合体になります。

XQLは日付の値の形式を定義していませんし、また関数がパラメータをどのようにして日付に変換するかも定義していません。この実装では日付を解釈するためにDate::Manipモジュールを使っています。これは想像しうるほとんどの形式を受け付けます。独自の日付実装を組み込むことについてはXML::XQLマニュアルページをご覧下さい。

Perl 組み込み関数と他のXQL+関数
XQL+ は大抵のPerl組み込み関数のためのXQL関数ラッパーを提供しています。他にもsubst(),map(),evalといったスバらしい関数も提供しています。これでドキュメントを変更したり、Perlのコードを埋め込むことが出来ます。もしこれで充分でなければ、独自の関数とメソッドを加えることもできます。詳細はXML::XQLマニュアルページをご覧下さい。

順序演算子 - ';' と ';;'

ホワイトペーパー 'The Design of XQL' by Jonathan Robie,はhttp://www.texcel.no/whitepapers/xql-design.html にあり、順序演算子 ';;' (precedes:先行) と ';' (immediately precedes:直前)について記述しています。これらの演算子はXQL仕様には入っていませんが、なんとかこれらを入れなくてはと思いました。


直前(Immediately Precedes) - ';'

:
以下のような入力があったとします:
 <TABLE>
  <ROWS>
   <TR>
    <TD>Shady Grove</TD>
    <TD>Aeolian</TD>
   </TR>
   <TR>
    <TD>Over the River, Charlie</TD>
    <TD>Dorian</TD>
   </TR>
  </ROWS>
 </TABLE>

"Shady Grove'' が入ったTDノードとそのすぐ後に続くTDノードは以下のようになります:

        //(TD="Shady Grove" ; TD)

XML::DOMでは、実際には2つのTDノードの間に空白のtextノードがあります。しかしtextノードがxml:spaceをpreserveにしていなければ、この演算子ではそれは無視されます。詳しくは???をご覧下さい。


先行(Precedes) - ';;'

例:
以下のような入力があったとします(ハムレットより):
 <SPEECH>
  <SPEAKER>MARCELLUS</SPEAKER>
  <LINE>Tis gone!</LINE>
  <STAGEDIR>Exit Ghost</STAGEDIR>
  <LINE>We do it wrong, being so majestical,</LINE>
  <LINE>To offer it the show of violence;</LINE>
  <LINE>For it is, as the air, invulnerable,</LINE>
  <LINE>And our vain blows malicious mockery.</LINE>
 </SPEECH>

以下はSTAGEDIRとそれに続く全てのLINEを返します:

        SPEECH//( STAGEDIR ;; LINE )

幽霊(Ghost)を演じている俳優がいつ出ていけばよいかを知りたがっているとします。つまり彼は彼が出ていこうとする直前に誰がどの行を言うかを知りたいとします。STAGEDIRの直前の行では、SPEAKERはその行の前から始まっているかもしれません。この問い合わせでは、先行演算子(;;)をSPEECHでのどこかのLINEの前にあるSPEAKERを識別するために使っています。幽霊は必要とする情報を以下の問い合わせで見つけることが出来ます。それはSPEAKERとLINEそしてSTAGEDIRを選択します。

        SPEECH//( SPEAKER ;; LINE ; STAGEDIR="Exit Ghost")

演算子の優先順位

以下の表に演算子を優先順に、最も高い優先順のものを先頭に、同じ優先順をもつ演算子を同じ行にして一覧で示します。この表では関連する演算の効果も載せています。

         効果         演算子
        ----------      -----------
        グループ化     ( )
        フィルター     [ ]
        副問い合わせ    [ ]
        メソッド      !
        パス        / //
        マッチ       $match$ $no_match$ =~ !~ (XQL+ only)
        比較        = != < <= > >= $eq$ $ne$ $lt$ $le$ $gt$
                  $ge$ $ieq$ $ine$ $ilt$ $ile$ $igt$ $ige$
        交差        $intersect$
        結合        $union$ |
        否定        $not$
        論理積       $and$
        論理和       $or$
        順序        ; ;;

XMLドキュメントのサンプル - bookstore.xml

このファイルはXML::XQLの配布といっしょにsamples/bookstore.xmlにも入ります。

 <?xml version='1.0'?>
 <!-- This file represents a fragment of a book store inventory database -->
 <bookstore specialty='novel'>
   <book style='autobiography'>
     <title>Seven Years in Trenton</title>
     <author>
       <first-name>Joe</first-name>
       <last-name>Bob</last-name>
       <award>Trenton Literary Review Honorable Mention</award>
     </author>
     <price>12</price>
   </book>
   <book style='textbook'>
     <title>History of Trenton</title>
     <author>
       <first-name>Mary</first-name>
       <last-name>Bob</last-name>
       <publication>
         Selected Short Stories of
         <first-name>Mary</first-name> <last-name>Bob</last-name>
       </publication>
     </author>
     <price>55</price>
   </book>
   <magazine style='glossy' frequency='monthly'>
     <title>Tracking Trenton</title>
     <price>2.50</price>
     <subscription price='24' per='year'/>
   </magazine>
   <book style='novel' id='myfave'>
     <title>Trenton Today, Trenton Tomorrow</title>
     <author>
       <first-name>Toni</first-name>
       <last-name>Bob</last-name>
       <degree from='Trenton U'>B.A.</degree>
       <degree from='Harvard'>Ph.D.</degree>
       <award>Pulizer</award>
       <publication>Still in Trenton</publication>
       <publication>Trenton Forever</publication>
     </author>
     <price intl='canada' exchange='0.7'>6.50</price>
     <excerpt>
       <p>It was a dark and stormy night.</p>
       <p>But then all nights in Trenton seem dark and
       stormy to someone who has gone through what
       <emph>I</emph> have.</p>
       <definition-list>
         <term>Trenton</term>
         <definition>misery</definition>
       </definition-list>
     </excerpt>
   </book>
   <my:book style='leather' price='29.50' xmlns:my='http://www.placeholder-name-here.com/schema/'>
     <my:title>Who's Who in Trenton</my:title>
     <my:author>Robert Bob</my:author>
   </my:book>
 </bookstore>

ホーム Perlの小技

ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。