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

отвечая на мой собственный вопрос здесь.
Я проделал некоторую работу с JSON в Excel VBA и опубликовал множество выводов, которые я сделаю в формате вопросов и ответов.https://stackoverflow.com/help/self-answer http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/

Так что в другом месте на stackoverflow можно увидеть вопросы о синтаксическом анализе 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. Вот полная серия

Q1В 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 VBA для Microsoft Windows, то мы можем использовать словарь сценариев, найденный в библиотеке.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
 hamish20 нояб. 2018 г., 13:40
идеально подходит для проверки Json, прежде чем его использовать. благодарю вас. Если Movie.hasOwnProperty («Ошибка»), то MovieError = Movie.Error End If

Ваш ответ на вопрос