![]() |
憨厚的佛珠 · 山东省科学技术厅 地方科技 ...· 3 月前 · |
![]() |
卖萌的自行车 · 第一冊語文常識(上)工具書使用法· 11 月前 · |
![]() |
老实的牛肉面 · 半个月来港股惊现四宗“杀猪盘” ...· 1 年前 · |
![]() |
英俊的小马驹 · 【克苏鲁神话文献】《哈斯塔祷词》 - 哔哩哔哩· 1 年前 · |
在这里回答我自己的问题。
我在Excel中使用JSON做了一些工作,并发布了许多发现,我将用Q&A格式的 https://stackoverflow.com/help/self-answer https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ 这样做。
因此,在堆栈溢出的其他地方,可以看到有关在VBA中解析JSON的问题,但它们似乎遗漏了一两个技巧。
首先,我不使用自定义JSON解析库,而是使用ScriptControl的Eval方法作为所有JSON代码的基础。此外,我们还表达了来自本地Microsoft解决方案的偏好。
下面是一个先前的问题 In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour? ,这个问题是建立在这个问题之上的。它展示了如何使用VBA.CallByName比使用点语法遍历解析的JSON对象更健壮。另外,前面的另一个问题 In Excel VBA on Windows, how to loop through a JSON array parsed? 展示了如何使用它来访问数组元素。但是CallByName返回一个奇怪的变量类型,它以Object/JScriptTypeInfo的形式出现在“监视窗口”中,如果在“立即”窗口中的一个类型(或悬停在该变量上),就会得到信息不丰富的" object“。
我们如何改进这一点,并得到一个JSON字符串表示呢?
下面是你在Debug.Print (?)之后立即看到的窗口屏幕截图。如果你悬停在一个变量上。
这是5组中的问题3,这是完整的系列
Q2 In Excel VBA on Windows, how to loop through a JSON array parsed?
Q5 In Excel VBA on Windows, for parsed JSON variables what is this JScriptTypeInfo anyway?
发布于 2016-06-08 19:17:45
对于与使用解析的JSON对象有关的其他堆栈溢出问题,请使用mini-script方法,我们可以在这里使用这种方法。
首先,我们承认Douglas是“javascript : The Good Parts”( http://shop.oreilly.com/product/9780596517748.do )的作者,也是javascript专家。因此,我们很高兴通过他的关于字符串化的代码。我们可以使用简单的Xml请求(通常缩写为XHR)获取他的代码,并将返回结果传递给ScriptControl的AddCode方法。然后添加一些代码,允许我们通过调用Douglas的库来覆盖"object Object“的默认表示。然后确保我们动态地将覆盖添加到所有的JScriptTypeInfo变量中,包括我们用DecodeJsonString()包装的ScriptControl的Eval方法以及用GetJSONObject()包装的VBA.CallByName产生的内容。
因此,
'Tools->References->
'Microsoft Script Control 1.0; {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx
'Microsoft Xml, v6.0
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 GetJavaScriptLibrary("https://raw.githubusercontent.com/douglascrockford/JSON-js/master/json2.js")
soScriptEngine.AddCode "function overrideToString(jsonObj) { jsonObj.toString = function() { return JSON.stringify(this); } }"
End If
Set GetScriptEngine = soScriptEngine
End Function
Private Function GetJavaScriptLibrary(ByVal sURL As String) As String
Dim xHTTPRequest As MSXML2.XMLHTTP60
Set xHTTPRequest = New MSXML2.XMLHTTP60
xHTTPRequest.Open "GET", sURL, False
xHTTPRequest.send
GetJavaScriptLibrary = xHTTPRequest.responseText
End Function
Private Function DecodeJsonString(ByVal JsonString As String) As Object
Dim oScriptEngine As ScriptControl
Set oScriptEngine = GetScriptEngine
Set DecodeJsonString = oScriptEngine.Eval("(" + JsonString + ")")
Call oScriptEngine.Run("overrideToString", DecodeJsonString) '* this gives JSON rendering instead of "[object Object]"
End Function
Private Function GetJSONObject(ByVal obj As Object, ByVal sKey As String) As Object
Dim objReturn As Object
Set objReturn = VBA.CallByName(obj, sKey, VbGet)
Call GetScriptEngine.Run("overrideToString", objReturn) '* this gives JSON rendering instead of "[object Object]"
Set GetJSONObject = objReturn
End Function
Private Sub TestJSONParsingWithCallByName2()
Dim sJsonString As String
sJsonString = "{'key1': 'value1' ,'key2': { 'key3': 'value3' } }"
Dim objJSON As Object
Set objJSON = DecodeJsonString(sJsonString)
Dim objKey2 As Object
Set objKey2 = GetJSONObject(objJSON, "key2")
Debug.Print objKey2
End Sub
下面是新代码的屏幕截图,它显示了JScriptTypeInfo变量的字符串化
发布于 2017-10-19 08:35:56
谢谢simple,这就是我想要的,一种将JSON对象转换为string的简单方法。我使用了您的想法并将其与代码合并,但我不喜欢每次创建JSON对象时建立连接和下载脚本的想法。因此,我将JSON2.js代码压缩为一个函数,然后使用它,接下来我将粘贴它,也许有人也会喜欢这个想法。
Private Function JSON2() As String
'https://stackoverflow.com/questions/37711073/in-excel-vba-on-windows-how-to-get-stringified-json-respresentation-instead-of
'https://raw.githubusercontent.com/douglascrockford/JSON-js/master/json2.js
JSON2 = _
"if(typeof JSON!==""object""){JSON={};}" _
& "(function(){""use strict"";var rx_one=/^[\],:{}\s]*$/;var rx_two=/\\(?:[""\\\/bfnrt]|u[0-9a-fA-F]{4})/g;var rx_three=/""[^""\\\n\r]*""|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;var rx_four=/(?:^|:|,)(?:\s*\[)+/g;var rx_escapable=/[\\""\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;var rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;function f(n){return n<10?""0""+n:n;}" _
& "function this_value(){return this.valueOf();}" _
& "if(typeof Date.prototype.toJSON!==""function""){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+""-""+" _
& "f(this.getUTCMonth()+1)+""-""+" _
& "f(this.getUTCDate())+""T""+" _
& "f(this.getUTCHours())+"":""+" _
& "f(this.getUTCMinutes())+"":""+" _
& "f(this.getUTCSeconds())+""Z"":null;};Boolean.prototype.toJSON=this_value;Number.prototype.toJSON=this_value;String.prototype.toJSON=this_value;}" _
& "var gap;var indent;var meta;var rep;function quote(string){rx_escapable.lastIndex=0;return rx_escapable.test(string)?""\""""+string.replace(rx_escapable,function(a){var c=meta[a];return typeof c===""string""?c:""\\u""+(""0000""+a.charCodeAt(0).toString(16)).slice(-4);})+""\"""":""\""""+string+""\"""";}" _
& "function str(key,holder){var i;var k;var v;var length;var mind=gap;var partial;var value=holder[key];if(value&&typeof value===""object""&&typeof value.toJSON===""function""){value=value.toJSON(key);}" _
& "if(typeof rep===""function""){value=rep.call(holder,key,value);}"
JSON2 = JSON2 _
& "switch(typeof value){case""string"":return quote(value);case""number"":return isFinite(value)?String(value):""null"";case""boolean"":case""null"":return String(value);case""object"":if(!value){return""null"";}" _
& "gap+=indent;partial=[];if(Object.prototype.toString.apply(value)===""[object Array]""){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||""null"";}" _
& "v=partial.length===0?""[]"":gap?""[\n""+gap+partial.join("",\n""+gap)+""\n""+mind+""]"":""[""+partial.join("","")+""]"";gap=mind;return v;}" _
& "if(rep&&typeof rep===""object""){length=rep.length;for(i=0;i<length;i+=1){if(typeof rep[i]===""string""){k=rep[i];v=str(k,value);if(v){partial.push(quote(k)+(gap?"": "":"":"")+v);}}}}else{for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?"": "":"":"")+v);}}}}" _
& "v=partial.length===0?""{}"":gap?""{\n""+gap+partial.join("",\n""+gap)+""\n""+mind+""}"":""{""+partial.join("","")+""}"";gap=mind;return v;}}" _
& "if(typeof JSON.stringify!==""function""){meta={""\b"":""\\b"",""\t"":""\\t"",""\n"":""\\n"",""\f"":""\\f"",""\r"":""\\r"",""\"""":""\\\"""",""\\"":""\\\\""};JSON.stringify=function(value,replacer,space){var i;gap="""";indent="""";if(typeof space===""number""){for(i=0;i<space;i+=1){indent+="" "";}}else if(typeof space===""string""){indent=space;}" _
& "rep=replacer;if(replacer&&typeof replacer!==""function""&&(typeof replacer!==""object""||typeof replacer.length!==""number"")){throw new Error(""JSON.stringify"");}" _
& "return str("""",{"""":value});};}" _
& "if(typeof JSON.parse!==""function""){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k;var v;var value=holder[key];if(value&&typeof value===""object""){for(k in value){if(Object.prototype.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}" _