web-services example - Gibt es einen JSON-Parser für VB6 / VBA?




auslesen (12)

Ich versuche, einen Webservice in VB6 zu konsumieren. Der Dienst - den ich kontrolliere - kann derzeit eine SOAP / XML-Nachricht oder JSON zurückgeben. Ich habe eine wirklich schwierige Zeit, herauszufinden, ob der SOAP-Typ von VB6 (Version 1) mit einem zurückgegebenen object umgehen kann - im Gegensatz zu einfachen Typen wie string , int usw. Bisher kann ich nicht herausfinden, was ich tun muss, um VB6 zu bekommen spielen mit zurückgegebenen Objekten.

Also dachte ich, ich könnte die Antwort im Web-Service als JSON-String serialisieren. Existiert ein JSON-Parser für VB6?


Answers

Aufbauend auf Ozmike-Lösung, die bei mir nicht funktioniert hat (Excel 2013 und IE10). Der Grund ist, dass ich die Methoden auf dem offen gelegten JSON-Objekt nicht aufrufen konnte. Seine Methoden werden nun durch Funktionen angezeigt, die an ein DOME-Element angehängt sind. Wusste nicht, dass das möglich ist (muss das IDispatch-Ding sein), danke ozmike.

Wie ozmike sagte, keine 3rd-Party-Bibliotheken, nur 30 Codezeilen.

Option Explicit

Public JSON As Object
Private ie As Object

Public Sub initJson()
    Dim html As String

    html = "<!DOCTYPE html><head><script>" & _
    "Object.prototype.getItem=function( key ) { return this[key] }; " & _
    "Object.prototype.setItem=function( key, value ) { this[key]=value }; " & _
    "Object.prototype.getKeys=function( dummy ) { keys=[]; for (var key in this) if (typeof(this[key]) !== 'function') keys.push(key); return keys; }; " & _
    "window.onload = function() { " & _
    "document.body.parse = function(json) { return JSON.parse(json); }; " & _
    "document.body.stringify = function(obj, space) { return JSON.stringify(obj, null, space); }" & _
    "}" & _
    "</script></head><html><body id='JSONElem'></body></html>"

    Set ie = CreateObject("InternetExplorer.Application")
    With ie
        .navigate "about:blank"
        Do While .Busy: DoEvents: Loop
        Do While .readyState <> 4: DoEvents: Loop
        .Visible = False
        .document.Write html
        .document.Close
    End With

    ' This is the body element, we call it JSON:)
    Set JSON = ie.document.getElementById("JSONElem")

End Sub

Public Function closeJSON()
    ie.Quit
End Function

Der folgende Test erstellt ein JavaScript-Objekt von Grund auf neu und stringiert es anschließend. Dann parst er das Objekt zurück und iteriert über seine Schlüssel.

Sub testJson()
    Call initJson

    Dim jsObj As Object
    Dim jsArray As Object

    Debug.Print "Construction JS object ..."
    Set jsObj = JSON.Parse("{}")
    Call jsObj.setItem("a", 1)
    Set jsArray = JSON.Parse("[]")
    Call jsArray.setItem(0, 13)
    Call jsArray.setItem(1, Math.Sqr(2))
    Call jsArray.setItem(2, 15)
    Call jsObj.setItem("b", jsArray)

    Debug.Print "Object: " & JSON.stringify(jsObj, 4)

    Debug.Print "Parsing JS object ..."
    Set jsObj = JSON.Parse("{""a"":1,""b"":[13,1.4142135623730951,15]}")

    Debug.Print "a: " & jsObj.getItem("a")
    Set jsArray = jsObj.getItem("b")
    Debug.Print "Length of b: " & jsArray.getItem("length")
    Debug.Print "Second element of b: "; jsArray.getItem(1)

    Debug.Print "Iterate over all keys ..."
    Dim keys As Object
    Set keys = jsObj.getKeys("all")

    Dim i As Integer
    For i = 0 To keys.getItem("length") - 1
        Debug.Print keys.getItem(i) & ": " & jsObj.getItem(keys.getItem(i))
    Next i

    Call closeJSON
End Sub

Ausgänge

