В Windows Excel VBA как получить ключи JSON для предупреждения "Ошибка времени выполнения" 438 ": объект не поддерживает это свойство или метод"?

Отвечая на мой собственный вопрос здесь.
Я проделал некоторую работу с JSON в Excel VBA и много выводов, которые я опубликую, которые я сделаю в формате вопросов и ответов https://stackru.com/help/self-answer http://blog.stackru.com/2011 / 07 / его нормально-к-аск-ответ-своего собственного вопросы /

Так что в другом месте на stackru можно увидеть вопросы о разборе JSON в VBA, но они, кажется, пропускают хитрость или два.

Для начала я отказываюсь от использования пользовательских библиотек анализа JSON и вместо этого использую метод ScriptControl Eval как основу всего моего кода JSON. А также мы выражаем предпочтение родным решениям Microsoft.

Вот предыдущий вопрос В Excel VBA на Windows, как уменьшить проблему точечного синтаксического анализа синтаксического анализа JSON, нарушенного поведением заглавных букв в среде IDE? на котором строится этот вопрос. Он показывает, что использование VBA.CallByName более надежно, чем использование точечного синтаксиса для прохождения проанализированного объекта JSON. Также еще один предыдущий вопрос В Excel VBA на Windows, как пройти через анализируемый массив JSON? показывает, как его также можно использовать для доступа к элементам массива. Но CallByName возвращает любопытный тип переменной, который появляется в окне Watch как Object/JScriptTypeInfo, и если один тип Debug.Print в непосредственном окне (или наводит курсор на переменную), он получает неинформативный "[object Object]". Другой вопрос из серии В Excel VBA в Windows, как получить строковое представление JSON вместо "[объектный объект]" для проанализированных переменных JSON? Я представляю некоторый отладочный "сахар", который позволяет хорошо проверить переменные.

В этом вопросе я спрашиваю, как мы можем программно получить список членов, с помощью которых я могу обнаружить присутствие ключа, это поможет предупредить любую "ошибку времени выполнения" 438 ": объект не поддерживает это свойство или метод "ошибки и позволяют ли мы писать защитный (надеюсь" пуленепробиваемый ") код?

Это Вопрос 4 из серии 5. Вот полная серия

В1. В Excel VBA в Windows, как уменьшить проблему точечного синтаксического анализа синтаксического анализа JSON, нарушенного поведением заглавных букв в среде IDE?

Q2 В Excel VBA в Windows, как пройти через анализируемый массив JSON?

Q3 В Excel VBA в Windows, как получить строковое представление JSON вместо "[объектный объект]" для проанализированных переменных JSON?

Q4 В Windows Excel VBA, как получить ключи JSON для предупреждения "Ошибка времени выполнения" 438 ": объект не поддерживает это свойство или метод"?

Q5 В Excel VBA в Windows, для проанализированных переменных JSON, что это за JScriptTypeInfo?

1 ответ

Решение

Ответы на другой вопрос переполнения стека, относящиеся к работе с проанализированными объектами JSON, используют подход мини-сценария, и мы можем использовать этот подход здесь. Если мы говорим, что используем Microsoft Windows Edition Excel VBA, тогда мы можем использовать словарь сценариев, найденный в библиотеке Microsoft Scripting Runtime,

Мы можем создать Scripting.Dictionary в Javascript, заполнить его ключами объекта JSON, а также использовать значения в качестве ссылок на подэлементы и, наконец, передать обратно в VBA. В VBA можно использовать метод словаря Exists для защиты от пропущенных ключей. Можно использовать метод Count в словаре для измерения других нижестоящих переменных. Можно даже использовать метод Item для словаря, чтобы получить подэлемент (только на один уровень ниже).

Таким образом,

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

Option Explicit

Private Function GetScriptEngine() As ScriptControl
    Static soScriptEngine As ScriptControl
    If soScriptEngine Is Nothing Then
        Set soScriptEngine = New ScriptControl
        soScriptEngine.Language = "JScript"

        soScriptEngine.AddCode "function getKeyValues(jsonObj) { " & _
                              " var dictionary = new ActiveXObject(""Scripting.Dictionary""); " & _
                              " var keys = new Array(); for (var i in jsonObj) { dictionary.add(i,jsonObj[i]); }; return dictionary; } "


    End If
    Set GetScriptEngine = soScriptEngine
End Function


Private Sub TestJSONParsingWithCallByName3()

    Dim oScriptEngine As ScriptControl
    Set oScriptEngine = GetScriptEngine

    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"

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

    Dim dicKeys As Scripting.Dictionary
    Set dicKeys = oScriptEngine.Run("getKeyValues", objJSON)

    Debug.Assert dicKeys.Count = 2

    Debug.Assert TypeName(dicKeys.Item(dicKeys.Keys()(1))) = "JScriptTypeInfo"
    Stop

    If dicKeys.Exists("foobarbaz") Then

        '*** Next line WOULD throw "Run-time error '438': Object doesn't support this property or method" because "foobarbaz" is not a key
        '*** but is skipped because of defensive code.
        Debug.Assert VBA.CallByName(objJSON, "foobarbaz", VbGet)

    End If

End Sub

Тем не менее, я также обнаружил замечательную альтернативу, которая не требует мини-сценария или Scripting.Dictionary. Это позволит упреждать отсутствующие ключи, но не имеет функциональности класса коллекции. Он использует малоизвестное свойство hasOwnProperty(). Таким образом,

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

Option Explicit

Private Sub TestJSONParsingWithCallByName4()

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

    Dim sJsonString As String
    sJsonString = "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }"

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

    Debug.Assert objJSON.hasOwnProperty("key1")
    Debug.Assert objJSON.hasOwnProperty("key2")

    Dim objKey2 As Object
    Set objKey2 = VBA.CallByName(objJSON, "key2", VbGet)

    Debug.Assert objKey2.hasOwnProperty("key3")


    If objJSON.hasOwnProperty("foobarbaz") Then

        '*** Next line WOULD throw "Run-time error '438': Object doesn't support this property or method" because "foobarbaz" is not a key
        '*** but is skipped because of defensive code.
        Debug.Assert VBA.CallByName(objJSON, "foobarbaz", VbGet)

    End If

End Sub
Другие вопросы по тегам