2024/06/23

DXL Step-by-Step:#34)表の列幅のしくみ

今回は、表の列幅の設定についてまとめます。


列幅の設定

ノーツクライアントでは表のプロパティで列幅を設定できます。設定は固定幅と可変幅に大別できます。固定幅の場合は、『固定幅』にチェックを入れて、幅を指定します。

可変幅の場合は、『固定幅』のチェックを外し、幅を指定します。画面上の表全体の幅からの相対的な幅となるので、画面のサイズが変われば伸縮します。


列幅の設定と DXL

2 行 3 列の表(マージンに合わせる設定)を作成し、1 列目の幅を 2 cmで固定します。残り 2 列は可変幅のまま、サイズを適当に調整します。

この表を DXL に変換し、列の定義 tablecolumn ノードを確認すると次のようになります。

固定幅の場合は、長さを明示的に指定し、可変幅の場合は % で指定されています。マージンの設定などと同じ仕組みですね。ただ、列幅の場合には、可変幅の合計が 100% となる仕様のようです。当たり前ではありますが...

列幅の設定 tablecolumn ノードの width 属性は次の通りとなります。

属性 設定値 補足
width '2.7875in' など 固定幅として幅を長さ(インチ)で指定
'33%' など 可変幅として割合(%)で指定
表内の可変幅の合計が 100% となる

また、前回 紹介した表の幅の設定(table ノードの widthtype 属性)で固定幅となっている場合には、列幅も固定幅だけとなります。DXL で表を操作する際には、設定のつじつまが合うように注意が必要ですね。


前回 DXL Step-by-Step


2024/06/21

アプリカタログのカテゴリを活用しよう!

前回作成したアプリケーションカタログには、カテゴリ別というビューが存在します。

数が少ないので、サーバ内のすべてのアプリケーションが表示されているわけではなさそうです。このビューの設計をデザイナーで開き確認します。細かな点はさておき、Categories フィールドが 空 でない文書を表示していることがわかります。

カタログ内の文書では、以下の項目の部分が Categories フィールドとなります。

では、この値の出所を確認しましょう。そのアプリケーションのプロパティを確認すると、カテゴリ欄にセットされていました。Catalog タスクで情報を収集する際、このプロパティの値をカテゴリとして記録しているということですね。


改めて、カテゴリ別というビューの1列目をデザイナーで確認します。列式は次の通りです。

カンマとセミコロンで分離してカテゴリ化するしているようです。そこで、ヘルプDBのカテゴリを修正します(確認を兼ねていますので、分離記号をあえてそろえていません)。

ついでにその他のヘルプ系のDBのプロパティも同様に修正し、Catalog タスクを実行します。すると、次のような結果となり、複数のカテゴリにヘルプDBが表示されます。


この機能を利用すれは、利用者の部門や事業所、アプリケーションの種類など、さまざまな切り口でアプリケーションを分類・整理できます。複数のカテゴリに対応しているあたりが、かゆいところに手が届いていていいですね。


2024/06/19

アプリケーションカタログ とは?

Domino サーバ内のアプリケーションデータベースをどのように管理されてますでしょうか? 

Domino サーバには標準でサーバ内のアプリケーションを管理する機能が存在します。今回は、『アプリケーションカタログ』というその機能を紹介します。

なお、nsf をデータベースと呼んできた時代には、『データベースカタログ』と呼んでいました。


アプリケーションカタログの概要

Domino サーバ内には、catalog.nsf というアプリケーションが存在します。これを開くとサーバ内のアプリケーションの一覧が確認できます。例えば、[データベース名]を開くと名称でカテゴライズされたビューが開きます。


文書を開くとデータベースの様々な情報が確認できます。


まず、アプリケーション タブには、名称だけでなく、配置されているサーバ名、ファイル名、レプリカIDまで記録されています。ほかには、文書数やDBのファイルサイズ、作成日などもあります。

タブの最下部には、使用状況が表示されています。

また、アクセス制御リストタブには ACL の設定が列挙されています。

アプリケーションに関する情報が集約されて記録されていますので、さまざまな用途で利用できそうですね。


カタログ作成の仕組み

アプリケーションカタログを作成するには、サーバ上で Catalog タスクを実行します。実行するとそのサーバ内にあるすべてのデータベースがカタログに登録されます。

もし、サーバに catalog.nsf が存在しない場合には、 catalog.ntf から自動的に作成されます。

Domino サーバのデフォルトでは、午前 1 時に Catalog タスクが実行されます。これは、サーバの notes.ini に以下の行が記述されているからです。

ServerTasksAt1=Catalog,Design


カタログの表示

Catalog タスクは、メールやテンプレートをを含む、サーバ内のすべてのアプリケーションの情報を収集して記録します。

ただし、 プロパティの[設計]タブで『データベースカタログに表示』にチェックされているものだけがビューに表示される仕組みになっています。

この設定をうまく利用すると、一般利用者通常使用するアプリだけをリストアップすることができます。しかも、データ収集はサーバが自動で行ってくれますので便利ですね。


まとめ

カタログ文書を開くと上部に[開く]ボタンがあります。クリックするとそのアプリケーションが開きます。うまく使えば、アプリの一覧をお手軽に作成できそうですね。


2024/06/17

すべての LotusScript をリコンパイルは ”すべて” ではない !?

このブログでは、汎用的な関数など共通の関数やクラスなどはスクリプトライブラリで管理し、各アプリケーションではそれを利用する方法をお薦めしています。プログラムの独立性の向上や分業化など開発効率が上がると考えているからです。

今回はスクリプトライブラリを使用した環境で、気がついた障害(?)と注意点についてまとめます。


すべての LotusScript をリコンパイル

Domino デザイナーのメニューには[ツール]-[すべての LotusScript をリコンパイル]があります。一般的に、スクリプトライブラリに変更があった場合など、LotusScript のプログラム全体をチェックしたい場合に利用します。実行すると開発中のアプリケーション内のすべての LotusScript に対して文法的な整合性チェックを行います。

ライブラリの新バージョンがリリースされてそれを開発中のアプリに組み込んだ時、ライブラリ内の関数のインタフェース(引数など)を修正した場合に利用すると便利な機能です。


発見した問題と再現方法

先日、この『すべての LotusScript をリコンパイル』という機能が、すべてのコードを対象にしていないという問題を発見しました。

まずは、現象の再現です。

次のような単純なスクリプトライブラリとそれを利用するビューのアクションボタンを作成します。


プリビューして、ボタンをクリックすると ”テスト” とメッセージが表示されます。当たり前ですが...

この状態で、スクリプトライブラリを下記の通り、引数を削除して、メッセージを固定の文字列に変更して保存します。

Option Declare

Public Function ShowMsg()
   MsgBox "テスト", 64
End Function

この状態で「すべての LotusScript をリコンパイル」を実行します。引数が合わないので文法エラーとなるべきところなのですが、正常に終了してしまいます。

ただ、コンパイルが成功したからと言って、ノーツからそのボタンを押すとエラーが発生します。

エラーメッセージには、引数が正しくないことと関数名が表示されていますので、この現象はコンパイルの機能に問題があるということになりますね。


問題の詳細と対策

調査した結果この現象は、Notes 6 のころから発生している既知の問題(問題報告番号 GFLY5VWM3C)で、現在(14.0)でも発生するそうです。詳細が以下のサポート情報に掲載されていますのでご確認ください。

すべての LotusScript をリコンパイルを実施してもアクションボタンの LotusScript が精査されない

Workaround として、エラーが出るべき設計要素をデザイナーで編集し、再保存するタイミングでエラーが検知されるので取り除く、と紹介されています。設計数が多い時には少々つらい対策ですね。

現時点で開発者が注意すべきは「すべての LotusScript をリコンパイル」機能を過信しないことになります。今回事例にあげた引数の変更以外に、サポート情報にある関数名の不一致なども検知できないようです。アプリ利用時に文法エラーのような基本的なエラーに出くわした場合、この問題を疑ってみるべきかもしれませんね。

ちなみに、修正は『問題の重要度やリクエスト数など複数の要素で勘案される』そうです。開発ツールとして恥ずかしいレベルの問題と思うので、勘案している場合じゃないぐらい重要度は高いと感じますけどね...


2024/06/08

クラス化に挑戦: #12)クラス化作業のまとめ

