XML::XQLの注意事項と検索プログラム

by 川合孝典 Hippo2000(1999/9/1,9/2)

XML::XQLはPerlでXMLを検索するためのモジュールです。

これを使うさいの注意事項と単純な検索プログラムについて説明したいと思います。

更新履歴

1999/ 9/ 1 : 初回リリース
1999/ 9/ 2 :tkxql.plに整形する機能を追加


目次


XML::XQLとは

XML::XQLモジュールは1998年9月XSLワーキング・グループによって提出されたXQL (XML Query Language) プロポーザルを実装しています。その仕様は以下のURLで見ることが出来ます: http://www.w3.org/TandS/QL/QL98/pp/xql.html。XQL文法の説明が、一緒に配布されているTutorialにも入っています。

なおXML::XQLでは、XQL+ということで独自の拡張も追加しています。詳細についてはドキュメントをご覧下さい。

XML::XQLのインストール

XML::XQLを利用するためには、以下のモジュールが必要になります。

パッケージ名 説    明
XML-DOM XQLモジュールはDOMをベースにしています。
Date-Manip 日付を解釈するために利用されています。
Parse-Yapp 問い合わせ式の解析に使われます。
XML-XQL XML-XQLです。

なおXML::XQLは、PPMの標準のURLには、まだ用意されていないようです。
http://www.fastnetltd.ndirect.co.uk/Perl/zips/ にも固められたものがあるのですが、ちょっと古いものです。
http://pm.bi.umist.ac.uk/packages/ または http://www.bi.umist.ac.uk/packages/ にあるものが最新のものになっています。

実行時の注意

encodingの値

Windowsで利用するXMLファイルのencodingの値には「Shift_JIS」、UNIXでは「euc-jp」が使われることが多いかと思います。
しかし、現在のところXML::Parserではこれらを認識しません。指定する場合には「x-sjis-unicode」あるいは「x-euc-unicode」をご利用下さい。詳しい説明がPerlをインストールしたディレクトリの下のsite\lib\xml\parser\encodingディレクトリ(通常はc:\perl\site\lib\xml\parser\encodings)にあるReadMeとJapanese_Encodings.msgというファイルをご覧下さい。

「プログラム名またはファイル名が違います」が出る

何の対策もなしにWindows上で起動すると「プログラム名またはファイルが違います」といったメッセージを5回出します。これはXML::XQLでは、問い合わせの評価の途中でのエラーメッセージを表示する時の区切り文字のために`tput smul` (下線をつける)と`tput rmal` (下線をはずす)、`tput bold`(太字にする)、`tput rmul` . `tput smul`(元に戻す)を使用しているためです。UNIXでは存在するtputというプログラムがないためにエラーメッセージが表示されるのです。エラーメッセージが出ても、検索には影響ありません。

これを避けるためには、「tput.bat」のようにダミーのプログラムを用意したり、xql.pmでtputを呼び出している箇所をコメント化するなどの対応が必要になります。(コメント化すると初期起動の時間が短くなるというメリットもあります。もちろん危険が伴いますが)

メモリが足りなくなる

XML::XQLもIEのXMLDOMもXMLを読み込んで、DOMツリーをメモリ上に展開します。そのためあまり大きなファイルを利用しようとすると異常終了することがあります。Windowsで利用する場合には、メモリはファイルサイズの約100倍くらいの空き容量が必要な印象を受けました。メモリ48MBの95マシンでも300K程度のファイルの検索はできています。


検索プログラム

Perlの機能だけで作成したtkxql.pl、IEの機能だけで作成したiexsl.htm、IEの機能をPerlから利用しているiexsl.plの3つのプログラムについて説明します。プログラム自体とても簡単なものなので、説明もとってもシンプルです。

ここで説明しているプログラムはここから(xql_pg101.lzh)まとめてダウンロードすることができます。

XQL検索プログラム(tkxql.pl)

XML::XQLモジュールによるXML検索プログラムにTkモジュールでGUIをつけました。Win95、98で動作を確認しています。

※tkxql.plに検索結果を整形する機能を追加しました。(99/9/2)

必要なモジュール

XML::XQLモジュールとそのためのモジュールの他に以下のものを利用しています。

パッケージ名 説    明
I18N::cvt 岡部さんがお作りになったモジュールです。UTF8<->SJISのコード変換を行います。
http://www.geocities.co.jp/SiliconValley-PaloAlto/2514/ にあります。
Tk GUIのためのモジュールです。

使い方

  1. コマンドラインから「perl tkxql.pl」としてプログラムを起動します。
  2. 「参照...」ボタンをクリックし、対象となるファイルを選択します。
  3. 問い合わせ文字列を入力し、「検索」ボタンをクリックすると結果が表示されます。
  4. 「終了」ボタンをクリックするとプログラムが終了します。

 

XSL検索プログラム(iexsl.htm)

