Вы используете объект, содержащий ссылку нулевого значения. Таким образом, он дает пустое исключение. В примере строковое значение равно null, и при проверке его длины произошло исключение.
Пример:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
Ошибка исключения:
Необработанное исключение:
System.NullReferenceException: ссылка на объект не установлена в экземпляр объекта. в Program.Main ()
blockquote>
Объект 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
Примечание:
InitScriptEngine
один раз, прежде чем использовать другие функции, чтобы выполнить некоторую базовую инициализацию. Супер простой ответ - через силу 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
Я знаю, что уже поздно, но для тех, кто не знает, как использовать VBJSON , вам просто нужно:
1) Импортировать JSON.bas в свой проект ( Открыть редактор VBA, Alt + F11; Файл> Файл импорта)
2) Добавить словарь / класс для словаря Только для Windows используйте ссылку «Время выполнения сценариев Microsoft»
Вы можете также используйте VBA-JSON таким же образом, который специфичен для VBA вместо VB6 и имеет всю документацию.
Ответ 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
Поскольку 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