前回まで 6 回にわたり、Google マップ の Place API の検索機能を題材にクラス化する作業を体験しました。結果を振り返りながら、クラス化の作業について整理しましょう。

改めて、今回作成したライブラリをデザイナーで確認してみます。全体を眺めると見えてくることがあります。

カプセル化

まず、最初に感じるのはスッキリ感ですね。

クラスを使用しない開発の場合、ライブラリに関数が増えてくると、煩雑になり、必要なものを探すのに苦労するようになります。名称順に並んではくれますが、機能的関連性はわかりません。名称を工夫する必要が出てきますが、数が多くなると悩ましくなってきます。

クラスは階層化して表示されます。そして、その階層の中にはクラスに関係があるものが集約されています。整理された状態になっており、気持ちがいいですね。

このように集約してまとめることをオブジェクト指向の世界では『カプセル化』というようです。


インターフェースの明確化と隠蔽

デザイナーでは Private な関数や変数には黄色の■がアイコン表示されています。これが付いていないものが Public となります。このマークを見れば、インターフェースとなるプロパティやメソッドがわかるということですね。

インターフェースを明確にするのは、不用意にデータにアクセスさせないなど、クラスが持つ機能やデータを安全に利用することが目的です。

プロパティで入力チェックを行い合格したデータだけを採用(メンバ変数にセット)したり、内部で利用するだけの関数を Private 化するなど、クラスの利用者が想定外の操作をしないようにして、安全性を高めます。このような考え方を『隠蔽』といいます。


命名規則

インターフェースとなるプロパティやメソッドは Count や Search など簡潔で端的な名称としています。クラス内に作成するメンバ変数や Private な関数には接頭文字として z をつけており、一覧で下の方に集まるようにしています。

結果的に、インターフェースが上に集まり目立つということですね。

複数のクラスで使用しそうな汎用的な関数(xGetElementByName_Obj や xGetLocation)はクラス外で定義されています。クラス外であることがわかるよう接頭文字は x としています。

関数の命名を少し工夫するだけで、さらにわかりやすいプログラムになりますね。


デバッガとクラス

クラスを利用した開発でデバッガを利用するには注意が必要です。

まずは不便な点、下図のイベント欄です。

クラスの名称や実行中の関数などが表示されず Declarations と表示されています。実際には NearBySearch クラスの Search メソッドを実行中なのですが表示されていません。

ステップ実行して確認するだけであれば、あまり気になりませんが、クラス内の Private 関数にブレークポイントをセットする場合など、クラス内を横断的に見たいときには、その場所を探すが大変です。

イベント欄にクラスを表示して、クラスを選択したら右にクラス内の関数を表示するなど、改善してほしいですね。

Notes 8 以降、スタンダード版のデザイナーが提供されるようになって、クラスが階層化して表示されるなど、クラス開発の効率がずいぶん上がりました。ただ、デバッガの機能は進化がなく旧来のままとなっています。機能強化が待たれますね。


デバッガの変数のタブは見方に少し注意がが必要です。下図は NearBySearch クラスの Search メソッドを実行中の、変数タブの状態です。

関数内の変数に混ざって、ME という変数があります。これが、Search メソッドを実行してるクラスのインスタンス(自分自身)を表します。中を確認すると、クラスのメンバ変数とその値が確認できます。NotesDocument などノーツオブジェクトクラスの場合はプロパティの値が見えますが、ユーザ定義クラスではプロパティとしては確認できません。

なお、3 列目の型には NEARBYSEARCH とクラス名が表示されています。また、zoLocation のようにメンバ変数内にユーザ定義クラスのインスタンスがある場合、そのメンバ変数がさらに階層化されて表示されます。


前回 クラス化に挑戦


2024/06/07

クラス化に挑戦: #11)Google マップ - Place API の NearBySearch をクラス化 ③

Google マップ の Place API の検索機能のクラス化に挑戦する第3回です。前回でクラスが出来上がったので、今回はそのクラスを利用してみます。


テストエージェントの作成

第 8 回 に作成したテストエージェントと同様の機能を今回作成した NearBySearch クラスを使用して実現します。

せっかくですから、今回追加した新機能を使ってみましょう。検索結果のすべての地点を順に表示するため、ヒットした件数でループさせ、順に地点情報を取得してみます。

Option Declare
Use "lsGoogleMAP"

