2010年2月3日水曜日

NotesDirectory クラスをさわってみた(2)

Notes 8 で追加されたクラス NotesDirectory のメソッド LookupNames を使い、ディレクトリ・アシスタンスで定義されている複数のドミノディレクトリからユーザー文書の短縮名を取得する処理を作成しています。
※とりいそぎ業務で使う予定はありませんが今後の参考のため...

今回の目標としては、次の式と同じ結果が戻ってくれば成功としています。

@StatusBar(@Implode(@NameLookup([Exhaustive]; "ichiro suzuki"; "ShortName"); ", "));
@StatusBar(@Implode(@NameLookup([Exhaustive]; "hogehoge"; "ShortName"); ", "));
@StatusBar(@Implode(@NameLookup([Exhaustive]; "sato"; "ShortName"); ", "));

名前を正常に検索できた場合、下表の ShortName が戻ります。
Name ShortName 1 ShortName 2 ShortName 3
ichiro suzuki sichiro si42
hogehoge
sato staro sjiro psato90

デザイナーヘルプによると LookupNames の2番目のパラメータ(以下 names) は Variant 型で指定できるのでスカラー値でも配列でも動作するようです。

そこで、検索したい名前がいくつもあるという前提で、配列で定義した names へ値を格納して実行するロジックを組み、検索する名前の順序を変化させてテストを繰り返してみたのですが、とても納得できる挙動にはならず目標が達成できませんでした。

結局 names を配列ではなくスカラー値とし、また名前を検索するたびに NotesDirectory オブジェクトを取得するロジックとしたところ、ようやく上の式と同じ結果が得られる様になりました。
Sub Initialize
    Dim strName(2) As String
    strName( 0 ) = "ichiro suzuki" '2件存在する
    strName( 1 ) = "hogehoge" '名前が存在しない
    strName( 2 ) = "sato" '3件存在する
    Forall o In strName
        Call LookupName( o )
    End Forall
End Sub

Sub LookupName( nam As String )
    Dim ss As New NotesSession
    Dim nd As NotesDirectory
    Dim ndnav As NotesDirectoryNavigator
    Dim var As Variant
    Dim init( 0 ) As String
    var = init
    Set nd = ss.GetDirectory( "hogehoge/org" )
    Set ndnav = nd.LookupNames( "$Users", nam, "ShortName", False )
    While ndnav.MatchLocated
        var = Arrayappend( var, ndnav.GetFirstItemValue )
        ndnav.FindNextMatch
    Wend
    Print Join( Fulltrim( var ), ", " )
End Sub
以下に NotesDirectoryNavigator について「理解した」ことをご紹介します。

LookupNames の検索結果へアクセスするには NotesDirectoryNavigator クラスを使います。

LookupNames を実行した直後の NotesDirectoryNavigator クラスには names の最初の名前の検索結果に位置付けられます。
names へ設定した「検索する名前」へ位置づけるのに
FindFirstName, FindNextName, FindNthName といったメソッドを使います。
LookupNames メソッドを実行したときには names の最初の名前に位置付けられます。

「検索する名前」へ位置づけた時、一致(Match)した名前の数が CurrentMatches プロパティにセットされます。
※CurrentMatches は8のデザイナーヘルプに掲載されていません...orz

例えば "suzuki" をディレクトリで検索すると一致する名前はたくさん見つかるかもしれません。
上の例の場合、"ichiro suzuki" は2エントリ(ユーザー文書の数)ですから CurrentMatches は 2 がセットされます。
CurrentMatches が 0 ではない時、一致する名前があることを示しています。

FindFirstMatch, FindNextMatch, FindNthMatch といったメソッドを使い、検索結果に一致する名前に位置決めをします。
位置づけられている名前の位置を示すのは CurrentMatch プロパティです。(名前がややこしい...)

以上、事実関係を並べましたがこういった説明がデザイナーヘルプに欲しかったよ...


未だによくわからないのが、NotesDirectory オブジェクトを使いまわす場合と、名前ごとに NotesDirectory オブジェクトを取得する場合で結果が異なることです。

「NotesDirectory キャッシュ」や「検索バッファ(namelookupバッファ?)」がどう影響して、FreeLookupBuffer メソッドはどのように効果を発揮するのか....理解するには時間がかかりそうです。


そして、とても気になっていることは、

・検索結果が3つになるはずの名前を FindNextName で位置づけたとき CurrentMatch が 2 になる...なぜ1番目に位置づけされないのか?

・FindNthMatch( i ) で i を1から順に変化させたときの CurrentMatch プロパティの値をデバッガで観察すると、どうしたわけか値は 1 -> 2 -> 3 と推移せず 2 -> 2 -> 3 と推移する

・FindNthMatch( 1 ) で CurrentMatch が 2 なのに GetFirstItemValue で 1 番目の値がとれた...orz

以下、おかしな挙動をするロジックです。ご参考まで
Dim ss As New NotesSession
Dim nd As NotesDirectory
Dim ndnav As NotesDirectoryNavigator
Dim strName(2) As String
Dim var As Variant
Dim init(0) As String
Dim cnt As Long
strName(0) = "ichiro suzuki" '2文書存在する
strName(1) = "hogehoge"      '存在しない名前
strName(2) = "sato"        '3文書存在する
Set nd = ss.GetDirectory( "hogehoge/org" )
Set ndnav = nd.LookupNames( "$Users", strName, "ShortName", False )
While cnt < Ubound( nd.AvailableNames ) + 1
    cnt = cnt + 1
    If ndnav.NameLocated Then
        For i = 1 To ndnav.CurrentMatches
            ndnav.FindNthMatch( i )
            var = Arrayappend( var, ndnav.GetFirstItemValue )
        Next
        Print Print Join( Fulltrim( var ), ", " )
    End If
    ndnav.FindNextName
Wend

0 件のコメント:

コメントを投稿