|
 |
ソフトウェア > Lotus > Lotus Developer Domain > 製品別技術情報 > Lotus Notes/Domino >
LDD Today
Web向けキーワード・マジック Part 2
 |
 |
 |
by Mark Polly
レベル:中級者
対 象:Notes/Domino
原文の掲載:2003年10月13日
Webの開発では、キーワード・リストについて問題がいくつか出てきます。フォーム上に複数のキーワード・リストがあり、前の選択内容に基づいてフィールドの選択肢を作成するような場合には、特に問題になります。Dominoでは、[キーワードの変更時にフィールドを更新]と[文書の更新時に選択肢を更新]という2つのフィールド・プロパティーを使用して、キーワード・リストを再作成することができます。しかし、これらの機能を使用すると、サーバーのトラフィックが増加したり、画面が何度も切り替わったりするほか、ページ上のJavaScriptで問題が発生する可能性もあります。
このシリーズのパート1では、JavaScriptとNotesの@式言語を使ってWeb上でキーワード・リストを作成する方法を見てきました。この方法では、非表示のiframeを使ってDominoフォームを読み込み、そのフォームで@DBColumn関数と@DBLookup関数を実行してキーワード・リストを作成します。この方法の手順を要約すると、次のようになります。
- 非表示のiframeをページに追加します。
- ユーザーがキーワード・リストで選択を行ったら、JavaScriptを使用してiframeに新しいページを読み込みます。
- クエリー文字列からルックアップ値を取得して、それを使ってデータベース・ルックアップを実行します。
- JavaScriptを使って次のキーワード・リストを作成するか、データベース・ルックアップに基づいてフィールドに値を設定します。
今回は、LotusScriptエージェントを使ってキーワード・リストを作成する方法を紹介します。最終的には、リレーショナル・データベースにアクセスしてキーワード・リストを作成する方法について検討します。この記事では、LotusScriptプログラミングの豊富な経験とJavaScriptの知識がある読者を想定しています。
ここで取り上げるアプリケーションでは、ユーザーがドロップダウン・リストから顧客名を選択します。顧客データベースには数千もの顧客名が含まれているため、ユーザーにまず名前の一部を入力してもらうことにします。次に、ユーザーが入力した名前を含むすべての顧客の全文検索を実行し、その結果となる名前のリストをドロップダウン・リストに設定します。その後、ユーザーがリストから実際の顧客名を選択します。以下は、使用するルックアップ・フォームの画面例です。