Sub Initialize
   Dim dLat As Double '緯度
   Dim dLng As Double '経度
   Dim oLocation As Location
   Dim oSearch As NearBySearch
   Dim oPlace As Place
   Dim i As Integer

   dLat = 34.683742526906634
   dLng = 135.49698067096077
   Set oLocation = New Location(dLat, dLng)
   
   ' 検索準備
   Set oSearch = New NearBySearch(oLocation)
   oSearch.Keyword = "鳥貴族"

   ' 検索実行
   If oSearch.Search() Then
       ' すべての検索結果を近い順に表示
       For i = 1 To oSearch.Count
         Set oPlace = oSearch.GetPlace_Nth(i)
         MsgBox CStr(i) & " 番目に近い店舗 = " & oPlace.PlaceName, 64
      Next
   End If
End Sub

実行すると、検索地点(本町駅)を中心に近い店舗が順に表示されます。大阪には鳥貴族がいっぱいありますね(笑)。

それはさて置き、正しく表示されれば、クラス化は成功です。


後片付け

クラス化作業は終了しましたが、元となったエージェントで不要となった関数が残っていますので掃除します。第 8 回 に作成した関数を含め、次の 4 つの関数が不要ですので削除します。

最終的にライブラリをデザイナーで確認すると、以下のようになります。ずいぶんすっきりしましたね。


なお、この作業を行うと 第 8 回 で作成したテストエージェントは動作しなくなりますのでご了承ください。



前回 クラス化に挑戦


2024/06/06

クラス化に挑戦: #10)Google マップ - Place API の NearBySearch をクラス化 ②

Google マップ の Place API の検索機能のクラス化に挑戦する第2回です。今回は、検索メソッドを NearBySearch クラスに追加します。


検索機能作成の方針

第 8 回 に作成した GetNearestPlace とその関連関数を NearBySearch クラス内に移植します。

この関数は、検索を実行して、一番近い場所を返す関数でした。今回クラス化するにあたり、検索の実行と n 番目に近い場所を返す機能に分離したいと思います。

まずは、検索結果を保持するためのメンバ変数を作成します。

   Private zjnavResults As NotesJSONNavigator   '検索結果
   Private zjaResults As NotesJSONArray   '検索結果(地点情報の配列)


検索メソッドの作成

それでは、検索を実行するメソッドを作成します。GetNearestPlace をベースに検索して結果をメンバ変数に保持するまでがこのメソッドの役割です。

以下がサンプルプログラムです。赤字の部分が修正箇所となります。

   Public Function Search() As Boolean
      Dim sURL As String
      Dim sPram As String
      Dim http As NotesHTTPRequest
      Dim jnav As NotesJSONNavigator
      Dim jeResults As NotesJSONElement

      If zoLocation Is Nothing Then Exit Function
      On Error GoTo Proc_Err


      'URL の準備
      sURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
      sPram = zxGetPram()
      sURL = sURL & "?" & sPram

      'API に接続しレスポンスを JSON で取得
      Set http = xns.CreateHttpRequest()
      http.PreferJSONNavigator = True
      Set jnav = http.Get(sURL)

      '検索結果を取得
      Set jeResults = jnav.GetElementByName("results")
      If jeResults.Type = Jsonelem_type_array Then
         '検索結果をメンバ変数に保存
         Set zjnavResults = jnav
         Set zjaResults = jeResults.Value
         Search = True
      End If

Proc_Exit:
      Exit Function

Proc_Err:
      Resume Proc_Exit

   End Function

主な作業内容は2つです。

まず、検索に必要な情報は、前回の作業でクラス内(メンバ変数)に保持されています。保持した値を利用するので、関数に引数で渡す必要がなくなりますので、引数が各所で省略されています。

もう一点がエラー処理です。クラス内のエラーはクラス内で処理する前提で、エラー発生時はメソッドの戻り値を False とし、検索結果数を 0 となるようにしています。


また、このメソッドでは zxGetPram というサブ関数をコールしています。API コール時の URL パラメータを作成する関数で、ベースとなるのは xGetPram 関数です。

