Как разобрать ответ json в VBA из запроса на получение [дублировать]

Вы используете объект, содержащий ссылку нулевого значения. Таким образом, он дает пустое исключение. В примере строковое значение равно null, и при проверке его длины произошло исключение.

Пример:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

Ошибка исключения:

Необработанное исключение:

System.NullReferenceException: ссылка на объект не установлена ​​в экземпляр объекта. в Program.Main ()

20
задан Joel Coehoorn 19 March 2012 в 02:35
поделиться

5 ответов

Объект JScriptTypeInfo является немного неудачным: он содержит всю необходимую информацию (как вы можете видеть в окне Watch ), но с VBA это невозможно сделать.

Если экземпляр JScriptTypeInfo ссылается на объект Javascript, For Each ... Next не будет работать. Тем не менее, он работает, если он ссылается на массив Javascript (см. Функцию GetKeys ниже).

Итак, обходным путем является повторное использование механизма Javascript для получения информации, которую мы не можем с VBA. Прежде всего, есть функция, чтобы получить ключи от объекта Javascript.

Как только вы знаете ключи, следующая проблема заключается в доступе к свойствам. VBA не поможет, если имя ключа известно только во время выполнения. Таким образом, существует два метода доступа к объекту объекта: один для значений, а другой для объектов и массивов.

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

Примечание:

  • В коде используется раннее связывание. Поэтому вам нужно добавить ссылку на «Microsoft Script Control 1.0».
  • Вы должны вызвать InitScriptEngine один раз, прежде чем использовать другие функции, чтобы выполнить некоторую базовую инициализацию.
28
ответ дан Codo 26 August 2018 в 23:15
поделиться

Супер простой ответ - через силу 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
3
ответ дан Community 26 August 2018 в 23:15
поделиться

Я знаю, что уже поздно, но для тех, кто не знает, как использовать VBJSON , вам просто нужно:

1) Импортировать JSON.bas в свой проект ( Открыть редактор VBA, Alt + F11; Файл> Файл импорта)

2) Добавить словарь / класс для словаря Только для Windows используйте ссылку «Время выполнения сценариев Microsoft»

Вы можете также используйте VBA-JSON таким же образом, который специфичен для VBA вместо VB6 и имеет всю документацию.

0
ответ дан Lionel T. 26 August 2018 в 23:15
поделиться

Ответ Codo велик и образует основу решения.

Однако знаете ли вы, что CallByName VBA позволяет вам довольно подробно обращаться к структуре JSON. Я просто написал решение в Сведения о Google Местах в Excel с VBA для примера.

На самом деле просто переписал его, не используя функции, добавляющие 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 Maps в Детали Google Places для Excel с VBA

3
ответ дан S Meaden 26 August 2018 в 23:15
поделиться

Поскольку 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
1
ответ дан SIM 26 August 2018 в 23:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: