2019年8月10日土曜日

JSON から目的の値を取り出す

画像に含まれるテキストをOCRで抽出するサービスが Google にあることを IBM Champion の小野様に教えていただきました。 


ものは試しにと LotusScript のエージェントでチャレンジしてみたのですが、不慣れな JSON に手間取ってしまったので、ここにメモとして残しておこうと思った次第です。


作成したエージェントの概要ですが、NotesStream に画像ファイルを読み込み Base64 エンコードしたものを、リクエストのボディとして渡す JSON の一部に埋め込み、NotesHTTPRequest を使って指定のエンドポイント(URL)へ JSON を POST します。返ってきた JSON から OCR で取得できたテキストを取り出して表示します。

このエージェントの中で OCR の結果が JSON 形式で戻るのですが、これが私にとってなかなか分かりづらいものでした。 戻ってきた JSON は(実際には2121行もあったのでほぼ省略しますが)次のようになっていました。
{
  "responses": [
    {
      "textAnnotations": [
        {
          "locale": "ja",
          "description": "取り出したいテキストは\nここにあります!\n",
          "boundingPoly": {
            "vertices": [・・・
            ]
          }
        },・・・
      ]
    }
  ]
}

実際に戻ってきた JSON データには、OCR で抽出できた「テキストの全体」を示すものと、「テキストの一部」を示すものがありました。今回取り出したいのはテキストの全体を示すほうです。

そして「テキスト全体」がJSONデータの中に、どうやら2か所にあることがわかりました。どちらを採用するのが正しいのかはさておき、今回はJSONデータの冒頭に見つけた、次の位置の文字列を取り出すことにしました。

「配列 "responses" の最初のエレメントである配列 "textAnnotations" の最初のエレメントにある "description"」


まずは戻ってきた JSON を NotesJSONNavigator などの V10 で追加されたJSONを処理するためのクラス群を使って目的の値を取り出します。

まず私が一つ目の値の取り込みに使用したのは次のようなコードです。変数"JSON"に上記JOSN文字列がセットされてます。

Dim ss As New NotesSession
Dim nav As NotesJSONNavigator
Dim elm As NotesJSONElement
Dim obj As NotesJSONObject
Dim arr As NotesJSONArray

Set nav = ss.CreateJSONNavigator(JSON)
Set elm = nav.Getelementbyname("responses")
Set arr = elm.Value
Set elm = arr.Getfirstelement()
Set obj = elm.Value
Set elm = obj.Getelementbyname("textAnnotations")
Set arr = elm.Value
Set elm = arr.Getfirstelement()
Set obj = elm.Value
Set elm = obj.Getelementbyname("description")
Print elm.Value


取り込みたい JSONObject の名前や配列上の位置が決まっていることが前提なので JSONElement の Type を確認することなくこのようなコードにしています。

位置が「決まっている」とはいえ、少々面倒くさいというか冗長なコードだなという印象です。


ところが、先ほどこちらの資料を読んでいたら、もっとシンプルなコードで実現できることがわかりました。

Dim ss As New NotesSession
Dim nav As NotesJSONNavigator

Set nav = ss.CreateJSONNavigator(JSON)
Set elm = nav.Getelementbypointer( "/responses/0/textAnnotations/0/description" )
Print elm.Value


NotesJSONNavigator クラスの GetElementByPointer メソッドを使うことで、ずいぶんとシンプルになりました。
このとき「配列の最初」を示す数値は「0」となります。

0 件のコメント:

コメントを投稿