version=2.9.1 vdate=16.01.2020 fname=lib_json.bas ns=%NAMESPACE% fpath=/vba/cast {{keywords>vba,json,array,dictionary,collection}} ====== [VBA] JSON ====== //Funktionen rund um JSON-Strings: obj2json() und json2obj().// ==Version %%version%% %%vdate%%== >//Das Modul hat versteckte Attribute. Damit diese aktiv übernommen werden reicht es nicht aus, den Code in ein neues Modul zu kopieren. Man muss das Modul aus der Datei nach VBA importieren.// >{{popup>:vba:vba_importfile.png|Bild zum Import}} {{%%fname%%|Download %%fname%% (V-%%version%%)}} Für mehrere Projekte brauche ich JSON. Ich arbeitete bisher mit [[ http://www.ediy.co.nz/vbjson-json-parser-library-in-vb6-xidc55680.html|VB-JSON]]. Aber irgendwie störte es mich, dafür jeweils 2 Klassen und ein Modul zu kopieren. Bei der Analyse des Codes war ich erstaunt, dass er ohne Reguläre Ausdrücke arbeitet. Darum setzte ich mich mal hin, eine eigene Version zu erstellen. Messungen haben ergeben, dass beide etwa gleich schnell sind. Ich versuchte mich möglichst nahe an [[wp>JavaScript Object Notation]] hinzukommen. Nur wenn man beim JSON erstrellen den Parameter jqmInternalArrayPrefix mitgibt, kommen %%TypenPrefixe%% vor die [] um zu definieren ob es sich um ein Array oder eine Collection handelt ===== Definition ===== ==== obj2json ==== Public Function obj2json( _ ByRef iObj As Variant, _ Optional ByVal iEncodeParams As jsonEncodeParams = jqmDefault _ ) As String === Parameterliste === ***iObj ** Das Objekt (Dictionary, Collection, Array), welches in ein JSON-String geschrieben werden soll ***//iEncodeParams//** Angabe, was für einAnführungszeichen verwendet werden soll === Return === Gibt ein JSON-String zurück ==== json2obj ==== Public Function json2obj( _ ByVal iString As Variant, _ Optional ByVal iParams As jsonDecodeParams = jrtDefault, _ Optional ByRef oObj As Variant) As Variant === Parameterliste === ***iString ** JSON-String, der geparst werden soll ***//iParams//** Steuert, ob [...] als Array oder als Collection zurückgegeben wird ***//oObj//** das geparste Objekt, analog zurm Returnvalue. Auf diese Art muss man den Return-Wert nicht zuerst prüfen ob es ein Array oder ein Object ist === Return === Ein Dictionary-, Collection-Object oder ein Variant-Array ==== Enumerator ==== === jsonEncodeParams === Einstellung, ob Strings im JSON in ' oder in " gefasst werden sollen Public Enum jsonEncodeParams jqmDoubleQuote = 2 ^ 1 'Umfasst die Values mit einem " jqmSingleQuote = 2 ^ 2 'Umfasst die Values mit einem ' jqmForceObject = 2 ^ 3 'Wandelt Arrays in Objekte (Dictionaries) jqmInternalArrayPrefix = 2 ^ 4 'Der JSON-String wird mit eigenen Prefixen bei Array und Collection mitgeliefert jqmReverseSolidusAsUnicode = 2 ^ 5 'Ein \ in einem String wird nicht als \\ sondern als Unicode gaparst jqmNoErrorForWrongType = 2 ^ 6 'Wenn ein nicht parsbarer Wert kommt, den TypeName() ausgeben jqmDefault = jqmDoubleQuote End Enum === jsonDecodeParams=== Einstellungen, ob [...] in ein Array oder in eine Collection geschrieben werden soll Public Enum jsonDecodeParams jrtCollection = 2 ^ 1 'Als Collection jrtArray = 2 ^ 2 'Als Array jrtDictionary = 2 ^ 3 'Als Dictionary jrtNotCastValue = 2 ^ 4 'cast der Values verhindern jrtEmptyList = 2 ^ 5 'Angabe, ob bei einem Leeren String eine Collection/Array/Dictionary zurückgegeben werden soll jrtSingle2List = 2 ^ 6 'Parst ein einzelnesItem zu einer Liste jrtDefault = jrtArray End Enum ===== Anwendungsbeispiele ===== Hier einige Anwendungsbeispiele > Für die Ausgabe der Resultate verwendete ich die Funktion [[:vba:functions:print_r:]]. ==== obj2json ==== === 1) Ein Einfacher Zahlenarray === '1) Einfacher Array print_r obj2json(array(1,2,3)) '[1,2,3]' === 2) Einfacher Stringarray === '2a) Array mit Texten und doppelten Anführungszeichen print_r obj2json(array("a","b","c")) '["a","b","c"]' '2b) Dito mit einfachen Anführungszeichen print_r obj2json(array("a","b","c"), jqmSingleQuote) '['a','b','c']' === 3) Ein komplexeres Beispiel === Public Sub testObj2Json() Dim c As New Collection Dim d As New Dictionary c.add True 'Boolen-Wert c.add Array(1, 2, 3) 'Normaler Zehlenarray d.add "t1", "a" & vbTab & "b" 'Text mit Tabulator d.add "t2", "a¦'b':{1....n}" 'Text mit Sonderzeichen, ' und {} c.add d c.add Null 'Null c.add Now 'Datum/Urhzeit Debug.Print "'Object" print_r c 'Ganze Collection c anzeigen Debug.Print "'JSON-String" print_r obj2json(c, jqmSingleQuote) Set d = Nothing Set c = Nothing End Sub Und die Ausgabe davon 'Object ( [1] => True [2] => ( [0] => 1 [1] => 2 [2] => 3 ) [3] => ( [t1] => 'a\tb' [t2] => 'a¦'b':{1....n}' ) [4] => [5] => 26.11.2014 12:37:03 ) 'JSON-String '[true,[1,2,3],{'t1':'a\u0009b','t2':'a\u00A6\u0027b\u0027:{1....n}'},null,2014-11-26T12:37:03]' ==== json2obj ==== Und alles wieder zurück === 1) Einfaches Zahlenarray/Collection === 'Als Array print_r json2obj("[1,2,3]") ( [0] => 1 [1] => 2 [2] => 3 ) 'Als Collection print_r json2obj("[1,2,3]", jrtCollection) ( [1] => 1 [2] => 2 [3] => 3 ) === 2) Einfacher Stringarray === '2a) Array mit Texten und doppelten Anführungszeichen print_r json2obj("[""a"",""b"",""c""]") ( [0] => 'a' [1] => 'b' [2] => 'c' ) '2b) Dito mit einfachen Anführungszeichen print_r json2obj("['a','b','c']") ( [0] => 'a' [1] => 'b' [2] => 'c' ) === 3) Ein komplexeres Beispiel === print_r json2obj("[true,[1,2,3],{'t1':'a\tb','t2':'a\u00A6\'b\'\:{1....n}'},null,'2014-02-24T11:11:41']") ( [0] => True [1] => ( [0] => 1 [1] => 2 [2] => 3 ) [2] => ( [t1] => 'a\tb' [t2] => 'a¦'b'\:{1....n}' ) [3] => 'null' [4] => 24.02.2014 11:11:41 ) === 4) Mit interner ArrayPrefix === Ich verwende in diesem Beispiel die Funkionen [[vba:cast:cdict]] und [[vba:cast:ccollection]] im ein Dictionary bzw. eine Collection zu erstellen. 'Normaler cast print_r obj2json(cCollection(1,"c",cDict("b",array(1,2)))) '[1,"c",{"b":[1,2]}]' 'Mit jqmInternalArrayPrefix print_r obj2json(cCollection(1,"c",cDict("b",array(1,2))), jqmInternalArrayPrefix) '#C[1,'c',{'b':#A[1,2]}]' 'Und die Rückwandlung ohne den Prefix. Beachte, aus dem ursprünglichen Collection wurde ein Array print_r json2obj("[1,'c',{'b':[1,2]}]") ( [0] => 1 [1] => 'c' [2] => ( [b] => ( [0] => 1 [1] => 2 ) ) ) 'Und mit PRefixen wird der Richtige Listentyp wieder hergestellt print_r json2obj("#C[1,'c',{'b':#A[1,2]}]") ( [1] => 1 [2] => 'c' [3] => ( [b] => ( [0] => 1 [1] => 2 ) ) ) === 5) Wenn der String kein JSON-String ist === Wenn der übergeben String kein JSON-String ist, gibt es verschiedene Möglichkeiten 'Standard: Es wird kein Objekt erstellt print_r json2obj("abc") 'String in ein Array parsen print_r json2obj("abc", jrtSingle2List) ( [0] => 'abc' ) 'String in ein Dictionary parsen print_r json2obj("abc", jrtSingle2List + jrtDictionary) ( [0] => 'abc' ) === 6) Werte Nicht Casten === Normalerweise werdend ie Werte in passende Typen umgewandelt print_r json2obj("[Null,True,12.3]") ( [0] => [1] => True [2] => 12.3 ) Mittels jrtNotCastValue kann dies aber auch unterbunden werden print_r json2obj("[Null,True,12.3]", jrtNotCastValue) ( [0] => 'Null' [1] => 'True' [2] => '12.3' ) === 7) Leere Listen erstellen === print_r json2obj(null) print_r json2obj(null,jrtEmptyList) () print_r json2obj(empty,jrtEmptyList) () print_r json2obj("[1]",jrtEmptyList) ( [0] => 1 ) ===== Code ===== {{%%fname%%|Download %%fname%% (V-%%version%%)}}