このフォームでは、PartialNameとCustListという2つのフィールドを使用します。PartialNameフィールドは、顧客の名前の一部を入力するためのテキスト・フィールドです。ここに名前の一部を入力して[Search]ボタンをクリックすると、名前のリストを取得できます。CustListフィールドは、顧客名を選択するためのドロップダウン・フィールドです。
ユーザーがPartialNameフィールドに名前の一部を入力した後に全文検索を実行するには、LotusScriptを使用して検索エージェントを作成します(同じことをJavaを使って行うこともできます)。この検索エージェントの名前はCustSearchとします。PartialNameフィールドの右側にある[Search]ボタンに、以下のJavaScriptコードを指定します。
pname=document.all.PartialName.value;
hidframe = document.all.HidFrame;
hidframe.src = "/" + thisdbname + "/CustSearch?OpenAgent&pname="
+ pname; |
|
このコードの1行目では、テキスト入力フィールド(PartialName)の値を取得しています。2行目では、ページ上の非表示のフレームへの参照を設定しています。3行目では、非表示のiframeのsrcプロパティーを、データベースのCustSearchエージェントを呼び出すURLに設定しています。この行が実行されると、このURLがブラウザーによって非表示のiframeに読み込まれ、エージェントが実行されます。JavaScript変数のthisdbnameは、フォームのHTMLHeadで設定されているため、グローバル変数です。
CustSearchエージェント
ここで取り上げている顧客検索アプリケーションのほとんどの作業は、CustSearchエージェントによって行われます。ここでは、コードをいくつかに分けて解説していきます。完全なLotusScriptコードについては、sidebarを参照してください(Web上でエージェントを実行する際のセキュリティーの問題についての概要は、「Agent security」を参照してください)。
以下のコードの最初の6行は標準のDIMステートメントであり、エージェントで使用するオブジェクトを定義しています。7行目で現在のデータベース・オブジェクトを取得し、8行目でエージェントの文書コンテキストを取得します。エージェントの文書コンテキストは、Notes文書上でフィールドとして定義されている標準のCGI変数(Query_String_Decodedなど)を提供します。10行目で、Notes文書からQuery_String_Decoded値を取得します。このクエリー文字列には、ユーザーが[Search]ボタンをクリックする前に入力したテキストが含まれています。11行目で、LotusScriptのStrRight関数を使用してクエリー文字列を解析し、等号に続けてテキストを返します。
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Dim note As NotesDocument
Dim custNote As NotesDocument
Dim coll As NotesDocumentCollection
Set db = s.CurrentDatabase
Set note = s.DocumentContext
'get the customer name from the querystring
qs = note.Query_String_Decoded(0)
pname = Strright(qs, "=" ) 'get the string to the right of the
equal sign |
|
これで、ユーザーが検索に使おうとしているテキストを取得できました。12行目では、全文検索のためのクエリーを含む文字列を定義します。ここでは、フィールドCustNameが、検索フォームに入力されたテキストに匹敵する文書を検索します。13行目で、作成したクエリーと、いくつかの標準の全文検索オプションを使用して、FTSearchコマンドを実行します。最後に、14行目で、ftsearchメソッドによって返された最初の文書を取得します。
query = "[CustName] Like " & pname
Set coll = db.Ftsearch(query, 0, FT_SCORES, FT_FUZZY + FT_STEMS)
Set custNote = coll.GetFirstDocument |
|
ここまでは、標準のLotusScriptコードを記述してきただけです。今度は、エージェントでJavaScriptコードを生成して、WebページのCustListキーワードを設定する必要があります。まず最初に、15行目で<script>タグを出力します。現在のようにWebブラウザーからエージェントを実行した場合、printステートメントの出力はWebページに送られます。<script>タグは、</script>タグまでのコードをJavaScriptとして解釈するようにブラウザーに指示します。
JavaScriptコードではまず、キーワード・リストから古い値をすべて削除する必要があります。17行目で、JavaScriptオブジェクトをWebページのオプション・オブジェクトに設定します。18〜20行目は、オプション・オブジェクトの既存のオプションを削除するForループです。
Print | oldcustList = parent.document.all("CustList").options;|
Print | for(x=oldcustList.length-1; x>=0; x--){|
Print | oldcustList.options[x] = null;;|
Print | }| |
|
22行目で、Do…Whileループを開始します。このループでは、ループの繰り返しごとに、検索結果から1つの文書を取得します。23行目で、検索結果の各文書について、CustNameフィールドの値を取得します。25行目からは、また一連のprintステートメントが始まります(したがって、再びブラウザーに対してJavaScriptコードを記述することになります)。25行目でページ上に新しいオプション・オブジェクトを作成し、26行目でそれをキーワード・リストのリスト・オプションに追加します。27行目のJavaScriptコードは、キーワード・オプションのテキストを文書のCustNameフィールドの値に設定します。28行目のJavaScriptコードは、キーワード・オプションの値を文書のCustNameフィールドの値に設定します。この時点で、キーワード・リストにはエントリーが1つ追加されています。
Do While Not(custNote Is Nothing)
custName = custNote.CustName(0)
'add the new option
Print | var oOption=parent.document.createElement("OPTION");|
Print | oldcustList.options.add(oOption);|
Print | oOption.innerText="| & custName & |";|
Print | oOption.value="| & custName & |";| |
|
30行目と31行目では、検索結果から次の文書を取得し、ループを継続します。このJavaScriptコードによって、検索されたすべての文書について、顧客名をエントリーとしてキーワード・リストにオプションが追加されます。
Set custNote = coll.GetNextDocument( custNote)
Loop |
|
最後に、33行目で</script>終了タグが出力されて、エージェントの実行が終了します。エージェントの終了後、非表示のiframeのWebページには、顧客名キーワード・リストを作成するためのJavaScriptが含まれています。
Print "</script>"
End Sub |
|
このJavaScriptは、ページの読み込みが終了すると実行されます。以下は、エージェントによって生成されたページのソース・コードです。.innerText
(ユーザーに表示されるテキスト)と.value (送信されるデータ、Notesの別名のようなもの)を設定する行に、FTSearchを使用して検索した文書からのデータが含まれている点に注目してください。
<html>
<head>
</head>
<body text="#000000">
<script>
oldcustList = parent.document.all("CustList").options;
for(x=oldcustList.length-1; x>=0; x--){
oldcustList.options[x] = null;;
}
var oOption=parent.document.createElement("OPTION");
oldcustList.options.add(oOption);
oOption.innerText="M Ind";
oOption.value="M Ind";
var oOption=parent.document.createElement("OPTION");
oldcustList.options.add(oOption);
oOption.innerText="Mark Polly";
oOption.value="Mark Polly";
</script>
</body>
</html> |
|
これで、カスタマイズされたキーワード・リストが顧客検索Webページに表示されます。以下は画面例です。