クラスへの移植にあたり修正した箇所を赤字としています。

   Private Function zxGetPram() As String
      Dim s As String
      Dim v As Variant

      s = "key=" & GoogleAPIKey

      '座標の指定
      s = s & "&" & "location=" & CStr(zoLocation.Latitude)
      s = s & "," & CStr(zoLocation.Longitude)

      '検索キーワードの指定
      If zsKeyword <> "" Then
         v = Evaluate(|@URLEncode("UTF-8"; "| & zsKeyword & |")|)
         s = s & "&" & "keyword=" & v(0)
      End If

      'プレイスタイプの指定

      If zsType <> "" Then
         v = Evaluate(|@URLEncode("UTF-8"; "| & zsType & |")|)
         s = s & "&" & "types=" & v(0)
      End If


      '固定パラメータの指定

      s = s & "&" & "language=ja"
      s = s & "&" & "rankby=distance"

      zxGetPram = s
   End Function

メンバ変数を使用する修正以外では、プレイスタイプ(zsType)を URL パラメータに付加する機能を追加しています。


検索結果を返すメソッド

最後に、検索結果から地点情報を返すメソッドを作成します。初めに記載したように n 番目に近い情報を取得できるメソッド GetPlace_Nth として作成します。

   Public Function GetPlace_Nth(ByVal viIndex As Integer) As Place
      Dim jePlace As NotesJSONElement

      'エラーチェック
      If zjaResults Is Nothing Then Exit Function
      If viIndex < 1 Then Exit Function
      If zjaResults.Size < viIndex Then Exit Function

      'n 番目の地点情報を取得
      Set jePlace = zjaResults.GetNthElement(viIndex)

      '地点情報からPlaceインスタンスを取得して返す
      Set GetPlace_Nth = New Place(jePlace)
   End Function


また、ヒットした件数を返すプロパティも併せて作成します。

   Public Property Get Count As Integer
      On Error Resume Next
      Count = zjaResults.Size
   End Property

なお、このプロパティでは、メンバ変数 zjaResults が Nothing である可能性があるので、エラーを無視するようにしています。


次回の予定

これで NearBySearch クラスは完成です。次回はこのクラスを組み込んでテストします。


前回 クラス化に挑戦 次回


2024/06/05

クラス化に挑戦: #9)Google マップ - Place API の NearBySearch をクラス化 ①

前回までは Google マップ の Place API の検索結果をクラス化してみました。要は検索結果の1件分を表すクラスでしたね。今回からは検索機能本体のクラス化に挑戦します。

作成するのは、NearBySearch クラスです。API の名称そのままとしています。今回はこのクラスで、検索前に必要な情報を管理する機能を作成します。


クラスと初期化の作成

NearBySearch で一番重要な情報は、検索の位置情報です。これがないと検索が成立しません。ですので、NearBySearch クラスでは検索位置を引数に初期化することとします。

クラス全体の定義を含め、コンストラクタである New メソッドを記述すると次の通りです。

Public Class NearBySearch
   Private zoLocation As Location

   Sub New(voLocation As Location)
      If Not(voLocation Is Nothing) Then
         Set zoLocation = voLocation
      End If
   End Sub
End Class

引数に検索位置を示す Location が指定されています。念のためではありますが Nothing でなければメンバ変数に保持するようにしています。


プロパティの作成

続いて必要なプロパティを作成します。作成するのは以下のプロパティです。

Location 取得のみ 検索位置の座標
SearchType 取得と設定 検索する場所の種類
Keyword 取得と設定 検索キーワード

NearBySearch クラスに追加するプログラムは次の通りです。

まず、メンバ変数を2つ追加します。

   Private zsKeyword As String
   Private zsType As String

続いて、次のプロパティを作成します。

   Public Property Get Location As Location
      Set Location = zoLocation
   End Property

   Public Property Set Keyword As String
      zsKeyword = Keyword
   End Property
   Public Property Get Keyword As String
      Keyword = zsKeyword
   End Property

   Public Property Get SearchType As String
      SearchType = zsType
   End Property
   Public Property Set SearchType As String
      zsType = SearchType
   End Property


次回の予定

これで検索までに必要な情報を管理する機能ができました。次回はこのクラスに検索メソッドを追加します。


前回 クラス化に挑戦 次回


2024/05/30

クラス化に挑戦: #8)Google マップ - Place API の結果をクラス化 ③

Google マップ の Place API の検索結果をクラス化してみる企画の 3 回目です。前回作成したクラスを実際に組み込んでテストします。


検索用関数の準備

現在のライブラリの状態は下図の通りです。一番近い場所を検索する xGetNearestPlaceName 関数は、エージェントから移行したままの状態です。これをクラスに対応し、利用できるようにします。

修正の方針は、

  1. 外部からアクセスできるように Public 化する
  2. 戻り値を名前(文字列)ではなく、Place のインスタンスに変更

とします。

修正後の関数は次の通りです。赤字が修正箇所となっています。

Public Function GetNearestPlace(ByVal vdLat As Double, vdLng As Double, _
                                                                                  ByVal vsKeyword As String) As Place
   Dim sURL As String
   Dim sPram As String
   Dim http As NotesHTTPRequest
   Dim jnav As NotesJSONNavigator
   Dim jeResults As NotesJSONElement
   Dim jePlace As NotesJSONElement

   'URL の準備
   sURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
   sPram = xGetPram(vdLat, vdLng, vsKeyword)
   sURL = sURL & "?" & sPram

   'API に接続しレスポンスを JSON で取得
   Set http = xns.CreateHttpRequest()
   http.PreferJSONNavigator = True
   Set jnav = http.Get(sURL)

   '一番近隣の地点情報を取得
   Set jeResults = jnav.GetElementByName("results")
   Set jePlace = xGetPlace_Nth(jeResults, 1)

   '地点情報からPlaceインスタンスを取得して返す
   Set GetNearestPlace = New Place(jePlace)
End Function

関数の戻り値の型が作成したクラス Place となっています。Plase のインスタンス、ようはオブジェクトを返すので戻り値のセットには Set が必要となります。


テストエージェントの作成

ライブラリの準備が整いましたので、テストエージェントを作成します。

Option Declare
Use "lsGoogleMAP"

Sub Initialize
   Dim dLat As Double '緯度
   Dim dLng As Double '経度
   Dim oPlace As Place

   dLat = 34.683742526906634
   dLng = 135.49698067096077

   Set oPlace = GetNearestPlace(dLat, dLng, "鳥貴族")
   MsgBox oPlace.PlaceName, 64
End Sub

もととなったエージェントの Initialize とほぼ同等です。ポイントとなるのは赤字の部分となります。

検索結果が Place クラスのインスタンスとなりますので、それを受けるためのオブジェクト変数 oPlace を利用しています。また、メッセージボックスでは、PlaceName プロパティを取得して表示しています。

座標にアクセスしたい場合は、次のように記述すれば OK です。

MsgBox oPlace.Location.Latitude, 64


前回 クラス化に挑戦 次回


2024/05/29

クラス化に挑戦: #7)Google マップ - Place API の結果をクラス化 ②

Google マップ の Place API の検索結果をクラス化してみる企画の 2 回目です。いよいよ具体的なコーディングに入ります。


位置クラス

Google マップ の 検索結果や GPS など地図上の位置情報を使用するには緯度と経度を使用します。まずはこれを管理する位置クラス Location を作成します。クラス初期化時に緯度と経度を与え、それをメンバ変数で保持し、プロパティから参照できるとても単純なクラスです。

サンプルコードは次の通りです。

Public Class Location
   Private zdLatitude As Double '緯度
   Private zdLongitude As Double '経度

   Public Sub New(ByVal vdLatitude As Double, ByVal vdLongitude As Double)
      zdLatitude = vdLatitude
      zdLongitude = vdLongitude
   End Sub

   Public Property Get Latitude As Double
      Latitude = zdLatitude
   End Property

   Public Property Get Longitude As Double
      Longitude = zdLongitude
   End Property
End Class

この程度であれば、クラス化する必要性はないかも知れません。サンプルの提示という側面もありますが、緯度・経度の入力チェックなど今後の拡張を考えて、クラスを採用しています。


場所クラス

続いてが本題である検索結果の 1 件分を表すクラスです。検索結果の JSON より場所の情報を取得してプロパティとして参照できる単純な仕様とします。

作成するプロパティは、とりあえず 3 つです。

PlaceID Google Place データベースで一意に表す ID
PlaceName 場所の名称
Location 場所の座標