Construction JS object ...
Object: {
    "a": 1,
    "b": [
        13,
        1.4142135623730951,
        15
    ]
}
Parsing JS object ...
a: 1
Length of b: 3
Second element of b:  1,4142135623731 
Iterate over all keys ...
a: 1
b: 13,1.4142135623730951,15

das ist vb6 beispielcode, ok getestet, funktioniert erledigt

Aus den obigen guten Beispielen habe ich Änderungen vorgenommen und dieses gute Ergebnis erzielt

Es kann Schlüssel {} und Arrays [] lesen

Option Explicit
'in vb6 click "Tools"->"References" then
'check the box "Microsoft Script Control 1.0";
Dim oScriptEngine As New ScriptControl
Dim objJSON As Object

''to use it
Private Sub Command1_Click()
  MsgBox JsonGet("key1", "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }")''returns "value1"
  MsgBox JsonGet("key2.key3", "{'key1': 'value1'  ,'key2': { 'key3': 'value3' } }") ''returns "value3"
  MsgBox JsonGet("result.0.Ask", "{'result':[{'MarketName':'BTC-1ST','Bid':0.00004718,'Ask':0.00004799},{'MarketName':'BTC-2GIVE','Bid':0.00000073,'Ask':0.00000074}]}") ''returns "0.00004799"
  MsgBox JsonGet("mykey2.keyinternal1", "{mykey:1111, mykey2:{keyinternal1:22.1,keyinternal2:22.2}, mykey3:3333}") ''returns "22.1"
End Sub

Public Function JsonGet(eKey$, eJsonString$, Optional eDlim$ = ".") As String
  Dim tmp$()
  Static sJsonString$
  If Trim(eKey$) = "" Or Trim(eJsonString$) = "" Then Exit Function
  If sJsonString <> eJsonString Then
    sJsonString = eJsonString
    oScriptEngine.Language = "JScript"
    Set objJSON = oScriptEngine.Eval("(" + eJsonString + ")")
  End If
  tmp = Split(eKey, eDlim)
  If UBound(tmp) = 0 Then JsonGet = VBA.CallByName(objJSON, eKey, VbGet): Exit Function

  Dim i&, o As Object
  Set o = objJSON
  For i = 0 To UBound(tmp) - 1
    Set o = VBA.CallByName(o, tmp(i), VbGet)
  Next i
  JsonGet = VBA.CallByName(o, tmp(i), VbGet)
  Set o = Nothing
End Function

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  Set objJSON = Nothing
End Sub

VBA-JSON von Tim Hall, MIT lizensiert und auf GitHub . Es ist eine weitere Gabelung von vba-json , die Ende 2014 herauskam. Ansprüche, um auf Mac Office und Windows 32bit und 64bit zu arbeiten.


Auf JSON.org finden Sie eine aktuelle Liste von JSON-Parsern in vielen verschiedenen Sprachen (siehe unten auf der Hauptseite). Zum Zeitpunkt des Schreibens sehen Sie einen Link zu zwei verschiedenen JSON-Parsern:

  • VB-JSON

    • Als ich versuchte, die Zip-Datei herunterzuladen, sagte Windows, dass die Daten beschädigt waren. Ich konnte jedoch 7-zip verwenden , um die Dateien herauszuziehen. Es stellt sich heraus, dass der Hauptordner in der Zip-Datei von Windows nicht als Ordner erkannt wird, da 7-zip den Inhalt dieses Hauptordners sehen kann, damit Sie ihn öffnen und die Dateien entsprechend extrahieren können .
    • Die tatsächliche Syntax für diese VB JSON-Bibliothek ist wirklich einfach:

      Dim p As Object
      Set p = JSON.parse(strFormattedJSON)
      
      'Print the text of a nested property '
      Debug.Print p.Item("AddressClassification").Item("Description")
      
      'Print the text of a property within an array '
      Debug.Print p.Item("Candidates")(4).Item("ZipCode")
      
    • Hinweis: Ich musste die Bibliotheken "Microsoft Scripting Runtime" und "Microsoft ActiveX Data Objects 2.8" im VBA-Editor über Extras> Referenzen als Referenzen hinzufügen.
    • Hinweis: VBJSON-Code basiert tatsächlich auf einem Google-Code-Projekt vba-json . VBJSON verspricht jedoch einige Fehlerbehebungen von der ursprünglichen Version.
  • PW.JSON
    • Dies ist eigentlich eine Bibliothek für VB.NET , also habe ich nicht viel Zeit darauf verwendet, mich damit zu befassen.


