在Windows Excel VBA中,如何获取JSON密钥以预先取得“运行时错误438”:对象不支持此属性或方法“?

在这里回答我自己的问题。
我已经在Excel VBA中使用JSON做了一些工作,并且发布了大量的调查结果,我将以问答格式进行发布。https: //stackoverflow.com/help/self-answer http://blog.stackoverflow.com/2011 / 07 / ITS-OK-到问一答,你自己的问题/

所以在stackoverflow的其他地方,你可以看到关于在VBA中parsingJSON的问题,但他们似乎错过了一两招。

首先,我使用自定义的JSONparsing库进行了重新设置,而改用ScriptControl的Eval方法作为我所有JSON代码的基础。 而且我们也expression了本地微软解决scheme的偏好。

这里是一个先前的问题在Windows的Excel VBA中,如何缓解由IDE的大小写行为破坏的parsingJSON的点语法遍历问题? 在这个问题上build立起来。 它显示了如何使用VBA.CallByName比使用点语法来遍历parsing的JSON对象更强大。 另外一个先前的问题在Windows上的Excel VBA中,如何通过parsing的JSON数组循环? 展示了它如何被用来访问数组元素。 但CallByName返回一个奇怪的variablestypes,它出现在监视窗口中作为Object / JScriptTypeInfo,并且如果在直接窗口中有一个types为Debug.Print(或hover在variables上),则获得无形的“[object Object]”。 在系列的另一个问题在Windows上的Excel VBA,如何获得string化的JSON respresentation而不是“[object object]”的parsingJSONvariables? 我提出了一些debugging“糖”,可以很好地检查variables。

在这个问题中,我问我们如何以编程方式获得一个成员列表,我可以检测到一个键的存在,这将有助于抢先任何“运行时错误'438':对象不支持此属性或方法“错误,并允许我们写防御(希望是”防弹“)的代码?

这是系列5的问题4.这里是完整的系列

Q1 在Windows上的Excel VBA中,如何缓解IDE大小写行为破坏的parsingJSON的点语法遍历问题?

Q2 在Windows上的Excel VBA中,如何通过parsing的JSON数组循环?

Q3 在Windows的Excel VBA中,如何获得string化的JSON表示而不是“[object object]”来parsingJSONvariables?

Q4 在Windows Excel VBA中,如何获取JSON密钥以预先取得“运行时错误438”:对象不支持此属性或方法“?

Q5 在Windows的Excel VBA中,对于parsing的JSONvariables,这个JScriptTypeInfo是什么?

解决与处理parsing的JSON对象有关的其他堆栈溢出问题的答案使用小脚本方法,我们可以在这里使用这种方法。 如果我们说我们正在运行Excel VBA的Microsoft Windows版本,那么我们可以使用Microsoft Scripting Runtime库中的Scripting Dictionary。

我们可以在Javascript中创buildScripting.Dictionary,使用JSON对象的键来填充它,并且使用这些值作为子元素的引用,并最终传回给VBA。 在VBA中,可以使用Dictionary的Exists方法来防御丢失的键。 可以使用Dictionary的Count方法来定义其他下游variables。 甚至可以使用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 

不过,我也发现了一个很好的select,不需要miniscript或Scripting.Dictionary。 它将允许抢先丢失密钥,但没有集合类function。 它使用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