このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

AppleScriptで簡易検索CGIで壁

発言者:saka
( Date Tuesday, January 28, 1997 21:18:10 )


現在、CGIによる簡単なデータ検索を行おうと思っています。

データとしては、30人分各々に「aa,bb,cc,dd,ee,ff,name」と言う
データを持たせタブ区切りでテキストファイルとして保存してあります。 
「m  ks  aa  bu  a  aries  name01
 f  hs  bb  sp  a  taurus  name02
                                           ・・・・」
                                                       
aa〜ffは各々複数の内容、例えばffはその人間の星座(結果12種類の選択)
の様なものです。

フォーム上のラジオボタンで、aa〜bb各々の検索条件を選び検索を実行すると
該当する人間の「name」の部分が一覧となって返ってくる、と言うものです。
(判りにくいでしょうか?)

田中先生のCGI Tool Kitなどを参考に、AppleScriptで書き始めましたが、
まず、on ヌevent WWWスsdocネ ハンドラの前に
on runハンドラ内ファイルを変数 memList にリストとして読み込みました。

on runハンドラの中では、この memList の各々の値を参照出来るのですが、
(Script Editorの結果や履歴を見る限り・・・)
いざ、on ヌevent WWWスsdocネ の中では

set memData to word 1 of item 1 of memList

と、しただけでブラウザでは

>>Error receiving results from ACGI execution. (-1701) 

となってしまいます。

memLIstさえ on ヌevent WWWスsdocネ の中で使わなければ
returnで定義したとおりの結果がブラウザに表示されるので、
たぶん memList の扱方が違っているのだと思いますが・・・。
 
なにぶん、AppleScriptは勉強中で必要な情報が抜けた
質問になっているかもしれませんが、どうかアドバイスをお願いします。

田中求之 さんからのコメント
( Tuesday, January 28, 1997 22:46:03 )

memList がローカル変数になっていませんか? ローカル変数になっていると
run ハンドラーの中で参照できません。

run ハンドラーで初期化された memList を CGI のメインのハンドラーの中で
利用するためには

1: memList を property にする
2: memList をグローバル変数にする

のどちらかでなければなりません。property にするのが良いと思います。

スクリプトの冒頭で

property memList : ""

として、memList を property にしておくのがよいでしょうね。

saka さんからのコメント
( Wednesday, January 29, 1997 13:44:37 )

田中先生ありがとうございます。

ご指摘のとおり
>>property memList : ""
として、memListをpropertyとすることで
on ヌevent WWWスsdocネ内でmemListを参照することが出来ました。
で、甘えついでにもう一つお聞かせください。

リストに格納された個人データの各々の項目をフォームでチェックされた
ものと比較するために現在、この様なスクリプトを書いて見たのですが、

set memRef to ""
repeat with i from 1 to 30
  if (((word 1 of item i of memList = sex) and (word 2 of item i of memList = department)) and ツ
  ((word 3 of item i of memList = years) and (word 4 of item i of memList = hobby))) and ツ
  ((word 4 of item i of memList = blood) and (word 5 of item i of memList = horos)) then
  set memRef to memRef & word 7 of item i of memList & crlf
  end if
end repeat

「sex,department,years,hobby,blood,horos」はpost_argsを解析し
最終的にURLデコードを施し、各変数に代入したものです。
このあと、return で memRefを返しているのですが、
果たして、結果は常にmemRefの中味は空のようです。

比較の仕方が間違っていますでしょうか?それとも、
リストの中味を参照した際のデータ形式とpost_argsから取り出した各変数の
データの形式が違っているのでしょうか?
ちなみに、「sex,department,years,hobby,blood,horos」を単純に
returnすると、フォームの選択項目通りのVALUEが表示されますが・・・

田中求之 さんからのコメント
( Wednesday, January 29, 1997 20:34:47 )

run ハンドラーでのmemList の初期化(タブ区切りで並んだデータを読み込んでリスト
として格納する)はどのようなスクリプトになっていますか?

memList のデータ構造が問題ではないかと思うのですが?


saka さんからのコメント
( Thursday, January 30, 1997 14:51:21 )

田中先生ありがとうございます。

>>run ハンドラーでのmemList の初期化(タブ区切りで並んだデータを読み込んでリスト
>>として格納する)はどのようなスクリプトになっていますか?

試行錯誤の上での苦肉の策として
Tanaka's osaxを利用させていただき

>set memList to getLines file FilePath keyword "mem"

としています。
keywordのため、ダミーとしてデータファイルのか苦行の末尾にmemを追加してます。(苦)
この結果、スクリプトエディターの履歴ウィンドウでは

getLines file "Master:CropHost:cgi-bin:memlist" keyword "mem"
  --> {"m  ks  aa  bu  a  aries  name1  mem", 
  "f  hs  bb  sp  a  taurus  name2  mem",
          ・
          ・
          ・
  "m  hs  cc  bu  o  scorpio  name30  mem"}
と表示されています。
この様な構造では、旨くいかないのでしょうか?

田中求之 さんからのコメント
( Thursday, January 30, 1997 19:25:50 )

memlist のファイルは、各項目がタブ区切りになって、レコードは改行で
区切られているというテキストファイルなのですよね?

でしたら、普通に読み込んだ後にリストに分解する方が早いと思いますよ。
getLine は検索処理が入りますからその分遅くなります。

set mydata to readFromFile file "Master:CropHost:cgi-bin:memlist"
set oldDel to AppleScript's text item delimiters
set AppleScript's text item delimiters to {return}
set memList to text items of myData
set AppleScript's text item delimiters to oldDel

これで、レコード毎に分かれたリストとして読み込まれます。


で、肝心のリストの比較の部分ですが、各アイテムはタブ区切りでデータが並んで
いるわけですから、これをいったんリストに分解して比較を行うのがよいと思います。
word を使うとスペースが混じったときに誤動作の原因になります。

比較部分は改めて書き込みます

田中求之 さんからのコメント
( Thursday, January 30, 1997 23:11:52 )

リストの比較については、具体的に書き始めると長くなりますので一般
的な点から述べておきます。

たとえば

ListA = {"MAH01402","UVJ"}  --- NIFTY の ID とハンドルです

ListB = {"MAH01402","UVJ","Tanaka"} --- 上プラス名前

という二つのリストがある場合、ListA が ListB の先頭2つのアイテム
と一致するかどうかは以下のスクリプトによって判定できます。

 ListA = (items 1 thru 2 of ListB)   --- 上の場合は true になる

ですから、post_args を分解した要素が memList に登録されている
データのどれかと一致するかどうかの判定は、post_argsのデータを
リストにしておき、これと、memList の各レコードの比較を行うのが
よいと思います。

 set myList to DecodeJArgs post_args

 set myNameList to {}
 repeat with thisR in memList
   set thiR to contents of thisR
   set thisR to itemsToList thisR --- Tab区切りテキストをリストに変換
   if myList = (items 1 thru 6 of thisR) then --- リストの比較
     set end of myNameList to item 7 of thisR
   end if
 end repeat

これを実行すれば、myNameList には、データの一致するものの名前
(レコードの第7アイテムのデータ)のリストが収まります。

もしテキストデータで欲しいのでしたら、最後に

 set oldDel to AppleScript's text item delimiters
 set AppleScript's text item delimiters to {return}
 set myNameList to myNameList as string
 set AppleScript's text item delimiters to oldDel

というスクリプトで変換を行います(データを次々に追加していく処理は
リストを使って set end of ... で追加を行い、最後に希望する型に
変換するというのが AS で処理をうまく/早くこなすポイントです)。

参考になれば幸いです

saka さんからのコメント
( Friday, January 31, 1997 14:06:06 )

いつも、本当にありがとうございます。

やはり、AppleScriptも奥が深いですねぇ。
この週末かけて試させていただきます。

(でも、FFVIIが・・・)

田中求之 さんからのコメント
( Friday, January 31, 1997 14:33:24 )

>やはり、AppleScriptも奥が深いですねぇ。


起動時に memList を読み込むのを止めて、ファイルを直接検索する方法もあるん
ですよ。

たぶん、こちらの方が、手間がかからず、データの更新などのことを考えると
現実的です( CGI Kit の file_db1 を参考にしてください。先日リリースした
改訂版の方)。

saka さんからのコメント
( Friday, January 31, 1997 17:02:04 )

ありがとうございました。

やはり、土日はFFVIIの為にあけようと(*^_^*;;先ほど教えて頂いた事を参考に
やっと原形が動きました。本当にありがとうございます。

>>起動時に memList を読み込むのを止めて、ファイルを直接検索する方法もあるん
>>ですよ。

>>たぶん、こちらの方が、手間がかからず、データの更新などのことを考えると
>>現実的です( CGI Kit の file_db1 を参考にしてください。先日リリースした
>>改訂版の方)。

なるほど、そういう手もあるのですね。
CGIの実行プロセスとしてはどちらが効率的なのでしょう?
on runハンドラーがアプリケーションとしてのAppleScriptを
立ち上げたときのみに実行され、その中でsetした変数をkeepしていてくれるのなら
ファイルへのアクセスは、立ち上げ時だけの方が
実行時間は若干短くなる様な気がしますが・・・

ところで、教えていただいたリストどうしの比較に
ワイルドカード的な要素をいれることは出来るのでしょうか?
フォーム上での選択肢の中に「この項目については検索しない」の様な
項を設け、検索要素を減らしてみたいのですが。
なにせ、30人程度のデータを6項目で完全一致検索させると、
出てくるデータが多くても一人なんて事になりますもので・・・・
他の方のコメントチェーンでも、ワイルドカードの話題が出ていますが、
どうも、目的が違うせいか(私のskillが低いからでしょう)応用が利きません。

田中求之 さんからのコメント
( Friday, January 31, 1997 17:24:06 )

リストの比較でワイルドカード的なものを用いようとすれば、結局、各項目を丹念に
比較することになりますので、処理の時間は遅くなります。たぶん、ファイルメーカーを
用いた方が早いという結果になると思います。

memList をメモリー読み込みするか、それとも検索時にファイルを検索させるか
ですが、ファイル検索の場合、ファイルのデータを必要に応じて更新すると、
更新が即座に反映されるというメリットがあります。


やり方は簡単で

set myList to DecodeJargs post_args

として FORM からのデータをデコードした後、

set AppleScript's text item delimiters to {tab}
set myList to myList as string

を実行して、タブ区切りの文字列にまとめてしまいます。で、これが含まれる行
だけをファイルからピックアップすればよいので、

set dataList to getLines file .... keyword myList

で、あとは、このリストから必要なデータを抜いていきます。

処理の時間としては、ファイルが数メガにならないかぎり、さほど差はないと思います。

まぁ、暇なときにでもお試しください。