Hier ist eine "native" VB JSON-Bibliothek.

Es ist möglich, JSON zu verwenden, das bereits in IE8 + ist. Auf diese Weise ist Ihre Bibliothek nicht von einer Drittanbieterbibliothek abhängig, die veraltet und nicht getestet wird.

Siehe die alternative Version von amedeus here

Sub myJSONtest()


Dim oJson As Object
Set oJson = oIE_JSON() ' See below gets IE.JSON object

' using json objects
Debug.Print oJson.parse("{ ""hello"": ""world"" }").hello ' world
Debug.Print oJson.stringify(oJson.parse("{ ""hello"": ""world"" }")) ' {"hello":"world"}

' getting items
Debug.Print oJson.parse("{ ""key1"": ""value1"" }").key1 ' value1
Debug.Print oJson.parse("{ ""key1"": ""value1"" }").itemGet("key1") ' value1
Debug.Print oJson.parse("[ 1234, 4567]").itemGet(1) '  4567

' change  properties
Dim o As Object
Set o = oJson.parse("{ ""key1"": ""value1"" }")
o.propSetStr "key1", "value\""2"
Debug.Print o.itemGet("key1") ' value\"2
Debug.Print oJson.stringify(o) ' {"key1":"value\\\"2"}
o.propSetNum "key1", 123
Debug.Print o.itemGet("key1") ' 123
Debug.Print oJson.stringify(o) ' {"key1":123}

' add properties
o.propSetNum "newkey", 123 ' addkey! JS MAGIC
Debug.Print o.itemGet("newkey") ' 123
Debug.Print oJson.stringify(o) ' {"key1":123,"newkey":123}

' assign JSON 'objects' to properties
Dim o2 As Object
Set o2 = oJson.parse("{ ""object2"": ""object2value"" }")
o.propSetJSON "newkey", oJson.stringify(o2) ' set object
Debug.Print oJson.stringify(o) ' {"key1":123,"newkey":{"object2":"object2value"}}
Debug.Print o.itemGet("newkey").itemGet("object2") ' object2value

' change array items
Set o = oJson.parse("[ 1234, 4567]") '
Debug.Print oJson.stringify(o) ' [1234,4567]
Debug.Print o.itemGet(1)
o.itemSetStr 1, "234"
Debug.Print o.itemGet(1)
Debug.Print oJson.stringify(o) ' [1234,"234"]
o.itemSetNum 1, 234
Debug.Print o.itemGet(1)
Debug.Print oJson.stringify(o) ' [1234,234]

' add array items
o.itemSetNum 5, 234 ' add items! JS Magic
Debug.Print o.itemGet(5) ' 234
Debug.Print oJson.stringify(o) ' [1234,234,null,null,null,234]

' assign JSON object to array item
o.itemSetJSON 3, oJson.stringify(o2)  ' assign object
Debug.Print o.itemGet(3) '[object Object]
Debug.Print oJson.stringify(o.itemGet(3)) ' {"object2":"object2value"}
Debug.Print oJson.stringify(o) ' [1234,234,null,{"object2":"object2value"},null,234]


oIE_JSON_Quit ' quit IE, must shut down or the IE sessions remain.
Debug.Print oJson.stringify(o) ' can use after but but IE server will shutdown... soon
End Sub

Sie können von VB zu IE.JSON überbrücken.
Erstellen Sie eine Funktion oIE_JSON

Public g_IE As Object ' global


