2016-06-08 17 views
5

odpowiadając na moje własne pytanie tutaj.
Zrobiłem trochę pracy z JSON w Excel VBA i wiele ustaleń odpowiedzieć które będę robić w Q & formacie https://stackoverflow.com/help/self-answerhttp://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/W programie Excel VBA w systemie Windows, jak uzyskać uszeregowaną reprezentację JSON zamiast "[obiektu obiektu]" dla sparsowanych zmiennych JSON?

Więc gdzie indziej na stackoverflow można zobaczyć pytania dotyczące analizowania JSON w VBA, ale oni wydaje się, że tęskni się za jedną lub dwiema sztuczkami.

Na początek używam niestandardowych bibliotek parsujących JSON i zamiast tego używam metody Eval ScriptControl jako podstawy dla całego mojego kodu JSON. A także wyrażamy preferencje z rodzimych rozwiązań Microsoft.

Oto poprzednie pytanie In Excel VBA on Windows, how to mitigate issue of dot syntax traversal of parsed JSON broken by IDE's capitalisation behaviour?, na podstawie którego powstaje to pytanie. Pokazuje, jak używać VBA.CallByName jest bardziej niezawodny niż użycie składni kropki do przechodzenia analizowanego obiektu JSON. Również inne wcześniejsze pytanie In Excel VBA on Windows, how to loop through a JSON array parsed? pokazuje, w jaki sposób można go również użyć do uzyskania dostępu do elementów tablicy. Ale CallByName zwraca ciekawy typ zmiennej, który pojawia się w oknie Watch jako Object/JScriptTypeInfo i jeśli jeden typ Debug.Print w bezpośrednim oknie (lub unosi się nad zmienną) uzyskuje się nieinformacyjny "[object Object]".

Jak możemy to poprawić i uzyskać usztywnioną reprezentację JSON?

Oto zrzut ekranu przedstawiający okna natychmiast po zakończeniu debugowania (?) I po najechaniu kursorem na zmienną.

object Object

To Pytanie 3 z serii 5. Oto pełna seria

Q1 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?

+1

Istnieje wiele problemów, więc jedno duże pytanie byłoby niewłaściwe. W rzeczywistości jest pięć pytań i odpowiedzi –

Odpowiedz

4

odpowiedzi na inne pytanie przepełnienie stosu, które odnoszą się do pracy z analizowany obiektów JSON stosować podejście mini-skrypt i możemy użyć tej metody tutaj.

Po pierwsze, przyznajemy, że Douglas Crockford jest autorem "Javascript: The Good Parts" (http://shop.oreilly.com/product/9780596517748.do) i jest ekspertem od javascript. Dlatego chętnie przyjmujemy jego kod w odniesieniu do uszeregowania. Możemy uzyskać jego kod za pomocą prostego żądania HTTP Xml (zwykle skróconego do XHR) i przekazać wynik zwrotny do metody AddCode ScriptControl. Następnie dodaj kod, który pozwala nam zastąpić domyślną reprezentację "[obiektu obiektu]", wywołując w bibliotece Douglasa. A następnie upewnijmy się, że dynamicznie dodajemy to przesłonięcie do wszystkich naszych zmiennych JScriptTypeInfo, zarówno tych, które pochodzą z metody Eval ScriptControl, którą zawijamy z DecodeJsonString() , jak i tego, co wychodzi z VBA.CallByName, które zawijamy za pomocą GetJSONObject().

Zatem

'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 

Oto zrzut ekranu z nowego kodu, który pokazuje stringification zmiennych JScriptTypeInfo

enter image description here

+0

Dziękuję za tę mini-serię Excel VBA/JSON - uważam ją za bardzo użyteczną, ponieważ bardzo trudno jest znaleźć dobre informacje na ten temat na SO. Teraz jest sekcja "Dokumentacja" na SO - sugeruję, żebyś tam też je opublikował. Jedną z idei, która ciągle mi przychodzi do głowy - czy istnieje sposób, aby wziąć JSON i przekonwertować lub sparsować go na DOM XML, który VBA obsługuje natywnie? Następnie pozwala na użycie DOM do wygodnej manipulacji oraz XPath dla zapytania. Czy można to zrobić efektywnie za pomocą tego podejścia (tzn. Może nawet używać JScript do konwersji JSON na XML)? –

+0

Dzięki. Jest kod do przekonwertowania z JSON do Xml Dom http://stackoverflow.com/questions/1773550/convert-xml-to-json-and-back-using-javascript#answer-1773571, ale nie mogłem go uruchomić z Microsoft Script Control. Będzie działał z cscript.exe (co również ułatwia debugowanie w Visual Studio), ale to oznacza, że ​​uruchamiany jest inny proces. –

0

Dziękuję S Meaden, to co szukałem , prosty sposób konwertowania obiektu JSON na ciąg. Użyłem twoich pomysłów i połączyłem je z moim kodem, ale nie podobał mi się pomysł połączenia i pobrania skryptu za każdym razem, gdy potrzebowałem stworzyć obiekt JSON. więc skompresowałem kod JSON2.js do funkcji i użyłem go zamiast tego, co wklejam dalej, może ktoś też polubi ten pomysł.

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];}}}}" _ 
     & "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