25

以下の例では...解析されたJSON文字列からオブジェクトをループすると、「オブジェクトはこのプロパティまたはメソッドをサポートしていません」というエラーが返されます。誰かがこれを機能させる方法をアドバイスできますか?非常に感謝しています(私はここで尋ねる前に答えを探すのに6時間を費やしました)。

JSON文字列をオブジェクトに解析する関数(これは問題なく機能します)。

Function jsonDecode(jsonString As Variant)
    Set sc = CreateObject("ScriptControl"): sc.Language = "JScript" 
    Set jsonDecode = sc.Eval("(" + jsonString + ")")
End Function

解析されたオブジェクトをループすると、「オブジェクトはこのプロパティまたはメソッドをサポートしていません」というエラーが返されます。

Sub TestJsonParsing()
    Dim arr As Object 'Parse the json array into here
    Dim jsonString As String

    'This works fine
    jsonString = "{'key1':'value1','key2':'value2'}"
    Set arr = jsonDecode(jsonString)
    MsgBox arr.key1 'Works (as long as I know the key name)

    'But this loop doesn't work - what am I doing wrong?
    For Each keyName In arr.keys 'Excel errors out here "Object doesn't support this property or method"
        MsgBox "keyName=" & keyName
        MsgBox "keyValue=" & arr(keyName)
    Next
End Sub 

PS。私はすでにこれらのライブラリを調べました:

--vba-json例を機能させることができませんでした。
--VBJSON vbaスクリプトは含まれていません(これは機能する可能性がありますが、Excelにロードする方法がわからず、最小限のドキュメントがあります)。

また、多次元で解析されたJSON配列にアクセスすることは可能ですか?基本的なキー/値配列ループを機能させるだけで素晴らしいでしょう(質問が多すぎる場合は申し訳ありません)。ありがとう。


編集:vba-jsonライブラリを使用した2つの実用的な例を次に示します。上記の質問はまだ謎です...

Sub TestJsonDecode() 'This works, uses vba-json library
    Dim lib As New JSONLib 'Instantiate JSON class object
    Dim jsonParsedObj As Object 'Not needed

    jsonString = "{'key1':'val1','key2':'val2'}"
    Set jsonParsedObj = lib.parse(CStr(jsonString))

    For Each keyName In jsonParsedObj.keys
        MsgBox "Keyname=" & keyName & "//Value=" & jsonParsedObj(keyName)
    Next

    Set jsonParsedObj = Nothing
    Set lib = Nothing
End Sub

Sub TestJsonEncode() 'This works, uses vba-json library
    Dim lib As New JSONLib 'Instantiate JSON class object
    Set arr = CreateObject("Scripting.Dictionary")

    arr("key1") = "val1"
    arr("key2") = "val2"

    MsgBox lib.toString(arr)
End Sub
4

6 に答える 6

31

