Dans Excel VBA sous Windows, Comment obtenir une représentation JSON stringifiée au lieu de" [object Object] " pour les variables JSON parsées?

répondant à ma propre question ici.

J'ai fait quelques travaux avec JSON dans Excel VBA et beaucoup de conclusions à poster que je vais le faire dans le format Q & A https://stackoverflow.com/help/self-answer http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions /

donc ailleurs sur stackoverflow on peut voir des questions sur l'analyse de JSON dans VBA mais ils semblent manquer une astuce ou de deux.

pour commencer, je n'utilise pas les bibliothèques d'analyse JSON personnalisées et j'utilise plutôt la méthode Eval de ScriptControl comme base de tout mon code JSON. Et nous exprimons également une préférence de Microsoft solutions natives.

Voici une question préalable dans Excel VBA sur Windows, comment atténuer la question de la syntaxe de point traversée de JSON parsemé brisée par le comportement de capitalisation D'IDE? sur laquelle cette question s'appuie. Il montre comment utiliser VBA.CallByName est plus robuste que d'utiliser la syntaxe de point pour traverser un objet JSON analysé. Aussi une autre question préalable dans Excel VBA sur Windows, comment boucler à travers un tableau JSON analysé? montre comment il peut également être utilisé pour accéder aux éléments du tableau. Mais CallByName renvoie un type de variable curieux qui apparaît dans la fenêtre Watch comme Object/JScriptTypeInfo et si un type de Débogage.D'impression dans la fenêtre (ou de la pointe sur la variable), on obtient l'imprécis "[object Objet."]

Comment Pouvons-nous améliorer cela et obtenir un JSON stringified represenation?

Voici une capture d'écran de ce que vous voyez dans les fenêtres immédiates après un débogage.D'impression (? et si vous passez la souris sur une variable.

object Object

C'est la Question 3 de la série de 5. Voici la série complète

Q1 en Excel VBA sur Windows, Comment faire atténuer la question de la traversée de la syntaxe de points de JSON par le comportement de capitalisation D'IDE?

Q2 en Excel VBA sur Windows, Comment faire une boucle à travers un tableau JSON parsed?

Q3 dans Excel VBA sur Windows, Comment obtenir une représentation JSON stringifiée au lieu de "[Objet Objet]" pour les variables JSON parsées?

Q4 dans Windows Excel VBA,comment obtenir JSON les clés pour anticiper un "Run-time error '438': cet Objet ne gère pas cette propriété ou cette méthode"?

Q5 Dans Excel VBA sur Windows, pour analysée JSON variables qu'est-ce que ce JScriptTypeInfo de toute façon?

5
demandé sur Community 2016-06-08 22:17:45

2 réponses

les réponses à d'autres questions sur le débordement de la pile qui se rapportent au travail avec des objets JSON analysés utilisent une approche de mini-script et nous pouvons utiliser cette approche ici.

tout d'Abord, nous reconnaissons que Douglas Crockford est l'auteur de 'Javascript: Les Bonnes Pièces" ( http://shop.oreilly.com/product/9780596517748.do ) et est expert en javascript. Nous sommes donc heureux d'adopter son code en ce qui concerne la stringification. Nous pouvons obtenir son code avec un HTTP Xml simple Demande (généralement raccourci à XHR) et passer le résultat de retour à la méthode Addcode de ScriptControl. Puis ajouter du code qui nous permet de modifier la représentation par défaut De" [objet objet] " en appelant à la bibliothèque de Douglas. Et ensuite, assurez-vous que nous ajoutons dynamiquement ce contrôleur à toutes nos variables JScriptTypeInfo., à la fois ce qui sort de la méthode Eval de ScriptControl que nous enveloppons de décodage() et aussi ce qui sort de VBA.CallByName que nous enveloppons avec GetJSONObject().

ainsi,

'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)

    Stop


    Dim objKey2 As Object
    Set objKey2 = GetJSONObject(objJSON, "key2")
    Debug.Print objKey2
    Stop

End Sub

voici une capture d'écran avec le nouveau code qui montre une stringification des variables JScriptTypeInfo

enter image description here

4
répondu S Meaden 2016-06-08 19:17:45

Merci Meaden, c'est ce que je cherchais, une façon simple de convertir un objet JSON en chaîne. J'ai utilisé vos idées et je les ai fusionnées avec mon code, mais je n'ai pas aimé l'idée de faire une connexion et de télécharger le script chaque fois que j'avais besoin de créer un objet JSON. donc, j'ai compressé le JSON2.JS code dans une fonction et l'a utilisé à la place que je vais coller la prochaine peut-être que quelqu'un aimera l'idée aussi.

Private Function JSON2() As String
    '/q/in-excel-vba-on-windows-how-to-get-stringified-json-respresentation-instead-of-object-object-for-parsed-json-variables-59998/"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];}}}}" _
        & "return reviver.call(holder,key,value);}" _
        & "text=String(text);rx_dangerous.lastIndex=0;if(rx_dangerous.test(text)){text=text.replace(rx_dangerous,function(a){return""\u""+" _
        & "(""0000""+a.charCodeAt(0).toString(16)).slice(-4);});}" _
        & "if(rx_one.test(text.replace(rx_two,""@"").replace(rx_three,""]"").replace(rx_four,""""))){j=eval(""(""+text+"")"");return(typeof reviver===""function"")?walk({"""":j},""""):j;}" _
        & "throw new SyntaxError(""JSON.parse"");};}}());"
End Function
1
répondu Ali Hussain Al Khawaher 2017-10-19 08:35:56