まずは、クラスの大枠を作成します。クラスを定義し、メンバ変数とプロパティを作成します。

Public Class Place
   Private zsPlaceID As String
   Private zsName As String
   Private zoLocation As Location

   Public Property Get PlaceID As String
      PlaceID = zsPlaceID
   End Property

   Public Property Get PlaceName As String
      PlaceName = zsName
   End Property

   Public Property Get Location As Location
      Set Location = zoLocation
   End Property
End Class


場所クラスの初期化

続いてコンストラクタを作成します。

Place API の検索結果 result は配列となっていました。その 1 要素分を表す JSON が New メソッドの引数となる前提で作成します。JSON から取得した値はそれぞれのメンバ変数に格納しています。

   Sub New(vjePlace As NotesJSONElement)
      Dim jobjPlace As NotesJSONObject
      Dim jobj As NotesJSONObject
      Dim je1 As NotesJSONElement
      Dim je2 As NotesJSONElement

      Set jobjPlace = vjePlace.Value

      'プレースID
      Set je1 = xGetElementByName_Obj(jobjPlace, "place_id")
      If Not(je1 Is Nothing) Then
         zsPlaceID = je1.Value
      Else
         zsPlaceID = ""
      End If

      '場所の名称
      Set je1 = xGetElementByName_Obj(jobjPlace, "name")
      If Not(je1 Is Nothing) Then
         zsName = Trim(je1.Value)
      Else
         zsName = ""
      End If

      '場所の座標
      Set je1 = xGetElementByName_Obj(jobjPlace, "geometry")
      If Not(je1 Is Nothing) Then
         Set jobj = je1.Value
         Set je2 = xGetElementByName_Obj(jobj, "location")
         Set zoLocation = xGetLocation(je2)
      End If
   End Sub


この処理では 2 つのサブ関数を利用しています。

1 つ目が xGetElementByName_Obj 関数です。JSON 内のエレメントを名称で検索機能なのですが、NotesJSONObject の GetElementByName メソッドは検索にヒットしない場合エラーを返します。メインルーチンでエラー処理を書くと煩雑になるで関数化しています。エラーの場合は Nothing を返す仕様ということですね。

Function xGetElementByName_Obj(vjobj As NotesJSONObject, _
                                                       ByVal vsName As String) As NotesJSONElement
   Dim je As NotesJSONElement

   On Error GoTo ErrProc
   Set je = vjobj.GetElementByName(vsName)

ExitProc:
   Set xGetElementByName_Obj = je
   Exit Function

ErrProc:
   Resume ExitProc
End Function


2 つ目のサブ関数は今回作成した Location のインスタンスを返す関数です。

JSON を確認すると座標を表す項目がいくつもあります。今回は location で指定されている座標を使用していますが、汎用的に使用できるよう関数化しています。

関数は次の通りです。

Private Function xGetLocation(vjeLocation As NotesJSONElement) As Location
   Dim jobj As NotesJSONObject
   Dim jeLat As NotesJSONElement
   Dim jeLng As NotesJSONElement
   Dim dLat As Double
   Dim dLng As Double

   If Not(vjeLocation Is Nothing) Then
      Set jobj = vjeLocation.Value
      Set jeLat = xGetElementByName_Obj(jobj, "lat")
      dLat = CDbl(jeLat.Value)
      Set jeLng = xGetElementByName_Obj(jobj, "lng")
      dLng = CDbl(jeLat.Value)

      Set xGetLocation = New Location(dLat, dLng)
   End If
End Function


ちなみに、この関数を利用している New メソッドでは以下のようになっていました。

location のエレメントを取得してこの関数に渡しているので、location の位置情報を保持させているということですね。

   Sub New(vjePlace As NotesJSONElement)
         ・・・
      '場所の座標
      Set je1 = xGetElementByName_Obj(jobjPlace, "geometry")
      If Not(je1 Is Nothing) Then
         Set jobj = je1.Value
         Set je2 = xGetElementByName_Obj(jobj, "location")
         Set zoLocation = xGetLocation(je2)

      End If
   End Sub


ライブラリの状態

ここまでの作業が完了するとライブラリの状態は以下のようになっています。今回作成した部分は赤枠の部分となります。

次回はこのクラスを実際に使用してみましょう。

前回 クラス化に挑戦 次回