Public Function oIE_JSON() As Object


    ' for array access o.itemGet(0) o.itemGet("key1")
    JSON_COM_extentions = "" & _
            " Object.prototype.itemGet        =function( i ) { return this[i] }   ;            " & _
            " Object.prototype.propSetStr     =function( prop , val ) { eval('this.' + prop + '  = ""' + protectDoubleQuotes (val) + '""' )   }    ;            " & _
            " Object.prototype.propSetNum     =function( prop , val ) { eval('this.' + prop + '  = ' + val + '')   }    ;            " & _
            " Object.prototype.propSetJSON    =function( prop , val ) { eval('this.' + prop + '  = ' + val + '')   }    ;            " & _
            " Object.prototype.itemSetStr     =function( prop , val ) { eval('this[' + prop + '] = ""' + protectDoubleQuotes (val) + '""' )   }    ;            " & _
            " Object.prototype.itemSetNum     =function( prop , val ) { eval('this[' + prop + '] = ' + val )   }    ;            " & _
            " Object.prototype.itemSetJSON    =function( prop , val ) { eval('this[' + prop + '] = ' + val )   }    ;            " & _
            " function protectDoubleQuotes (str)   { return str.replace(/\\/g, '\\\\').replace(/""/g,'\\""');   }"

    ' document.parentwindow.eval dosen't work some versions of ie eg ie10?
     IEEvalworkaroundjs = "" & _
         " function IEEvalWorkAroundInit ()   { " & _
         " var x=document.getElementById(""myIEEvalWorkAround"");" & _
         " x.IEEval= function( s ) { return eval(s) } ; } ;"

    g_JS_framework = "" & _
      JSON_COM_extentions & _
      IEEvalworkaroundjs

    ' need IE8 and DOC type
    g_JS_HTML = "<!DOCTYPE html>  " & _
         " <script>" & g_JS_framework & _
                  "</script>" & _
         " <body>" & _
         "<script  id=""myIEEvalWorkAround""  onclick=""IEEvalWorkAroundInit()""  ></script> " & _
                 " HEllo</body>"

On Error GoTo error_handler

' Create InternetExplorer Object
Set g_IE = CreateObject("InternetExplorer.Application")
With g_IE
    .navigate "about:blank"
    Do While .Busy: DoEvents: Loop
    Do While .ReadyState <> 4: DoEvents: Loop
    .Visible = False ' control IE interface window
    .Document.Write g_JS_HTML
End With

Set objID = g_IE.Document.getElementById("myIEEvalWorkAround")
objID.Click ' create  eval
Dim oJson As Object

'Set oJson = g_IE.Document.parentWindow.Eval("JSON") ' dosen't work some versions of IE
Set oJson = objID.IEEval("JSON")

Set objID = Nothing
Set oIE_JSON = oJson

Exit Function
error_handler:
MsgBox ("Unexpected Error, I'm quitting. " & Err.Description & ".  " & Err.Number)
g_IE.Quit
Set g_IE = Nothing

End Function

Public Function oIE_JSON_Quit()
         g_IE.Quit
         Exit Function
End Function

Abstimmen, wenn Sie nützlich finden


Sie könnten ein Excel-DNA-Add-In in VB.NET schreiben. Excel-DNA ist eine schlanke Bibliothek, mit der Sie XLLs in .NET schreiben können. Auf diese Weise erhalten Sie Zugriff auf das gesamte .NET-Universum und können beispielsweise http://james.newtonking.com/json - ein JSON-Framework, das JESON in einer beliebigen benutzerdefinierten Klasse deserialisiert.

Wenn Sie interessiert sind, hier eine Beschreibung, wie man einen generischen Excel JSON Client für Excel mit VB.NET erstellt:

http://optionexplicitvba.com/2014/05/09/developing-a-json-excel-add-in-with-vb-net/

Und hier ist der Link zum Code: https://github.com/spreadgit/excel-json-client/blob/master/excel-json-client.dna


Ich würde vorschlagen, eine .Net-Komponente zu verwenden. Sie können .Net-Komponenten von VB6 über Interop - hier ist ein tutorial . Meine Vermutung ist, dass .Net-Komponenten zuverlässiger und besser unterstützt werden als alles, was für VB6 produziert wird.

Es gibt Komponenten im Microsoft .Net-Framework wie DataContractJsonSerializer oder JavaScriptSerializer . Sie können auch Drittanbieterbibliotheken wie JSON.NET .


Mit JavaScript-Funktionen zum Parsen von JSON können wir, zusätzlich zu ScriptControl, einen Parser in VBA erstellen, der jeden einzelnen Datenpunkt im JSON auflistet. Unabhängig davon, wie verschachtelt oder komplex die Datenstruktur ist, wird dieser Parser, solange wir einen gültigen JSON bereitstellen, eine vollständige Baumstruktur zurückgeben.