IEを利用して、XSLの問い合わせを行うプログラムです。IE5.0が必要です。

使い方:

  1. ファイルをIE5.0で読み込みます。
  2. 「参照...」ボタンをクリックし、対象となるファイルを選択します。
  3. 問い合わせ文字列を入力し、「検索」ボタンをクリックすると結果が表示されます。

 

XSL検索プログラム(iexsl.pl)

IE5.0のXSL検索機能をPerlから利用しています。

必要なモジュール

XML::XQLモジュールとそのためのモジュールの他に以下のものを利用しています。

パッケージ名 説    明
Tk GUIのためのモジュールです。
Win32::OLE OLE連携のためのモジュールです。             

IE5.0の機能を利用しているので、この他にIE5.0がインストールされている必要があります。

使い方

  1. コマンドラインから「perl iexsl.pl」としてプログラムを起動します。
  2. 「参照...」ボタンをクリックし、対象となるファイルを選択します。
  3. 問い合わせ文字列を入力し、「検索」ボタンをクリックすると結果が表示されます。
  4. 「終了」ボタンをクリックするとプログラムが終了します。

QL検索プログラム(tkql.pl)

XML検索するためのもう1つのモジュールXML::QLを使った例です。

必要なモジュール

以下のモジュールを利用しています。

パッケージ名 説    明
XML-QL QLのためのモジュールです。
I18N::cvt 岡部さんがお作りになったモジュールです。UTF8<->SJISのコード変換を行います。
http://www.geocities.co.jp/SiliconValley-PaloAlto/2514/ にあります。
Tk GUIのためのモジュールです。

なおXML::QLは、PPMの標準のURLには、まだ用意されていないようです。
http://pm.bi.umist.ac.uk/packages/ または http://www.bi.umist.ac.uk/packages/ にあるものが最新のものになっています。

使い方

  1. コマンドラインから「perl .pl」としてプログラムを起動します。
  2. 問い合わせ文字列を入力し、「検索」ボタンをクリックすると結果が表示されます。
  3. 「終了」ボタンをクリックするとプログラムが終了します。

簡単な実行例

添付したXMLファイルで簡単な検索の例をあげてみます。

問い合わせ文字列の詳しい説明については、参考資料をご覧下さい。

対象となるデータ

一緒に配布されている「組織図.xml」(IE5の機能を利用しているプログラムでは「組織図_ie.xml」)というファイルを利用します。

内容は以下のような12人の会社の組織を表しています。

<?xml version="1.0" encoding="x-sjis-unicode" ?>
<!-- サンプルデータ for XML::XQL by Hippo2000 -->
<組織図>
<社員 肩書="社長" 社員番号="1"><名前>社長大二郎</名前></社員>
    <組織 組織名="技術部">
        <社員 肩書="部長" 社員番号="9"><名前>部長一郎</名前></社員>
        <組織 組織名="1課">
            <社員 社員番号="17" 肩書="課長" 生年月日="Mar 23rd 1964"><名前>課長一郎</名前></社員>
            <社員 社員番号="25" 肩書="リーダー" 生年月日="Mar 9th 1970"><名前>平花子</名前></社員>
            <社員 社員番号="23" 生年月日="03/11/1970"><名前>平一郎</名前></社員>
            <社員 社員番号="29" 生年月日="6/27/1966"><名前>平三郎</名前></社員>
        </組織>
        <組織 組織名="2課">
            <社員 肩書="課長"  社員番号="22"><名前>課長花子</名前></社員>
            <社員  社員番号="18"><名前>平太郎</名前></社員>
            <社員  社員番号="20"><名前>平四郎</名前></社員>
        </組織>
        <社員  社員番号="8" 肩書="専門技師"><名前>技術一筋</名前></社員>
    </組織>
    <組織 組織名="営業部">
        <社員 肩書="部長"  社員番号="30"><名前>部長次郎</名前></社員>
        <社員 肩書="担当課長"  社員番号="27"><名前>課長一人</名前></社員>
    </組織>
</組織図>

問い合わせ文字列とその結果

問い合わせ文字列のパターンとその結果を表にすると以下のようになります。

特にXML::XQLのみと書いていないもの以外は、3つのプログラムとも同じ動きになります。

   種類   

問い合わせ文字列

         検索結果           

要素の検索 社員名の一覧を表示する:

//社員/名前

===== No:1====
<名前>社長大二郎</名前>
===== No:2====
<名前>部長一郎</名前>
===== No:3====
<名前>課長一郎</名前>
===== No:4====
<名前>平花子</名前>
===== No:5====
<名前>平一郎</名前>
===== No:6====
<名前>平三郎</名前>
===== No:7====
<名前>課長花子</名前>
===== No:8====
<名前>平太郎</名前>
===== No:9====
<名前>平四郎</名前>
===== No:10====
<名前>技術一筋</名前>
===== No:11====
<名前>部長次郎</名前>
===== No:12====
<名前>課長一人</名前>
属性の検索 肩書きを持っている人の一覧表示:

//社員[@肩書]/名前

===== No:1====
<名前>社長大二郎</名前>
===== No:2====
<名前>部長一郎</名前>
===== No:3====
<名前>課長一郎</名前>
===== No:4====
<名前>平花子</名前>
===== No:5====
<名前>課長花子</名前>
===== No:6====
<名前>技術一筋</名前>
===== No:7====
<名前>部長次郎</名前>
===== No:8====
<名前>課長一人</名前>
フィルターを利用する
(要素の値)
名前が「平三郎」である社員:

//社員[名前="平三郎"]

===== No:1====
<社員 社員番号="29" 生年月日="6/27/1966"><名前>平三郎</名前></社員>
フィルターを利用する
(属性の値)
社員番号が10番までの社員:

//社員[@社員番号 $le$ 10]

===== No:1====
<社員 肩書="社長" 社員番号="1"><名前>社長大二郎</名前></社員>
===== No:2====
<社員 肩書="部長" 社員番号="9"><名前>部長一郎</名前></社員>
===== No:3====
<社員 社員番号="8" 肩書="専門技師"><名前>技術一筋</名前></社員>
添字を使う ある組織の責任者:
※各組織の先頭が責任者と考えます。

//組織/社員[0]/名前

===== No:1====
<名前>部長一郎</名前>
===== No:2====
<名前>課長一郎</名前>
===== No:3====
<名前>課長花子</名前>
===== No:4====
<名前>部長次郎</名前>
メソッドを使う
ある組織の責任者の次の人:
※各組織の先頭が責任者と考えます。

//組織/社員[index() = 1]

===== No:1====
<社員 社員番号="25" 肩書="リーダー" 生年月日="Mar 9th 1970"><名前>平花子</名前></社員>
===== No:2====
<社員 社員番号="18"><名前>平太郎</名前></社員>
===== No:3====
<社員 社員番号="8" 肩書="専門技師"><名前>技術一筋</名前></社員>
===== No:4====
<社員 肩書="担当課長" 社員番号="27"><名前>課長一人</名前></社員>
関数を使う
(XML::XQLのみ)
技術部に所属する人数:

count(//組織[@組織名="技術部"]//社員)

===== No:1====
XML::XQL::Number
[0]:9
[1]:
XML::XQL独自の型を
利用する
(XML::XQLのみ)
生年月日が1964年3月23日か、1966年6月27日の社員:

//社員[date(@生年月日) = "03/23/1964" $or$ date(@生年月日) = "Jun 27th 1966"]

===== No:1====
<社員 社員番号="17" 肩書="課長" 生年月日="Mar 23rd 1964"><名前>課長一郎</名前></社員>
===== No:2====
<社員 社員番号="29" 生年月日="6/27/1966"><名前>平三郎</名前></社員>

XMLとデータベースについて(ここは独り言)

現在、データベースといえばAccess、OracleなどといったRDBが主流だと思われます。
今回、ここでは簡単な検索のためのXMLとXQL(あるいはXSLのパターン)を説明させていただきましたが、結構使いやすいのではないかと感じているのですが、いかがでしょう?データの更新/作成も普通のエディタでできます。

もちろん本当のデータベースではありませんから、メモリに展開できる分しか扱えませんし、索引を利用していないので検索スピードにも限界があります。

しかし、ここで出しているような簡単なデータであってもRDBの形式で実現するどうすればよいのでしょうか?
「社員」テーブルと「組織」テーブルを用意して、結合のためのIDを用意して...。あまり簡単には思えません。
特に「階層」を表そうとするとそれだけで私は途方にくれてしまいます。

※RDBで柔軟に階層をアクセスできる方法をご存知のかたがいらっしゃったら教えていただきたいと思っています。<(__)>

さらにデータベースということでいえば、メモリにあるのかデータベースにあるのかを意識しないように使えればとても便利だろうとは思っています。オブジェクト・デザイン社のObjectStoreにPerl用インタフェースをつけてくれぃ。


参考資料

XML::DOM、XML::XQLのドキュメント:
各モジュールに一緒に添付されるドキュメントをご覧下さい。特にXQLチュートリアルは便利だと思います。
日本語にした(つもり)のドキュメントは河馬屋二千年堂ホームからご覧下さい。 
 
Microsoft社のサイト:
あいにくと英語ですが、リファレンスなので見ておかないと...
XML DOM Reference http://msdn.microsoft.com/xml/reference/xmldom/start.asp
XSL Developer's Guide: http://msdn.microsoft.com/xml/xslguide/default.asp
XSL Reference : http://msdn.microsoft.com/xml/reference/xsl/start.asp

ホーム Perlの小技

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