以上で、LotusScriptを使用して、全文検索の結果に基づくキーワード・リストを動的に作成できるようになりました。先にも述べたように、Javaエージェントを使用しても同じことが可能です。
エージェントを呼び出してキーワード・リストを作成できるのなら、その発想をさらに広げて、リレーショナル・データベースからのデータをリストに含めることもできるはずです。エージェントは、LSXとODBCを使用して簡単にリレーショナル・データにアクセスできます。このほか、JavaとJDBCを使用してリレーショナル・データにアクセスすることもできます。次の例では、先ほどのLotusScriptエージェントを元にして、DB2の顧客リストにアクセスできるようにします。
まずは、先ほどと同じ発想から出発します。キーワード・リストに含めるには顧客リストが大きすぎるため、検索に使用するテキストをユーザーに入力してもらって選択肢を絞り込むことにします。顧客検索フォームは、先ほどと同じものを使用します。以下の検索ボタンのJavaScriptコードもほとんど同じに見えますが、今回は、新しいエージェントであるRDBCustSearchを呼び出しています。
pname=document.all.PartialName.value;
hidframe = document.all.HidFrame;
hidframe.src = "/" + thisdbname + "/RDBCustSearch?OpenAgent&pname="
+ pname; |
|
RDBCustSearchエージェント
RDBCustSearchエージェントは、前の例と同様、LotusScriptエージェントです。ここでは、コードをいくつかに分けて解説していきます。完全なコードの例については、sidebarを参照してください
このエージェントの最初の20行は、前の例とよく似ています。変数とオブジェクトをDIMステートメントで定義し、セッションと文書コンテキストを取得し、Query_String_Decodedのデータを解析しています。
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Dim note As NotesDocument
Dim custNote As NotesDocument
Dim coll As NotesDocumentCollection
Dim con As ODBCConnection
Dim qry As ODBCQuery
Dim res As ODBCResultSet
Dim dataSource As String
Dim userName As String
Dim password As String
Dim SQLStmt As String
Set db = s.CurrentDatabase
Set note = s.DocumentContext
'get the customer name from the querystring
qs = note.Query_String_Decoded(0)
pname = Strright(qs, "=" ) 'get the string to the right of the
equal sign |
|
21〜23行目では、ODBCConnection、ODBCQuery、およびODBCResultSetの各オブジェクトを作成します。24〜26行目では、データベースへの接続に使用する変数を設定します。28行目で、データソース、ユーザーID、およびパスワードの値を使用してデータベースに接続します。接続に成功すると、31行目でクエリー・オブジェクトがデータベースに接続されます。
Set con = New ODBCConnection
Set qry = New ODBCQuery
Set res = New ODBCResultSet
dataSource = "CUSTDB"
userName = "MPOLLY"
password = "test"
If Not con.ConnectTo(dataSource, userName, password) Then
Messagebox "Could not connect to " & dataSource
Else
Set qry.Connection = con
End If |
|
34〜37行目では、DB2データベースのクエリーに必要なSQLステートメントを定義します。このSQLでは、クエリー文字列から解析した値に匹敵する("like")
Cust_Nmフィールドを要求します。39〜41行目で、SQLステートメントをクエリー・オブジェクトに接続し、クエリーを実行します。クエリーの結果は、resオブジェクトで返されます。データが返されなかった場合は、43行目でエージェントを終了します。この場合、フォーム上のキーワード・リストは変更されません。
SQLStmt = "SELECT LTRIM(TRANSLATE(B.CUST_NM, '', '*')) AS CUST_NAME"
&_
"FROM CUSTDB.EDW00T.VRPM_CUST_DIM B " &_
"WHERE B.CUST_NM LIKE '*" & pname & "%' OR B.CUST_NM
LIKE '" & pname & "%' " &_
"ORDER BY CUST_NAME"
qry.SQL = SQLStmt
Set res.Query = qry
res.Execute
If Not(res.IsResultSetAvailable) Then ' No matches were found exit
Exit Sub
End If |
|
結果が返された場合は、46行目からJavaScriptステートメントの出力を開始します。<script>タグは、その後に続くコードがJavaScriptであることをブラウザーに伝えます。先ほどのLotusScriptの例と同様に、まず最初にキーワード・リストの古いエントリーを削除する必要があります。48行目で、oldcustListオブジェクトをページ上のキーワード・オブジェクトに設定します。49〜51行目で、Forループを使用して各オブジェクトをnullに設定して、古いエントリーをすべて削除します。
Print "<script>"
'delete current options in the keyword list
Print | oldcustList = parent.document.all("CustList").options;|
Print | for(x=oldcustList.length-1; x>=0; x--){|
Print | oldcustList.options[x] = null;;|
Print | }| |
|
53行目では、Doループを実行します。このループは、結果セットの最後に達するまで(63行目)実行されます。まず最初に、結果セットの次の行を取得します(54行目)。1回目のループでは、レコード1が取得されます。57行目で検索ページ上に新しいオプション・オブジェクトを作成し、58行目でそれをキーワード・リストに追加します。次に、.innerTextプロパティーを使用して、キーワード・リストに表示するテキストを設定し、続いてvalueプロパティーを設定します。valueプロパティーは、Notesフォームの別名のように機能します。結果セットのすべてのデータが処理された後、65行目で<script>タグを閉じます。
Do
res.NextRow
custName = res.GetValue(Cust_Name)
'add the new option
Print | var oOption=parent.document.createElement("OPTION");|
Print | oldcustList.options.add(oOption);|
Print | oOption.innerText="| & custName & |";|
Print | oOption.value="| & custName & |";|
Loop Until res.IsEndOfData
'close the javascript tag
Print "</script>"
End Sub |
|
検索が実行されてキーワード・リストが設定された状態のページがどのようになるかは、前の画面例を参照してください。
Webアプリケーションにおいて、キーワード・リストは非常に強力なツールです。キーワード・リストがないと、ユーザーによって間違ったデータがシステムに入力される可能性がありますが、キーワード・リストを使用すれば、初めから正しいデータが作成されるようにすることができます。しかし、HTMLはステートレスであるため、フォームに入力されたデータを使用してキーワード・リストを作成したり、ページ上の別のキーワード・リストからキーワード・リストを作成したりするのは困難です。ここで紹介した方法を使えば、Notesクライアントの場合と同じように、Webでも動的にキーワード・リストを作成することができます。

著者について
Mark Pollyは、Meritage Technologies, Inc.のテクニカル・アーキテクトです。Meritageは、従業員所有の技術コンサルティング会社であり、Global
3500企業や公共部門の組織に専門的サービスを提供しています。Lotus Notes認定開発者であるMark
Pollyは、Release 1のときからLotus Notesに携わっており、1996年以降さまざまな企業に対して、Notes、Domino、およびその他の技術プロジェクトのコンサルティングを行ってきました。
|
 |
|
|
|