2016-06-08 12 views
1

Beantwortung meiner eigenen Frage hier.
Ich habe einige Arbeit mit JSON in Excel VBA und viele Erkenntnisse getan zu schreiben, die ich in Q so tue & A-Format https://stackoverflow.com/help/self-answerhttp://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/In Windows Excel VBA, wie Sie JSON-Schlüssel zum Präventieren erhalten "Laufzeitfehler '438': Objekt unterstützt diese Eigenschaft oder Methode nicht"?

So anderswo auf Stackoverflow eine Frage zum Parsen von JSON in VBA sehen kann, aber sie scheinen einen oder zwei Tricks zu verpassen.

Zunächst kann ich keine benutzerdefinierten JSON-Parsing-Bibliotheken verwenden und stattdessen die Eval-Methode von ScriptControl als Grundlage für meinen gesamten JSON-Code verwenden. Und auch wir drücken eine Präferenz von nativen Microsoft-Lösungen aus.

Hier ist eine vorherige Frage In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?, auf der diese Frage aufbaut. Es zeigt, wie die Verwendung von VBA.CallByName robuster ist als die Verwendung der Punktsyntax zum Durchlaufen eines analysierten JSON-Objekts. Auch eine andere Vorfrage In Excel VBA on Windows, how to loop through a JSON array parsed? zeigt, wie man auch zum Zugriff auf Array-Elemente verwenden kann. Aber CallByName gibt einen kuriosen Variablentyp zurück, der im Watch-Fenster als Object/JScriptTypeInfo erscheint und wenn man Debug.Print im unmittelbaren Fenster eingibt (oder über die Variable schwebt) erhält man das nicht informative "[object Object]". In einer anderen Frage in der Reihe In Excel VBA on Windows, how to get stringified JSON respresentation instead of “[object Object]” for parsed JSON variables? Ich präsentiere einige Debugging "Zucker", die eine gute Überprüfung der Variablen ermöglicht.

In dieser Frage frage ich, wie können wir programmatisch eine Liste von Mitgliedern erhalten, mit denen ich die Anwesenheit eines Schlüssels erkennen kann, wird dies dazu beitragen, "Run-Time-Fehler '438': Object nicht zuunterstützen diese Eigenschaft oder Methode "Fehler und erlauben uns, defensiven (hoffentlich" kugelsicheren ") Code zu schreiben?

Dies ist Frage 4 der Serie von 5. Hier ist die vollständige Reihe

Q1 ist In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?

Q2 In Excel VBA on Windows, how to loop through a JSON array parsed?

Q3 In Excel VBA on Windows, how to get stringified JSON respresentation instead of “[object Object]” for parsed JSON variables?

Q4 In Windows Excel VBA,how to get JSON keys to pre-empt “Run-time error '438': Object doesn't support this property or method”?

Q5 In Excel VBA on Windows, for parsed JSON variables what is this JScriptTypeInfo anyway?

Antwort

1

Antworten auf andere Stapelüberlauffragen, die sich auf die Arbeit mit geparsten JSON-Objekten beziehen, verwenden einen Miniscript-Ansatz, und wir können diesen Ansatz hier verwenden. Wenn wir sagen, dass wir eine Microsoft Windows-Edition von Excel VBA ausführen, können wir das Skriptwörterbuch wie in der Bibliothek Microsoft Scripting Runtime verwenden.

Wir können das Scripting.Dictionary im Javascript erstellen, es mit den Schlüsseln des JSON-Objekts füllen und die Werte auch als Referenzen auf die Unterelemente verwenden und schließlich an VBA zurückgeben. In VBA kann man dann die Dictionary's Exists-Methode verwenden, um sich gegen fehlende Schlüssel zu verteidigen. Man kann die Zählmethode des Dictionary verwenden, um andere Downstream-Variablen zu dimensionieren. Man kann sogar die Item-Methode des Dictionary verwenden, um ein Subelement abzurufen (nur eine Ebene tiefer).

So

'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 

Allerdings habe ich auch entdeckt, eine wunderbare Alternative, die keine Miniskript oder Scripting benötigt.Wörterbuch. Es ermöglicht das Vorwegnehmen von fehlenden Schlüsseln, aber hat keine Sammelklassenfunktionalität. Es verwendet eine wenig bekannte Eigenschaft von hasOwnProperty(). Somit

'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 
Verwandte Themen