Die JavaScript-Methoden Eval, getKeys und getProperty bieten Bausteine ​​zum Überprüfen und Lesen von JSON.

In Verbindung mit einer rekursiven Funktion in VBA können wir alle Schlüssel (bis zur n-ten Ebene) in einer JSON-Zeichenfolge durchlaufen. Mit einem Tree-Steuerelement (in diesem Artikel) oder einem Wörterbuch oder sogar einem einfachen Arbeitsblatt können wir die JSON-Daten nach Bedarf anordnen.

Voller VBA-Code hier.Mit JavaScript-Funktionen zum Parsen von JSON können wir, zusätzlich zu ScriptControl, einen Parser in VBA erstellen, der jeden einzelnen Datenpunkt innerhalb des JSON auflistet. Unabhängig davon, wie verschachtelt oder komplex die Datenstruktur ist, wird dieser Parser, solange wir einen gültigen JSON bereitstellen, eine vollständige Baumstruktur zurückgeben.

Die JavaScript-Methoden Eval, getKeys und getProperty bieten Bausteine ​​zum Überprüfen und Lesen von JSON.

In Verbindung mit einer rekursiven Funktion in VBA können wir alle Schlüssel (bis zur n-ten Ebene) in einer JSON-Zeichenfolge durchlaufen. Mit einem Tree-Steuerelement (in diesem Artikel) oder einem Wörterbuch oder sogar einem einfachen Arbeitsblatt können wir die JSON-Daten nach Bedarf anordnen.

Voller VBA-Code hier.


UPDATE: Eine sicherere Methode zum Analysieren von JSON als die Verwendung von Eval gefunden. Dieser Blogpost zeigt die Gefahren von Eval ... exceldevelopmentplatform.blogspot.com/2018/01/…

Spät zu dieser Party, aber sorry Jungs, aber bei weitem der einfachste Weg ist, Microsoft Script Control zu verwenden. Ein Beispielcode, der VBA.CallByName zum Drill-In verwendet

'Tools->References->
'Microsoft Script Control 1.0;  {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx

Private Sub TestJSONParsingWithCallByName()

    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 VBA.CallByName(objJSON, "key1", VbGet) = "value1"
    Debug.Assert VBA.CallByName(VBA.CallByName(objJSON, "key2", VbGet), "key3", VbGet) = "value3"

End Sub

Ich habe tatsächlich eine Reihe von Fragen und Antworten zu JSON / VBA-verwandten Themen gemacht.

Q1 In Excel VBA unter Windows, wie kann man das Problem der Punktsyntax-Traversierung von geparsten JSON, die durch das Großbuchungsverhalten der IDE gebrochen ist, abschwächen?

Q2 In Excel VBA unter Windows, wie durchläuft ein JSON-Array analysiert?

Q3 In Excel VBA unter Windows, wie erhält man eine stringifizierte JSON-Repräsentation anstelle von "[object Object]" für geparste JSON-Variablen?

Q4 In Windows Excel VBA, wie Sie JSON-Schlüssel zum Präventieren erhalten "Laufzeitfehler '438': Objekt unterstützt diese Eigenschaft oder Methode nicht"?

F5 In Excel VBA unter Windows, für geparste JSON-Variablen, was ist diese JScriptTypeInfo überhaupt?


Ich weiß, dass dies eine alte Frage ist, aber meine Antwort wird hoffentlich eine große Hilfe für andere sein, die weiter auf diese Seite kommen, nachdem sie nach "vba json" gesucht haben.

Ich fand diese page sehr hilfreich. Es bietet mehrere Excel-kompatible VBA-Klassen, die sich mit der Verarbeitung von Daten im JSON-Format befassen.


Ich musste auch nach einer Lösung für dieses Problem suchen und schließlich stieß ich auf moment.js, die eine nette Bibliothek ist, die dieses Datumsformat analysieren kann und vieles mehr.

var d = moment(yourdatestring)

Es hat mir Kopfschmerzen bereitet, also dachte ich, ich würde es mit dir teilen. :)
Sie können mehr Informationen darüber hier finden: http://momentjs.com/





web-services json vba serialization vb6