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%%)}}