私が翻弄されたのは、JSONのデータに「配列」と「連想配列」が混在することからくるものでした。
この「配列」は、
のように「値」を大括弧 [ ] で囲みます。[ "v1", "v2", "v3" ]
もうひとつの「連想配列」はというと
のように「キー」と「値」のペアを中括弧 { } で囲みます。{ "k1": "v1", "k2": "v2", "k3": "v3" }
キーと値のペアで配列を作るところは、LotusScript で例えるなら「リスト」に似ていると思います。
そして getElementByPonter メソッドを使うと、JSON 上の位置を Pointer に指定することで効率よく目的の Element から「値」を取り出すことができます。
実際のコードを示します。
※以下の環境は Community版の Notes 10.0.1 FP2 です
まずは次のような Function を用意しました。
Function getValue( json$, pointer$ ) As Variant Dim ss As New NotesSession Dim nav As NotesJSONNavigator Dim elm As NotesJSONElement Set nav = ss.Createjsonnavigator( json ) Set elm = nav.Getelementbypointer( pointer ) Select Case elm.Type Case 1, 2 '1: Object, 2: Array MessageBox "Element type is Object or Array" Case 3, 4, 5, 64 '3: String, 4: Number, 5: Boolean, 64: Empty getValue = elm.Value Case Else messagebox "undefined type" End Select End Function
配列にある2番目の値を取り出す場合、Pointer に "/1" を指定します。
JSON = |[ "v1", "v2", "v3" ]| pointer = "/1" Print getValue( JSON, pointer )
配列の最初は 0、2番目は 1、n番目は n-1 といった数字をスラッシュ"/"の右側に指定します。
連想配列では、キー "k2" の値を取り出す場合、Pointer に "/k2" を指定します。
JSON = |{ "k1": "v1", "k2": "v2", "k3": "v3" }| pointer = "/k2" Print getValue( JSON, pointer )
連想配列は、キーを人間が理解しやすい文言にしておくことで、値が取り出しやすくなります。
さて、実際の JSON では、連想配列の「値」の部分が「配列」になっている、といったように、連想配列と配列とが交互に現れたりする場合があります。
これらを区別しながら、連想配列 { } の場合は「キー」を、配列 [] の場合は「位置」を、それぞれ正しく指定しなければなりません。
前回のエントリでも示した次の JSON を見ていきます。
{ "responses": [ { "textAnnotations": [ { "locale": "ja", "description": "取り出したいテキストは\nここにあります!\n", "boundingPoly": { "vertices": [・・・ ] } } ] } ] }
ここから "description" の「値」を取り出したいので、
- 連想配列にあるキー"responses" の値(配列)の、
- その配列の最初 "0" の、
- 連想配列にあるキー "textAnnotations" の値(配列)の、
- その配列の最初 "0" の、
- 連想配列にあるキー "description"
という構造になるよう Pointer を組み立てると、次のようになります。
/responses/0/textAnnotations/0/description
ところで Pointer では、連想配列の「キー」や配列の「位置」をスラッシュ"/"で区切っていますが、「キー」にスラッシュ"/"を含む場合はどうしたら?と疑問がわきました。
「きっとバックスラッシュでエスケープするんだろうな」などと安易に試したら見事に外れてしまい...
実はこれ RFC 6901 で仕様化されていました。
スラッシュ "/" とチルダ "~" は特別な意味があることから、
"/" は "~1"
"~" は "~0"
に符号化するのだそうです。
ということで、次のように キーが "Key/0" の場合、Pointer は "/key~10" とするのが正解でした。
JSON = |{ "key/0": false, "Key/1", true }| pointer = "/key~10" Print getValue( JSON, pointer )
以下におまけとして、(私にとって?)イレギュラーだったケースを以下に示します。
JSON文字列が(指定できることが正しいかどうかはさておき)配列や連想配列ではない場合、Pointer を "" とすると取れました。
JSON = |"v1"| pointer = "" Print getValue( JSON, pointer )
連想配列の「キー」が日本語の場合、Pointer として日本語文字列を指定しても not found (コード 4843)となりました。
JSON = |["キー1", "値1", "キー2", "値2"]| pointer = "キー2" Print getValue( JSON, pointer )
「値」が真偽値( True / False )の場合、True / False の最初の文字が小文字になっていないと、 JSON を JSONNavigator へロードしたところでパースできないことを示すエラー(コード 4842)となりました。
JSON = |["1", 2, True]| 'true でないとエラーになる pointer = "/2" Print getValue( JSON, pointer )
それから、連想配列や配列の最後に余計なカンマがある場合もパースできないと叱られてしまいました...
文法は厳しくチェックされるようです。
0 件のコメント:
コメントを投稿