JScriptTypeInfoオブジェクトは少し残念です。関連するすべての情報が含まれていますが([ウォッチ]ウィンドウで確認できます、VBAで取得することは不可能のようです。

JScriptTypeInfoインスタンスがJavascriptオブジェクトを参照している場合、は機能しFor Each ... Nextません。ただし、Javascript配列を参照している場合は機能します(以下のGetKeys関数を参照)。

したがって、回避策は、Javascriptエンジンを再度使用して、VBAでは取得できない情報を取得することです。まず、Javascriptオブジェクトのキーを取得する関数があります。

キーがわかったら、次の問題はプロパティにアクセスすることです。キーの名前が実行時にのみわかっている場合も、VBAは役に立ちません。したがって、オブジェクトのプロパティにアクセスする方法は2つあります。1つは値用で、もう1つはオブジェクトと配列用です。

Option Explicit

Private ScriptEngine As ScriptControl

Public Sub InitScriptEngine()
    Set ScriptEngine = New ScriptControl
    ScriptEngine.Language = "JScript"
    ScriptEngine.AddCode "function getProperty(jsonObj, propertyName) { return jsonObj[propertyName]; } "
    ScriptEngine.AddCode "function getKeys(jsonObj) { var keys = new Array(); for (var i in jsonObj) { keys.push(i); } return keys; } "
End Sub

Public Function DecodeJsonString(ByVal JsonString As String)
    Set DecodeJsonString = ScriptEngine.Eval("(" + JsonString + ")")
End Function

Public Function GetProperty(ByVal JsonObject As Object, ByVal propertyName As String) As Variant
    GetProperty = ScriptEngine.Run("getProperty", JsonObject, propertyName)
End Function

Public Function GetObjectProperty(ByVal JsonObject As Object, ByVal propertyName As String) As Object
    Set GetObjectProperty = ScriptEngine.Run("getProperty", JsonObject, propertyName)
End Function

Public Function GetKeys(ByVal JsonObject As Object) As String()
    Dim Length As Integer
    Dim KeysArray() As String
    Dim KeysObject As Object
    Dim Index As Integer
    Dim Key As Variant

    Set KeysObject = ScriptEngine.Run("getKeys", JsonObject)
    Length = GetProperty(KeysObject, "length")
    ReDim KeysArray(Length - 1)
    Index = 0
    For Each Key In KeysObject
        KeysArray(Index) = Key
        Index = Index + 1
    Next
    GetKeys = KeysArray
End Function


Public Sub TestJsonAccess()
    Dim JsonString As String
    Dim JsonObject As Object
    Dim Keys() As String
    Dim Value As Variant
    Dim j As Variant

    InitScriptEngine

    JsonString = "{""key1"": ""val1"", ""key2"": { ""key3"": ""val3"" } }"
    Set JsonObject = DecodeJsonString(CStr(JsonString))
    Keys = GetKeys(JsonObject)

    Value = GetProperty(JsonObject, "key1")
    Set Value = GetObjectProperty(JsonObject, "key2")
End Sub

ノート:

  • コードは早期バインディングを使用します。したがって、「MicrosoftScriptControl1.0」への参照を追加する必要があります。
  • InitScriptEngine基本的な初期化を行うには、他の関数を使用する前に1回呼び出す必要があります。
于 2011-09-04T17:34:52.277 に答える
7

Codoの答えは素晴らしく、ソリューションのバックボーンを形成しています。

ただし、VBAのCallByNameを使用すると、JSON構造のクエリをかなり実行できることをご存知でしたか。例として、 GooglePlacesDetailsでVBAを使用したExcelのソリューションを作成しました。

実際には、この例のようにScriptEngineに追加する関数を使用せずに書き直しただけです。CallByNameのみを使用して配列をループすることを実現しました。

だから、説明するためのいくつかのサンプルコード

'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Option Explicit

Sub TestJSONParsingWithVBACallByName()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = New ScriptControl
    oScriptEngine.Language = "JScript"

    Dim jsonString As String
    jsonString = "{'key1':'value1','key2':'value2'}"

    Dim objJSON As Object
    Set objJSON = oScriptEngine.Eval("(" + jsonString + ")")

    Debug.Assert VBA.CallByName(objJSON, "key1", VbGet) = "value1"
    Debug.Assert VBA.CallByName(objJSON, "key2", VbGet) = "value2"

    Dim jsonStringArray As String
    jsonStringArray = "[ 1234, 4567]"

    Dim objJSONArray As Object
    Set objJSONArray = oScriptEngine.Eval("(" + jsonStringArray + ")")

    Debug.Assert VBA.CallByName(objJSONArray, "length", VbGet) = "2"

    Debug.Assert VBA.CallByName(objJSONArray, "0", VbGet) = "1234"
    Debug.Assert VBA.CallByName(objJSONArray, "1", VbGet) = "4567"


    Stop

End Sub

また、サブオブジェクト(ネストされたオブジェクト)も実行します。また、Google Places Details to ExcelwithVBAのGoogleマップの例も参照してください。

編集:Evalを使用しないでください。JSONをより安全に解析してみてください。このブログ投稿を参照してください。

于 2016-06-02T19:08:51.083 に答える
3

超簡単な答え-OOの力を通して(またはそれはjavascriptです;)あなたはいつも欲しかったitem(n)メソッドを追加することができます!

ここに私の完全な答え

Private ScriptEngine As ScriptControl

Public Sub InitScriptEngine()
    Set ScriptEngine = New ScriptControl
    ScriptEngine.Language = "JScript"
    ScriptEngine.AddCode "Object.prototype.myitem=function( i ) { return this[i] } ; "
    Set foo = ScriptEngine.Eval("(" + "[ 1234, 2345 ]" + ")") ' JSON array
    Debug.Print foo.myitem(1) ' method case sensitive!
    Set foo = ScriptEngine.Eval("(" + "{ ""key1"":23 , ""key2"":2345 }" + ")") ' JSON key value
    Debug.Print foo.myitem("key1") ' WTF

End Sub
于 2013-10-14T11:21:05.583 に答える
2

Jsonは文字列に他ならないので、構造がどんなに複雑であっても、正しい方法で操作できれば簡単に処理できます。トリックを行うために外部ライブラリやコンバーターを使用する必要はないと思います。これは、文字列操作を使用してjsonデータを解析した例です。

Sub Json_data()
Const URL = "https://api.redmart.com/v1.5.8/catalog/search?extent=2&pageSize=6&sort=1&category=bakery"
Dim http As New XMLHTTP60, html As New HTMLDocument
Dim str As Variant

With http
    .Open "GET", URL, False
    .send
    str = Split(.responseText, "category_tags"":")
End With
On Error Resume Next
y = UBound(str)

    For i = 1 To y
        Cells(i, 1) = Split(Split(str(i), "title"":""")(1), """")(0)
        Cells(i, 2) = Split(Split(str(i), "sku"":""")(1), """")(0)
        Cells(i, 3) = Split(Split(str(i), "price"":")(1), ",")(0)
        Cells(i, 4) = Split(Split(str(i), "desc"":""")(1), """")(0)
    Next i
End Sub
于 2017-06-16T19:15:09.437 に答える
2

そのため、2020年でありながら、エンドツーエンドのソリューションが不足しているため、このスレッドに出くわしました。それは役に立ちましたが、実行時にキーなしで動的にデータにアクセスする必要がある場合、上記の答えは、目的のデータを取得するためにさらにいくつかの調整が必要です。

私はついに、VBAでのこのJSON解析の問題に対するエンドツーエンドのきちんとしたソリューションを持つ関数を思いつきました。この関数の機能は、入力としてJSON文字列(任意のレベルにネストされている)を受け取り、フォーマットされた2次元配列を返すことです。この配列は、プレーンなi / jループによってさらに簡単にワークシートに移動したり、インデックスベースのアクセスが簡単なため便利に再生したりできます。

サンプル入出力

関数は、GithubリポジトリのJSON2Array.basファイルに保存されます。 JSON2Array-VB

デモ使用法のサブルーチンも.basファイルに含まれています。VBAモジュールにファイルをダウンロードしてインポートしてください。お役に立てば幸いです。

于 2020-05-16T19:24:26.160 に答える
0

遅いことは知っていますが、 VBJSONの使い方がわからない人は、次のことを行う必要があります。

1)JSON.basをプロジェクトにインポートします(VBAエディターを開き、Alt +F11;ファイル>ファイルのインポート)

2)辞書参照/クラスの追加Windowsのみの場合、「MicrosoftScriptingRuntime」への参照を含めます

VBA-JSONも同じように使用できます。これは、VB6ではなくVBAに固有であり、すべてのドキュメントが含まれています。

于 2017-03-22T19:17:01.297 に答える