ExcelでJSONを扱いたいときなんですが、基本的には「データの取得と変換」で取り込むのが一番簡単だと思います。(これは記事の最後の方で記載します)
しかし、「VBAでRESTAPIに対してリクエストを投げて色々解析して処理を分岐させたい」とかなってくるとコード内でJSONをパースしたくなります。
その方法などについて記載をしてみたいと思います。
ScriptControlは64bit環境で動かない
Webで「VBA JSON パース」と検索すると、ほとんどのページでScriptControlを使用したロジックが紹介されます。
以下のような感じですね。
Private Sub test()
Dim js As Object
Dim jsonObj As Object
Set js = CreateObject("ScriptControl")
js.Language = "JScript"
js.AddCode "function Parse(str) { return eval('(' + str + ')'); };"
Set jsonObj = js.CodeObject.Parse("{""name"":""value""}")
End Sub
しかし自分の環境で上記コードを試すと以下のエラーになってしまいます。
実行時エラー’-2147221164(80040154)’
クラスが登録されていません
これはScriptControl(MSScript.ocx)が64bit環境に存在していないためです。
代替として一番ラクなのはMITライセンスで公開されている64bit対応版のMSScript.ocxを使用することです。
https://tablacus.github.io/scriptcontrol.html
上記のページに有るダウンロードからファイルをダウンロードして、インストールするとScriptControlが使用できるようになります。
↓冒頭に書いたコードの実行結果
ちょっと見にくいですが、jsonObjという変数にパラメータがパースされて格納されていることがわかります。
しかし、この方法はすべての端末に64bit対応版のMSScript.ocxをインストールする必要があるので、ExcelVBAをクライアントに配布する場合には使用しにくいです。
VBA-JSONを使ってJSONをパースする
自作でVBAをパースする関数を作るのはかなり面倒です。(配列なども考慮しないといけないため)
そこで、他の方が作ったAPIを使用してサクッと実装するのが良いかと思います。他のサイトなどで情報を集めたところ、以下が使いやすくてよいかと思いました。
https://github.com/VBA-tools/VBA-JSON
導入方法
まず上記のGitからMasterをクローンします。Gitとか入れてねーよって人はダウンロードでもOKです。
すると、specsフォルダ内に「VBA-JSON – Specs.xlsm」というファイルがあるのでこちらを開きます。
VBEから以下の2ファイルをエクスポートします。
- JsonConverter
- Dictionary
その他のファイルは必要なのか不明…。今のところ無くても問題なく動いているので放置しています。
エクスポートしたファイルを自分のEXCELにインポートすれば準備完了です。
使い方
Sub test()
Dim Json As Object
Set Json = ParseJson("{""a"":123,""b"":[1,2,3,4],""c"":{""d"":456}}")
Debug.Print Json("a")
Debug.Print Json("b")(1)
End Sub
JsonConverter.basの中にあるParseJsonという関数でJsonを連想配列に変換することが出来ます。
連想配列で戻ってくるため、非配列項目はそのまま項目名を引数に渡してあげれば値を取得することが出来ます。上記コードのJson(“a”)の部分です。
配列項目は、配列として取得できるのでインデックスを指定すれば値を取得できます。上記コードのJson(“b”)(1)の部分です。
ちなみに存在しないパラメータを指定すると空文字が返ってくるようです。エラーにならないのは便利ですが、パラメータがあるけど空の場合と区別出来ないのは厄介な場合もありそうですね。
実行結果
「データの取得と変換」でJSONを取り込む
もっと簡単にやりたい時用に、冒頭で書いた以下の件について方法を記載しておきます。
基本的には「データの取得と変換」で取り込むのが一番簡単だと思います。(これは記事の最後の方で記載します)
例として、郵便番号検索のAPI(https://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060)から住所などの情報を取得してみたいと思います。
まずExcelのリボンから「データ→Webから」を選択します。
WebからのフォームでOKを押します。
データの変換を押します
変換タブから「解析→JSON」を選択します。
するとこんな感じで展開してくれます。
ちなみにマクロで実行することも可能ですが、その度に接続情報が作られてしまうので、ちょっと工夫が必要な気がします。
自動保存すると以下のようなコードです。
Sub Macro2()
'
' Macro2 Macro
'
'
ActiveWorkbook.Queries.Add Name:="search?zipcode=7830060", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " ソース = Csv.Document(Web.Contents(""https://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060""),[Delimiter="":"", Columns=2, Encoding=65001, QuoteStyle=QuoteStyle.None])," & Chr(13) & "" & Chr(10) & " 変更された型 = Table.TransformColumnTypes(ソース,{{""Column1"", type text}, {""Column2"", type text}})," & Chr(13) & "" & Chr(10) & " #""解析された JSON"" = Table.TransformColumns(変更された型,{{""Column1"", Json.Document}})" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & "" & _
" #""解析された JSON"""
ActiveWorkbook.Worksheets.Add
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=""search?zipcode=7830060"";Extended Properties=""""" _
, Destination:=Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [search?zipcode=7830060]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "search_zipcode_7830060"
.Refresh BackgroundQuery:=False
End With
Range("K10").Select
ActiveWorkbook.Queries.Add Name:="search?zipcode=7830060 (2)", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " ソース = Csv.Document(Web.Contents(""https://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060""),[Delimiter="":"", Columns=2, Encoding=65001, QuoteStyle=QuoteStyle.None])," & Chr(13) & "" & Chr(10) & " 変更された型 = Table.TransformColumnTypes(ソース,{{""Column1"", type text}, {""Column2"", type text}})" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & " 変更された型"
ActiveWorkbook.Worksheets.Add
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=""search?zipcode=7830060 (2)"";Extended Properties=""""" _
, Destination:=Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [search?zipcode=7830060 (2)]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "search_zipcode_7830060__2"
.Refresh BackgroundQuery:=False
End With
Range("K10").Select
End Sub
この方法は、お手軽にJSONの中身を見れて便利なのですが、配列の情報などが失われてしまうため、詳細な解析をしたい場合には向きません。
難しい処理を行う場合には使えないので、結局APIと連携したいなどと言った場合はVBA-JSONにお世話になるのが良いかなと思います。
[…] プログラマー向けEXCEL活用術ブログ 【VBA】ScriptControlを使用せずにJSONをパースする […]
[…] プログラマー向けEXCEL活用術ブログ 【VBA】ScriptControlを使用せずにJSONをパースする […]
[…] プログラマー向けEXCEL活用術ブログ 【VBA】ScriptControlを使用せずにJSONをパースする […]
[…] プログラマー向けEXCEL活用術ブログ 【VBA】ScriptControlを使用せずにJSONをパースする […]