在这里回答我自己的问题。 我已经在Excel VBA中使用JSON完成了一些工作,并发布了很多发现,并将以问答格式 http://blog.stackoverflow.com/2011发布/ 07 /它可以询问并回答您自己的问题/
因此,在stackoverflow上的其他地方,可以看到有关在VBA中解析JSON的问题,但它们似乎错过了一两个技巧。
首先,我不再使用自定义JSON解析库,而是使用ScriptControl的Eval方法作为所有JSON代码的基础。另外,我们对本机Microsoft解决方案表示偏爱。
这是一个先前的问题,在Windows上的Excel VBA中,如何减轻IDE的大写行为破坏解析的JSON的点语法遍历的问题?这个问题基于此。它显示了与使用点语法遍历已解析的JSON对象相比,使用VBA.CallByName的鲁棒性更高。还有另一个先前的问题,在Windows上的ExcelVBA中,如何遍历解析的JSON数组?显示了如何将其也用于访问数组元素。但是CallByName返回一个奇怪的变量类型,它在监视窗口中显示为Object / JScriptTypeInfo,并且如果一种类型的Debug.Print在当前窗口中(或将鼠标悬停在变量上)将获得无意义的“ [objectObject]”。在系列的另一个问题中[在Windows上的Excel VBA中,如何为解析的JSON变量获取字符串化的JSON表示形式而不是“ object Object]”?我介绍了一些调试“糖”,它可以很好地检查变量。
在此问题中,我问我们如何以编程方式获取可以检测到密钥存在的成员列表,这将有助于抢占任何“运行时错误‘438”:对象不支持此属性或方法错误并允许我们编写防御性(希望是“防弹”的)代码?
与使用已解析的JSON对象相关的其他堆栈溢出问题的答案使用小型脚本方法,我们可以在此处使用此方法。如果说我们正在运行Microsoft Windows版本的Excel VBA,则可以使用库中的脚本字典Microsoft Scripting Runtime。
Microsoft Scripting Runtime
我们可以在Javascript中创建Scripting.Dictionary,使用JSON对象的键填充它,还可以使用这些值作为对子元素的引用,最后传递回VBA。在VBA中,然后可以使用Dictionary的Exists方法防御丢失的密钥。可以使用Dictionary的Count方法确定其他下游变量的尺寸。甚至可以使用Dictionary的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
但是,我还发现了一个不需要miniscript或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