Load aJSON string into a data structure. Also, create a new data structure and serialize it into JSON.
Use objects and arrays (as appropriate for your language) and make sure your JSON is valid (https://jsonformatter.org).
T.serializable Person String firstName, lastName Int age T PhoneNumber String ntype String number [PhoneNumber] phoneNumbers [String] childrenPerson pjson:to_object(‘{ "firstName": "John", "lastName": "Smith", "age": 27, "phoneNumbers": [ { "ntype": "home", "number": "212 555-1234" }, { "ntype": "office", "number": "646 555-4567" } ], "children": ["Mary", "Kate"]}’, &p)p.phoneNumbers.pop(0)p.children.append(‘Alex’)print(json:from_object(p))
{ "age": 27, "children": [ "Mary", "Kate", "Alex" ], "firstName": "John", "lastName": "Smith", "phoneNumbers": [ { "ntype": "office", "number": "646 555-4567" } ]}
8th uses JSON as its data description language, so:
[1,2,3] . cr
Prints an array of [1,2,3].
Converting a string to an object:
"{ \"a\": 123 }" json>
Takes the string and converts to the JSON object (which is an 8th object). Convert back to a string:
{"a": 123} >s
That takes the object and converts to the JSON string given above.
withAda.Text_IO;withGNATCOLL.JSON;procedureJSON_TestisuseAda.Text_IO;useGNATCOLL.JSON;JSON_String:constantString:="{""name"":""Pingu"",""born"":1986}";Penguin:JSON_Value:=Create_Object;Parents:JSON_Array;beginPenguin.Set_Field(Field_Name=>"name",Field=>"Linux");Penguin.Set_Field(Field_Name=>"born",Field=>1992);Append(Parents,Create("Linus Torvalds"));Append(Parents,Create("Alan Cox"));Append(Parents,Create("Greg Kroah-Hartman"));Penguin.Set_Field(Field_Name=>"parents",Field=>Parents);Put_Line(Penguin.Write);Penguin:=Read(JSON_String,"json.errors");Penguin.Set_Field(Field_Name=>"born",Field=>1986);Parents:=Empty_Array;Append(Parents,Create("Otmar Gutmann"));Append(Parents,Create("Silvio Mazzola"));Penguin.Set_Field(Field_Name=>"parents",Field=>Parents);Put_Line(Penguin.Write);endJSON_Test;
{"parents":["Linus Torvalds", "Alan Cox", "Greg Kroah-Hartman"], "name":"Linux", "born":1992}{"parents":["Otmar Gutmann", "Silvio Mazzola"], "name":"Pingu", "born":1986}
withAda.Wide_Wide_Text_IO;useAda.Wide_Wide_Text_IO;withLeague.JSON.Arrays;useLeague.JSON.Arrays;withLeague.JSON.Documents;useLeague.JSON.Documents;withLeague.JSON.Objects;useLeague.JSON.Objects;withLeague.JSON.Values;useLeague.JSON.Values;withLeague.Strings;useLeague.Strings;procedureMainisfunction"+"(Item:Wide_Wide_String)returnUniversal_StringrenamesTo_Universal_String;JSON_String:constantUniversal_String:=+"{""name"":""Pingu"",""born"":1986}";Penguin:JSON_Object;Parents:JSON_Array;beginPenguin.Insert(+"name",To_JSON_Value(+"Linux"));Penguin.Insert(+"born",To_JSON_Value(1992));Parents.Append(To_JSON_Value(+"Linus Torvalds"));Parents.Append(To_JSON_Value(+"Alan Cox"));Parents.Append(To_JSON_Value(+"Greg Kroah-Hartman"));Penguin.Insert(+"parents",To_JSON_Value(Parents));Put_Line(To_JSON_Document(Penguin).To_JSON.To_Wide_Wide_String);Penguin:=From_JSON(JSON_String).To_JSON_Object;Parents:=Empty_JSON_Array;Parents.Append(To_JSON_Value(+"Otmar Gutmann"));Parents.Append(To_JSON_Value(+"Silvio Mazzola"));Penguin.Insert(+"parents",To_JSON_Value(Parents));Put_Line(To_JSON_Document(Penguin).To_JSON.To_Wide_Wide_String);endMain;
{"parents":["Linus Torvalds","Alan Cox","Greg Kroah-Hartman"],"name":"Linux","born":1992}{"parents":["Otmar Gutmann","Silvio Mazzola"],"name":"Pingu","born":1986}
JSON parser (maybe failes with "invalid JSON" error)
json:{[data]catch[eval[,|{[y]catch[{":" = "="; "[" = "<"; "]" = ">"; "," = ";"}[y];{x};{[]y}]}'("""("(\\.|[^\\"])*"|\-?[0-9]+(\.[0-9]+)?|\{|\}|\[|\]|\:|\,)"""~data)["strings"]];{x};{error["Invalid JSON"]}]}
// Parse JSON//// Nigel Galloway - April 27th., 2012//grammarJSON;@members{StringIndent="";}Number:(('0')|('-'?('1'..'9')('0'..'9')*))('.'('0'..'9')+)?(('e'|'E')('+'|'-')?('0'..'9')+)?;WS:(' '|'\t'|'\r'|'\n'){skip();};Tz:' '..'!'|'#'..'['|']'..'~';Control:'\\'('"'|'\\'|'/'|'b'|'f'|'n'|'r'|'t'|UCode);UCode:'u'('0'..'9'|'a'..'f'|'A'..'F')('0'..'9'|'a'..'f'|'A'..'F')('0'..'9'|'a'..'f'|'A'..'F')('0'..'9'|'a'..'f'|'A'..'F');Keyword:'true'|'false'|'null';String:'"'(Control?Tz)*'"';object:'{'{System.out.println(Indent+"{Object}");Indent+=" ";}(pair(','pair*)*)?'}'{Indent=Indent.substring(4);};pair:e=String{System.out.println(Indent+"{Property}\t"+$e.text);}':'value;value:Number{System.out.println(Indent+"{Number} \t"+$Number.text);}|object|String{System.out.println(Indent+"{String} \t"+$String.text);}|Keyword{System.out.println(Indent+"{Keyword} \t"+$Keyword.text);}|array;array:'['{System.out.println(Indent+"Array");Indent+=" ";}(value(','value)*)?']'{Indent=Indent.substring(4);};
Produces:
>java Test{ "Nigel" : -110.2e-13 , "Fred" : { "Joe" : [3,true,"Nigel"] } "Harry" : [23,"Hello"]}^Z{Object} {Property} "Nigel" {Number} -110.2e-13 {Property} "Fred" {Object} {Property} "Joe" Array {Number} 3 {Keyword} true {String} "Nigel" {Property} "Harry" Array {Number} 23 {String} "Hello"
JSON serialization and deserialization is built in
class TestClass{ String foo {get;set;} Integer bar {get;set;}}TestClass testObj = new TestClass();testObj.foo = 'ABC';testObj.bar = 123;String serializedString = JSON.serialize(testObj);TestClass deserializedObject = (TestClass)JSON.deserialize(serializedString, TestClass.class);//"testObj.foo == deserializedObject.foo" is true//"testObj.bar == deserializedObject.bar" is true
printread.json{{ "foo": 1, "bar": [10, "apples"] }}object:#[name:"john"surname:"doe"address:#[number:10street:"unknown"country:"Spain"]married:false]printwrite.jsonø object
[foo:1 bar:[10 apples]]{ "name": "john", "surname": "doe", "address": { "number": 10, "street": "unknown", "country": "Spain" }, "married": false}
Bracmat has built-in functionality for reading and writing JSON data.A full roundtrip from JSON file over a Bracmat internal representation back to a JSON file looks like this:
put$(jsn$(get$("input.json",JSN)),"output.JSN,NEW)
Let us split this into separate steps.
To read a JSON file "myfile.json", use
get$("myfile.json",JSN)
If the JSON data, e.g, an array, has to be read from a string value, use theMEM
option on theget
function, like this:
get$("[1,2,3]",JSN,MEM)
To convert the corresponding Bracmat data structure(,1 2 3)
back to a JSON string, use
jsn$(,1 2 3)
To write a JSON string"[1,2,3]"
to a file "array.json", use
put$("[1,2,3]","array.json",NEW)
Bracmat and JSON/Javascript do far from represent data in similar ways. Bracmat has arbitrary-precision arithmetic. Floating point numbers are not a native datatype in Bracmat. (But since 2023, Bracmat has an object type, UFP, that handles floating point operations using C "double"s.)Bracmat has no Boolean valuestrue
andfalse
and nonull
value.Bracmat has arrays and objects, but they are second class citizens. Most data is best represented as binary tree structures, with binary operators like the plus, comma, dot or white space sitting in the nodes and the atomic parts of the data sitting in the leaves. The only data type that is somewhat the same in JSON/JavaScript and Bracmat is the string, but there is a slight difference in the representation of strings in code. Whereas strings in JSON always are enclosed in quotation marks, this is only necessary in Bracmat if a string contains operator characters or starts with flag characters.
Here are the mapping rules:
Bracmat representation | JSON representation | Comment |
---|---|---|
null | null | |
true | true | |
false | false | |
12345 | 12345 | |
2/3 | 6.66666666666666666667E-1 | Most rational numbers cannot be represented as floating point numbers, see note (1) |
(.string) | "string" | |
(,1 2) | [1,2] | |
((a.1)+(b.2),) | {"a":1,"b":2} | The+ operator sorts its arguments. See note (2) |
Note (1) All floating point numbers can be represented as rational numbers. Therefore, a round trip of a Bracmat number to a JSON number and back to a Bracmat number can give a different number:2/3
becomes666666666666666666667/1000000000000000000000
.
Note (2) The objects{"a":1,"b":2}
and{"b":2,"a":1}
are equivalent in Bracmat, as they are both internally represented as((a.1)+(b.2),)
Here is a full round trip of the following JSON data, which is assumed to be stored in a file "rosetta.json". The employed code is:
( get$("rosetta.json",JSN):?json& lst$(json,"json.bra",NEW)& put$(jsn$!json,"rosetta-roundtrip.json",NEW))
rosetta.json:
[ { "ape": "\"King Kong\"", "C:\\projects": "23", "OS\/2": { "White\b\f\n\r\tspace": {} }, "Cyrillic": [ "Ya \u042F", "ya \u044f" ] }, "TAB", [ "elem1", "elem2" ], "Bernhard", [], [ "x", "y", "z" ], [ "true", true, false, null ], { "fixed point": [ 3.4, 0.00987654321, -10.01, 56.78, 56.780 ] }, { "floating point": [ 0e0, 0.0000006e-007, 17E123, -17.87E123, 0.87E123, 286e400 ] }, { "integer": [ -0, 0, -5, 1234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567890 ] }]
Content of json.bra:
json= , ( ("C:\\projects"..23) + (Cyrillic.,(."Ya Я") (."ya я")) + (OS/2.("White\b\f\rspace".0,),) + (ape.."\"King Kong\"") , ) (.TAB\t) (,(.elem1) (.elem2)) (.Bernhard) (,) (,(.x) (.y) (.z)) (,(.true) true false null) ( ("fixed point".,34/10 987654321/100000000000 -1001/100 5678/100 56780/1000) , ) ( ( "floating point" . , 0 6/100000000000000 17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -17870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 2860000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ... ) , ) ( ( integer . , -0 0 -5 1234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891 ... ) , );
The file "rosetta-roundtrip.json" will contain a single line. There is no beautify option when constructing a JSON string using thejsn
function. Thehttp://jsonlint.com service can be used to view the JSON string, but notice that some of the numbers are to big to be handled by this service and are turned into null values.
Content of rosetta-roundtrip.json (1402 characters):
[{"C:\\projects":"23","Cyrillic":["Ya Я","ya я"],"OS/2":{"White\b\f\n\r\tspace":{}},"ape":"\"King Kong\""},"TAB\t",["elem1","elem2"],"Bernhard",[],["x","y","z"],["true",true,false,null],{"fixed point":[3.4,0.00987654321,-10.01,56.78,56.78]},{"floating point":[0,0.00000000000006,17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,-17870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,2860000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]},{"integer":[-0,0,-5,1234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567890]}]
After manual reformatting, again shortened where lines run off the screen:
[ { "C:\\projects": "23", "Cyrillic": [ "Ya Я", "ya я" ], "OS/2": { "White\b\f\n\r\tspace": {} }, "ape": "\"King Kong\"" }, "TAB\t", [ "elem1", "elem2" ], "Bernhard", [], [ "x", "y", "z" ], [ "true", true, false, null ], { "fixed point": [ 3.4, 0.00987654321, -10.01, 56.78, 56.78 ] }, { "floating point": [ 0, 0.00000000000006, 17000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, -17870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 870000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 2860000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ... ] }, { "integer": [ -0, 0, -5, 1234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891234567891 ... ] }]
Reads a snippet of JSON intoYAJL's tree format, then walks the tree to print it back out again. The tree contains numbers both in an unparsed, string form, and also converted to long long or double when possible. The example below demonstrates both ways of dealing with numbers.
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<yajl/yajl_tree.h>#include<yajl/yajl_gen.h>staticvoidprint_callback(void*ctx,constchar*str,size_tlen){FILE*f=(FILE*)ctx;fwrite(str,1,len,f);}staticvoidcheck_status(yajl_gen_statusstatus){if(status!=yajl_gen_status_ok){fprintf(stderr,"yajl_gen_status was %d\n",(int)status);exit(EXIT_FAILURE);}}staticvoidserialize_value(yajl_gengen,yajl_valval,intparse_numbers){size_ti;switch(val->type){caseyajl_t_string:check_status(yajl_gen_string(gen,(constunsignedchar*)val->u.string,strlen(val->u.string)));break;caseyajl_t_number:if(parse_numbers&&YAJL_IS_INTEGER(val))check_status(yajl_gen_integer(gen,YAJL_GET_INTEGER(val)));elseif(parse_numbers&&YAJL_IS_DOUBLE(val))check_status(yajl_gen_double(gen,YAJL_GET_DOUBLE(val)));elsecheck_status(yajl_gen_number(gen,YAJL_GET_NUMBER(val),strlen(YAJL_GET_NUMBER(val))));break;caseyajl_t_object:check_status(yajl_gen_map_open(gen));for(i=0;i<val->u.object.len;i++){check_status(yajl_gen_string(gen,(constunsignedchar*)val->u.object.keys[i],strlen(val->u.object.keys[i])));serialize_value(gen,val->u.object.values[i],parse_numbers);}check_status(yajl_gen_map_close(gen));break;caseyajl_t_array:check_status(yajl_gen_array_open(gen));for(i=0;i<val->u.array.len;i++)serialize_value(gen,val->u.array.values[i],parse_numbers);check_status(yajl_gen_array_close(gen));break;caseyajl_t_true:check_status(yajl_gen_bool(gen,1));break;caseyajl_t_false:check_status(yajl_gen_bool(gen,0));break;caseyajl_t_null:check_status(yajl_gen_null(gen));break;default:fprintf(stderr,"unexpectedly got type %d\n",(int)val->type);exit(EXIT_FAILURE);}}staticvoidprint_tree(FILE*f,yajl_valtree,intparse_numbers){yajl_gengen;gen=yajl_gen_alloc(NULL);if(!gen){fprintf(stderr,"yajl_gen_alloc failed\n");exit(EXIT_FAILURE);}if(0==yajl_gen_config(gen,yajl_gen_beautify,1)||0==yajl_gen_config(gen,yajl_gen_validate_utf8,1)||0==yajl_gen_config(gen,yajl_gen_print_callback,print_callback,f)){fprintf(stderr,"yajl_gen_config failed\n");exit(EXIT_FAILURE);}serialize_value(gen,tree,parse_numbers);yajl_gen_free(gen);}intmain(intargc,char**argv){charerr_buf[200];constchar*json="{\"pi\": 3.14,\"large number\": 123456789123456789123456789, ""\"an array\": [-1, true, false, null,\"foo\"]}";yajl_valtree;tree=yajl_tree_parse(json,err_buf,sizeof(err_buf));if(!tree){fprintf(stderr,"parsing failed because: %s\n",err_buf);returnEXIT_FAILURE;}printf("Treating numbers as strings...\n");print_tree(stdout,tree,0);printf("Parsing numbers to long long or double...\n");print_tree(stdout,tree,1);yajl_tree_free(tree);returnEXIT_SUCCESS;}
Treating numbers as strings...{ "pi": 3.14, "large number": 123456789123456789123456789, "an array": [ -1, true, false, null, "foo" ]}Parsing numbers to long long or double...{ "pi": 3.1400000000000001243, "large number": 1.2345678912345679134e+26, "an array": [ -1, true, false, null, "foo" ]}
This uses theJavaScriptSerializer class which was shipped with .NET 3.5.
usingSystem;usingSystem.Collections.Generic;usingSystem.Web.Script.Serialization;classProgram{staticvoidMain(){varpeople=newDictionary<string,object>{{"1","John"},{"2","Susan"}};varserializer=newJavaScriptSerializer();varjson=serializer.Serialize(people);Console.WriteLine(json);vardeserialized=serializer.Deserialize<Dictionary<string,object>>(json);Console.WriteLine(deserialized["2"]);varjsonObject=serializer.DeserializeObject(@"{ ""foo"": 1, ""bar"": [10, ""apples""] }");vardata=jsonObjectasDictionary<string,object>;vararray=data["bar"]asobject[];Console.WriteLine(array[1]);}}
#include"Core/Core.h"usingnamespaceUpp;CONSOLE_APP_MAIN{JsonArraya;a<<Json("name","John")("phone","1234567")<<Json("name","Susan")("phone","654321");Stringtxt=~a;Cout()<<txt<<'\n';Valuev=ParseJSON(txt);for(inti=0;i<v.GetCount();i++)Cout()<<v[i]["name"]<<' '<<v[i]["phone"]<<'\n';}
C++11
#include<iostream>#include<iomanip> // std::setw#include<sstream>#include<cassert>#include"json.hpp"usingjson=nlohmann::json;intmain(intargc,char*argv[]){std::stringconstexpected=R"delim123({ "answer": { "everything": 42 }, "happy": true, "list": [ 1, 0, 2 ], "name": "Niels", "nothing": null, "object": { "currency": "USD", "value": 42.99 }, "pi": 3.141})delim123";jsonconstjexpected=json::parse(expected);assert(jexpected["list"][1].get<int>()==0);assert(jexpected["object"]["currency"]=="USD");jsonjhandmade={{"pi",3.141},{"happy",true},{"name","Niels"},{"nothing",nullptr},{"answer",{{"everything",42}}},{"list",{1,0,2}},{"object",{{"currency","USD"},{"value",42.99}}}};assert(jexpected==jhandmade);std::stringstreamjhandmade_stream;jhandmade_stream<<std::setw(4)<<jhandmade;std::stringjhandmade_string=jhandmade.dump(4);assert(jhandmade_string==expected);assert(jhandmade_stream.str()==expected);return0;}
Class Sample.JSON [ Abstract ]{ClassMethod GetPerson(ByRef pParms, Output pObject As %RegisteredObject) As %Status{Set pObject=##class(Sample.Person).%OpenId(pParms("oid"))Quit $$$OK}}
SAMPLES>Set pParms("oid")=5 SAMPLES>Do ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONFromObject("", "Sample.JSON", "GetPerson", .pParms){"_class":"Sample.Person","_id":5,"Age":80,"DOB":33603,"FavoriteColors":["White","Purple"],"Home": {"_class":"Sample.Address", "City":"Denver", "State":"SC", "Street":"6932 Second Court", "Zip":51309 },"Name":"Tillem,Will D.","Office": {"_class":"Sample.Address", "City":"Queensbury", "State":"NV", "Street":"1169 Main Drive", "Zip":25310 },"SSN":"729-56-4619","Spouse":null}SAMPLES>Read json{"_class":"Sample.Person","_id":5,"Age":80,"DOB":33603,"FavoriteColors":["White","Purple"],"Home":{"_class":"Sample.Address","City":"Denver","State":"S C","Street":"6932 Second Court","Zip":51309},"Name":"Tillem,Will D.","O ffice":{"_class":"Sample.Address","City":"Queensbury","State":"NV"," Street":"1169 Main Drive","Zip":25310},"SSN":"729-56-4619","Spouse":null}SAMPLES>Do ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(json, "", .person)SAMPLES>Write person.NameTillem,Will D.SAMPLES>Write person.FavoriteColors.Count()2SAMPLES>Write person.Home.Street6932 Second Court
Library:data.json
(use'clojure.data.json); Load as Clojure data structures and bind the resulting structure to 'json-map'.(defjson-map(read-json"{ \"foo\": 1, \"bar\": [10, \"apples\"] }")); Use pr-str to print out the Clojure representation of the JSON created by read-json.(pr-strjson-map); Pretty-print the Clojure representation of JSON. We've come full circle.(pprint-jsonjson-map)
sample=blue:[1,2]ocean:'water'json_string=JSON.stringifysamplejson_obj=JSON.parsejson_stringconsole.logjson_stringconsole.logjson_obj
<!--- Create sample JSON structure ---><cfsetjson={string:"Hello",number:42,arrayOfNumbers:[1,2,3,4],arrayOfStrings:["One","Two","Three","Four"],arrayOfAnything:[1,"One",[1,"One"],{one:1}],object:{key:"value"}}/><!--- Convert to JSON string ---><cfsetjsonSerialized=serializeJSON(json)/><!--- Convert back to ColdFusion ---><cfsetjsonDeserialized=deserializeJSON(jsonSerialized)/><!--- Output examples ---><cfdumpvar="#jsonSerialized#"/><cfdumpvar="#jsonDeserialized#"/>
Library:cl-json
(ql:quickload'("cl-json"))(json:encode-json'#(((foo.(123))(bar.t)(baz.#\!))"quux"4/174.25))(print(with-input-from-string(s"{\"foo\": [1, 2, 3], \"bar\": true, \"baz\": \"!\"}")(json:decode-jsons)))
To load "cl-json": Load 1 ASDF system: cl-json; Loading "cl-json"[{"foo":[1,2,3],"bar":true,"baz":"!"},"quux",0.23529412,4.25]((:FOO 1 2 3) (:BAR . T) (:BAZ . "!"))
Before 1.0.0:
require"json_mapping"classFooJSON.mapping(num:Int64,array:Array(String),)enddefjsonfoo=Foo.from_json(%({"num": 1, "array": ["a", "b"]}))puts("#{foo.num}#{foo.array}")puts(foo.to_json)end
After 1.0.0:
require"json"classFooincludeJSON::Serializablepropertynum:Int64propertyarray:Array(String)enddefjsonfoo=Foo.from_json(%({"num": 1, "array": ["a", "b"]}))puts("#{foo.num}#{foo.array}")puts(foo.to_json)end
Output:
1 ["a", "b"]{"num":1,"array":["a","b"]}
importstd.stdio,std.json;voidmain(){autoj=parseJSON(`{ "foo": 1, "bar": [10, "apples"] }`);writeln(toJSON(&j));}
{"foo":1,"bar":[10,"apples"]}
import'dart:convert'showjsonDecode,jsonEncode;main(){varjson_string='''{"rosetta_code": {"task": "json","language": "dart","descriptions": [ "fun!", "easy to learn!", "awesome!" ]}}''';// decode string into Map<String, dynamic>varjson_object=jsonDecode(json_string);for(vardescriptioninjson_object["rosetta_code"]["descriptions"])print("dart is $description");vardart={"compiled":true,"interpreted":true,"creator(s)":["Lars Bak","Kasper Lund"],"development company":"Google"};varas_json_text=jsonEncode(dart);assert(as_json_text=='{"compiled":true,"interpreted":true,"creator(s)":["Lars Bak","Kasper Lund"],"development company":"Google"}');}
dart is fun!dart is easy to learn!dart is awesome!
import'dart:convert';main(){vardata=jsonDecode('{ "foo": 1, "bar": [10, "apples"] }');varsample={"blue":[1,2],"ocean":"water"};varjson_string=jsonEncode(sample);}
DuckDB supports JSON as though it were one of the pre-defined types.Conversion to JSON is typically as simple as appending `::JSON`to an expression, as illustrated below.
Files containing one or more JSON values can be read inseveral ways, depending on how the JSON is organized andon whether any kind of conversion is required.
For example, a file containing a single array of JSON objects canbe conveniently used to populate a table with data-driven determinationof the column names.
Similarly, one might wish to import an NDJSON file as a table withone row per line. For example, if colors.json is a file containing the text:
{ "white": [255, 255, 255] }{ "red": [195, 176, 145] }
then the statement
from'colors.json';
yields:
┌─────────────────┬─────────────────┐│ white │ red ││ int64[] │ int64[] │├─────────────────┼─────────────────┤│ [255, 255, 255] │ ││ │ [195, 176, 145] │└─────────────────┴─────────────────┘
But if we want to read the values as two separate JSON objects, we could write:
selectjson::JSONfromread_csv('colors.json',header=false,sep='\t')t(json);
with the result:
┌──────────────────────────────┐│ CAST("json" AS "JSON") ││ json │├──────────────────────────────┤│ { "white": [255, 255, 255] } ││ { "red": [195, 176, 145] } │└──────────────────────────────┘
DuckDB provides extensive support for convertingrows and columns, and indeed DuckDB values in general, to JSON.These conversions can often be accomplished simply by "casting"a value to JSON as illustrated by the following query and the responseit generates:
select 1, 1::JSON as int, [1,2], [1,2]::JSON as list, {'a':1}, {'a':1}::JSON as struct;┌───────┬──────┬───────────────────────┬───────┬──────────────────────────┬─────────┐│ 1 │ int │ main.list_value(1, 2) │ list │ main.struct_pack(a := 1) │ struct ││ int32 │ json │ int32[] │ json │ struct(a integer) │ json │├───────┼──────┼───────────────────────┼───────┼──────────────────────────┼─────────┤│ 1 │ 1 │ [1, 2] │ [1,2] │ {'a': 1} │ {"a":1} │└───────┴──────┴───────────────────────┴───────┴──────────────────────────┴─────────┘
The second row in the table above indicates the DuckDB type of the value below it.
DuckDB's COPY command can be used to export a table or the result of a query to a JSON filesimply by using .json as the suffix, e.g.
COPYtto'output.json';
Here's an informative typescript:
D COPY (select 1 as x, 2 as y) to 'output.json';D .system cat output.json{"x":1,"y":2}D COPY (select unnest([1, 2]) as a) to 'output.json';D .system cat output.json{"a":1}{"a":2}D COPY (select {'a':1, 'b': [1, 2]::JSON} as json) to 'output.json';D .system cat output.json{"json":{"a":1,"b":[1,2]}}
The COPY command has various options for governing the export to JSON,e.g. the ARRAY option for producing a single JSON array.
JSON values can also be printed (and therefore sent to a file) directly,e.g. using the `.once` dot command.
programJsonTest;{$APPTYPE CONSOLE}{$R *.res}usesSystem.SysUtils,Json;typeTJsonObjectHelper=classhelperforTJsonObjectpublicclassfunctionDeserialize(data:string):TJsonObject;static;functionSerialize:string;end;{ TJsonObjectHelper }classfunctionTJsonObjectHelper.Deserialize(data:string):TJsonObject;beginResult:=TJSONObject.ParseJSONValue(data)asTJsonObject;end;functionTJsonObjectHelper.Serialize:string;beginResult:=ToJson;end;varpeople,deserialized:TJsonObject;bar:TJsonArray;_json:string;beginpeople:=TJsonObject.Create();people.AddPair(TJsonPair.Create('1','John'));people.AddPair(TJsonPair.Create('2','Susan'));_json:=people.Serialize;Writeln(_json);deserialized:=TJSONObject.Deserialize(_json);Writeln(deserialized.Values['2'].Value);deserialized:=TJSONObject.Deserialize('{"foo":1 , "bar":[10,"apples"]}');bar:=deserialized.Values['bar']asTJSONArray;Writeln(bar.Items[1].Value);deserialized.Free;people.Free;Readln;end.
{"1":"John","2":"Susan"}Susanapples
Thejson library allows to import/export basic JSON types (string ,numbers, arrays) and to translate EchoLisp objects (lists, dates, ..) from/to JSON objects and types. See reference documentation [[1]].
;; JSON standard types : strings, numbers, and arrays (vectors)(export-json#(6789))→"[6,7,8,9]"(export-json#("alpha""beta""gamma"))→"["alpha","beta","gamma"]"(json-import"[6,7,8,9]")→#(6789)(json-import#<<["alpha","beta","gamma"]>>#)→#("alpha""beta""gamma");; EchoLisp types : dates, rational, complex, big int(export-json3/4)→"{"_instanceof":"Rational","a":3,"b":4}"(json-import#<<{"_instanceof":"Rational","a":666,"b":42}>>#)→111/7;; Symbols(export-json'Simon-Gallubert)→"{"_instanceof":"Symbol","name":"Simon-Gallubert"}"(json-import#<<{"_instanceof":"Symbol","name":"Antoinette-de-Gabolde"}>>#)→Antoinette-de-Gabolde;; Lists(definemy-list(export-json'(4345(67(89)))))→"{"_instanceof":"List" ,"array":[43,4,5,{"_instanceof":"List", "array":[6,7,{"_instanceof":"List", "array":[8,9],"circular":false}],"circular":false}],"circular":false}"(json-importmy-list)→(4345(67(89)));; Structures(structPerson(namepict))→#struct:Person[namepict](defineantoinette(Person"antoinette""👰"))→#(antoinette👰)(export-jsonantoinette)→"{"_instanceof":"Struct", "struct":"Person","id":17,"fields":["antoinette","👰"]}"(json-import#<<{"_instanceof":"Struct","struct":"Person","id":18,"fields":["simon","🎩"]}>>#)→#(simon🎩)
Structures used both to construct and to parse JSON strings:
record familyMemberperson person;relationships relationship[]?;endrecord personfirstName string;lastName string;age int;endrecord relationshiprelationshipType string;id int;end
Construct JSON string:
people Person[]; // Array of peoplepeople.appendElement(new Person { firstName = "Frederick", lastName = "Flintstone", age = 35} );people.appendElement(new Person { firstName = "Wilma", lastName = "Flintstone", age = 34} );people.appendElement(new Person { firstName = "Pebbles", lastName = "Flintstone", age = 2} );people.appendElement(new Person { firstName = "Bernard", lastName = "Rubble", age = 32} );people.appendElement(new Person { firstName = "Elizabeth", lastName = "Rubble", age = 29} );people.appendElement(new Person { firstName = "Bam Bam", lastName = "Rubble", age = 2} );family Dictionary; // A dictionary of family members using a uid as keyfamily["1"] = new FamilyMember{ person = people[1], relationships = [new Relationship{ relationshipType="spouse", id = 2 }, new Relationship{ relationshipType="child", id = 3}] };family["2"] = new FamilyMember{ person = people[2], relationships = [new Relationship{ relationshipType="spouse", id = 1 }, new Relationship{ relationshipType="child", id = 3}] };family["3"] = new FamilyMember{ person = people[3], relationships = [new Relationship{ relationshipType="mother", id = 2 }, new Relationship{ relationshipType="father", id = 1}] };family["4"] = new FamilyMember{ person = people[4], relationships = [new Relationship{ relationshipType="spouse", id = 5 }, new Relationship{ relationshipType="child", id = 6}] };family["5"] = new FamilyMember{ person = people[5], relationships = [new Relationship{ relationshipType="spouse", id = 4 }, new Relationship{ relationshipType="child", id = 6}] };family["6"] = new FamilyMember{ person = people[6], relationships = [new Relationship{ relationshipType="mother", id = 5 }, new Relationship{ relationshipType="father", id = 4}] };// Convert dictionary of family members to JSON stringjsonString string = jsonLib.convertToJSON(family);// Show JSON stringSysLib.writeStdout(jsonString);
{"1":{"person":{"firstName":"Frederick","lastName":"Flintstone","age":35},"relationships":[{"relationshipType":"spouse","id":2},{"relationshipType":"child","id":3}]},"2":{"person":{"firstName":"Wilma","lastName":"Flintstone","age":34},"relationships":[{"relationshipType":"spouse","id":1},{"relationshipType":"child","id":3}]},"3":{"person":{"firstName":"Pebbles","lastName":"Flintstone","age":2},"relationships":[{"relationshipType":"mother","id":2},{"relationshipType":"father","id":1}]},"4":{"person":{"firstName":"Bernard","lastName":"Rubble","age":32},"relationships":[{"relationshipType":"spouse","id":5},{"relationshipType":"child","id":6}]},"5":{"person":{"firstName":"Elizabeth","lastName":"Rubble","age":29},"relationships":[{"relationshipType":"spouse","id":4},{"relationshipType":"child","id":6}]},"6":{"person":{"firstName":"Bam Bam","lastName":"Rubble","age":2},"relationships":[{"relationshipType":"mother","id":5},{"relationshipType":"father","id":4}]}}
{ "1": { "person": { "firstName": "Frederick", "lastName": "Flintstone", "age": 35 }, "relationships": [ { "relationshipType": "spouse", "id": 2 }, { "relationshipType": "child", "id": 3 } ] },...}
Parse JSON:
// Convert JSON string into dictionary of family membersfamily Dictionary;jsonLib.convertFromJSON(jsonString, family);// List family members and their relationshipsfamilyMember FamilyMember;relation FamilyMember;keys string[] = family.getKeys();for(i int from 1 to keys.getSize())SysLib.writeStdout("----------------------------------------------------");familyMember = family[keys[i]];SysLib.writeStdout(familyMember.person.lastName + ", " + familyMember.person.firstName + " - " + familyMember.person.age);for(j int from 1 to familyMember.relationships.getSize())id string = familyMember.relationships[j].id;relation = family[id];SysLib.writeStdout(familyMember.relationships[j].relationshipType + ": " +relation.person.lastName + ", " + relation.person.firstName);endend
Flintstone, Frederick - 35spouse: Flintstone, Wilmachild: Flintstone, Pebbles----------------------------------------------------Flintstone, Wilma - 34spouse: Flintstone, Frederickchild: Flintstone, Pebbles----------------------------------------------------Flintstone, Pebbles - 2mother: Flintstone, Wilmafather: Flintstone, Frederick----------------------------------------------------Rubble, Bernard - 32spouse: Rubble, Elizabethchild: Rubble, Bam Bam----------------------------------------------------Rubble, Elizabeth - 29spouse: Rubble, Bernardchild: Rubble, Bam Bam----------------------------------------------------Rubble, Bam Bam - 2mother: Rubble, Elizabethfather: Rubble, Bernard
The examples above illustrate that it is possible to perform manual conversions to and from a JSON format but in EGL it is much more common for the programming language to handle these conversion automatically as a natural part of service invocations. Below is an example of a function definition designed to consume the Google Maps Geocoding service. The results are returned in a JSON format and parsed by EGL into records that mirror the structure of the reply.
// Service function definitionfunction geocode(address String) returns (GoogleGeocoding) { @Resource{uri = "binding:GoogleGeocodingBinding"}, @Rest{method = _GET, uriTemplate = "/json?address={address}&sensor=false", requestFormat = None, responseFormat = JSON}}// Invoke service functioncall geocode("111 Maple Street, Somewhere, CO") returning to callback;function callBack(result GoogleGeocoding in) SysLib.writeStdout(result.status); SysLib.writeStdout(result.results[1].geometry.location.lat); SysLib.writeStdout(result.results[1].geometry.location.lng);end
ELENA 4.x
import extensions;import extensions'dynamic; public program(){ var json := "{ ""foo"": 1, ""bar"": [10, ""apples""] }"; var o := json.fromJson(); console.printLine("json.foo=",o.foo); console.printLine("json.bar=",o.bar)}
json.foo=1json.bar=10,apples
Emacs 27.1 offers native JSON processing using the Jansson library.
(require'cl-lib)(cl-assert(fboundp'json-parse-string))(cl-assert(fboundp'json-serialize))(defvarexample"{\"foo\": \"bar\", \"baz\": [1, 2, 3]}")(defvarexample-object'((foo."bar")(baz.[123])));; decoding(json-parse-stringexample);=> #s(hash-table [...]));; using json.el-style options(json-parse-stringexample:object-type'alist:null-objectnil:false-object:json-false);;=> ((foo . "bar") (baz . [1 2 3]));; using plists for objects(json-parse-stringexample:object-type'plist);=> (:foo "bar" :baz [1 2 3]);; encoding(json-serializeexample-object);=> "{\"foo\":\"bar\",\"baz\":[1,2,3]}"
(require'json)(defvarexample"{\"foo\": \"bar\", \"baz\": [1, 2, 3]}")(defvarexample-object'((foo."bar")(baz.[123])));; decoding(json-read-from-stringexample);=> ((foo . "bar") (baz . [1 2 3]));; using plists for objects(let((json-object-type'plist))(json-read-from-string));=> (:foo "bar" :baz [1 2 3]);; using hash tables for objects(let((json-object-type'hash-table))(json-read-from-stringexample));=> #<hash-table equal 2/65 0x1563c39805fb>;; encoding(json-encodeexample-object);=> "{\"foo\":\"bar\",\"baz\":[1,2,3]}";; pretty-printing(let((json-encoding-pretty-printt))(message"%s"(json-encodeexample-object)))
{ "foo": "bar", "baz": [ 1, 2, 3 ]}
Use the JSON library for Erlang (mochijson) frommochiweb. The JSON code is extracted fromwikipedia
-module(json).-export([main/0]).main()->JSON="{\"firstName\":\"John\",\"lastName\":\"Smith\",\"age\": 25,\"address\": {\"streetAddress\":\"21 2nd Street\",\"city\":\"New York\",\"state\":\"NY\",\"postalCode\":\"10021\" },\"phoneNumber\": [ {\"type\":\"home\",\"number\":\"212 555-1234\" }, {\"type\":\"fax\",\"number\":\"646 555-4567\" } ]}",Erlang={struct,[{"firstName","John"},{"lastName","Smith"},{"age",25},{"address",{struct,[{"streetAddress","21 2nd Street"},{"city","New York"},{"state","NY"},{"postalCode","10021"}]}},{"phoneNumber",{array,[{struct,[{"type","home"},{"number","212 555-1234"}]},{struct,[{"type","fax"},{"number","646 555-4567"}]}]}}]},io:format("JSON -> Erlang\n~p\n",[mochijson:decode(JSON)]),io:format("Erlang -> JSON\n~s\n",[mochijson:encode(Erlang)]).
JSON -> Erlang{struct,[{"firstName","John"}, {"lastName","Smith"}, {"age",25}, {"address", {struct,[{"streetAddress","21 2nd Street"}, {"city","New York"}, {"state","NY"}, {"postalCode","10021"}]}}, {"phoneNumber", {array,[{struct,[{"type","home"},{"number","212 555-1234"}]}, {struct,[{"type","fax"},{"number","646 555-4567"}]}]}}]}Erlang -> JSON{"firstName":"John","lastName":"Smith","age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021"},"phoneNumber":[{"type":"home","number":"212 555-1234"},{"type":"fax","number":"646 555-4567"}]}
There are several ways:
1. Using Json.Net
openNewtonsoft.JsontypePerson={ID:int;Name:string}letxs=[{ID=1;Name="First"};{ID=2;Name="Second"}]letjson=JsonConvert.SerializeObject(xs)json|>printfn"%s"letxs1=JsonConvert.DeserializeObject<Personlist>(json)xs1|>List.iter(funx->printfn"%i %s"x.IDx.Name)
Print:
[{"ID":1,"Name":"First"},{"ID":2,"Name":"Second"}]1First2Second
2. Using FSharp.Data
openFSharp.DataopenFSharp.Data.JsonExtensionstypePerson={ID:int;Name:string}letxs=[{ID=1;Name="First"};{ID=2;Name="Second"}]letinfos=xs|>List.map(funx->JsonValue.Record([|"ID",JsonValue.Number(decimalx.ID);"Name",JsonValue.String(x.Name)|]))|>Array.ofList|>JsonValue.Arrayinfos|>printfn"%A"matchJsonValue.Parse(infos.ToString())with|JsonValue.Array(x)->x|>Array.map(funx->{ID=System.Int32.Parse(stringx?ID);Name=(stringx?Name)})|_->failwith"fail json"|>Array.iter(funx->printfn"%i %s"x.IDx.Name)
Print:
[{"ID":1,"Name":"First"},{"ID":2,"Name":"Second"}]1"First"2"Second"
3. Alternative way of parsing: JsonProvider
openFSharp.DatatypePerson={ID:int;Name:string}typePeople=JsonProvider<""" [{"ID":1,"Name":"First"},{"ID":2,"Name":"Second"}] """>People.GetSamples()|>Array.map(funx->{ID=x.Id;Name=x.Name})|>Array.iter(funx->printfn"%i %s"x.IDx.Name)
Print:
1First2Second
USING:json.writerjson.reader;SYMBOL:foo! Load a JSON string into a data structure"[[\"foo\",1],[\"bar\",[10,\"apples\"]]]"json>fooset! Create a new data structure and serialize into JSON{{"blue"{"ocean""water"}}>json
using utilclass Json{ public static Void main () { Str input := """{"blue": [1, 2], "ocean": "water"}""" Map jsonObj := JsonInStream(input.in).readJson echo ("Value for 'blue' is: " + jsonObj["blue"]) jsonObj["ocean"] = ["water":["cold", "blue"]] Map ocean := jsonObj["ocean"] echo ("Value for 'ocean/water' is: " + ocean["water"]) output := JsonOutStream(Env.cur.out) output.writeJson(jsonObj) echo () }}
Value for 'blue' is: [1, 2]Value for 'ocean/water' is: [cold, blue]{"blue":[1,2],"ocean":{"water":["cold","blue"]}}
Forth has no built-in high level data structures such as arrays,strings, and objects. Nor is there a standardized Forth library to buildand use such structures. But there are many different Forth libraries,written by individuals, available though finding them is not always easy and the syntax and behavior is different for each.The library code used below can be found here:
https://github.com/DouglasBHoffman/FMS2
Load a JSON Forth string into a json data structure and print it.
s\" {\"value\":10,\"flag\":false,\"array\":[1,2,3]}" $>json value j j :.
Prints a JSON as follows:{"value": 10, "flag": false, "array": [ 1, 2, 3]}
Create a new Json data structure (here a Json pair), and insert it into the previous Json object. Print it again.
j{ "another":"esc\"ap\u20ACed" }j j :add j :.
Prints the modified JSON:
{"value": 10, "flag": false, "array": [ 1, 2, 3],"another": "esc"ap€ed" }
Serialize the JSON object into a string. Print the string.
j json>$ :.
{"value":10,"flag":false,"array":[1,2,3],"another":"esc\"ap\u20ACed"}
Usingjson-fortran library. Creating the json example file / reading a JSON string.
{ "PhoneBook": [ { "name": "Adam", "phone": "0000001" }, { "name": "Eve", "phone": "0000002" }, { "name": "Julia", "phone": "6666666" } ]}
programjson_fortranusejson_moduleimplicit none typephonebook_typecharacter(len=:),allocatable::namecharacter(len=:),allocatable::phoneend typephonebook_typetype(phonebook_type),dimension(3)::PhoneBookinteger::itype(json_value),pointer::json_phonebook,p,etype(json_file)::jsonPhoneBook(1)%name='Adam'PhoneBook(2)%name='Eve'PhoneBook(3)%name='Julia'PhoneBook(1)%phone='0000001'PhoneBook(2)%phone='0000002'PhoneBook(3)%phone='6666666'calljson_initialize()!create the root structure:calljson_create_object(json_phonebook,'')!create and populate the phonebook array:calljson_create_array(p,'PhoneBook')doi=1,3calljson_create_object(e,'')calljson_add(e,'name',PhoneBook(i)%name)calljson_add(e,'phone',PhoneBook(i)%phone)calljson_add(p,e)!add this element to arraynullify(e)!cleanup for next loopend do calljson_add(json_phonebook,p)!add p to json_phonebooknullify(p)!no longer need this!write it to a file:calljson_print(json_phonebook,'phonebook.json')! read directly from a character stringcalljson%load_from_string('{ "PhoneBook": [ { "name": "Adam", "phone": "0000001" },& { "name": "Eve", "phone": "0000002" }, { "name": "Julia", "phone": "6666666" } ]}')! print it to the consolecalljson%print_file()end programjson_fortran
FreeBASIC JSON Parser "JSON is simple, so the interface should also be simple" Written by Oz (alex DOT barry AT gmail DOT com) - April 22, 2010, Updated May 21, 2013
Sample JSON file:
{ "menu": { "id": "file", "string": "File:", "number": -3, "boolean1":true , "boolean2" :false,"boolean3":true, "sentence" : "the rain in spain falls mainly on the plain. This here \" is an escaped quote!", "null": null, "array" : [0,1,2,3] "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": "100" }, }}
#include"inc/fbJSON.bas"SubprintNodeChildren(ByvalnAsfbJSONPtr,ByvallevelAsInteger)EndSubDimtestAsfbJSONPtr=fbJSON_ImportFile("test1.json")Iftest=NULLThenPrint"Unable to load json file/string!"End1EndIfPrintfbJSON_ExportString(test,1)fbJSON_Delete(test)Sleep
{ "menu": { "id" : "file", "string" : "File:", "number" : -3, "boolean1" : true, "boolean2" : false, "boolean3" : true, "sentence" : "the rain in spain falls mainly on the plain. This here " is an escaped quote!", "null" : null, "array": [ 0, 1, 2, 3 ], "Thumbnail": { "Url" : "http://www.example.com/image/481989943", "Height" : 125, "Width" : "100" } }}
Since FunL map syntax is conforms to JSON, the built-in functioneval()
can be used to parse a JSON string. Built-inprintln()
also produces JSON conformant output. This method only uses built-in functions but is comparatively slow.
println( eval('{ "foo": 1, "bar": [10, "apples"] }') )
Using modulejson
gives better performance and also pretty prints the JSON output.
import json.*DefaultJSONWriter.write( JSONReader({'ints', 'bigInts'}).fromString('{ "foo": 1, "bar": [10, "apples"] }') )
{"foo": 1, "bar": [10, "apples"]}{ "foo": 1, "bar": [ 10, "apples" ]}
FB has dedicated JSON functions making easy to serialize objects as JSON and to convert JSON to objects.
include "NSLog.incl"local fn DoIt ErrorRef err = NULL CFStringRef jsonString = @"{ \"foo\": 1, \"bar\": [10, \"apples\"] }" CFDataRef strData = fn StringData( jsonString, NSUTF8StringEncoding ) CFTypeRef jsonObj = fn JSONSerializationJSONObjectWithData( strData, NULL, @err ) if err then NSLog( @"%@", fn ErrorLocalizedDescription( err ) ) NSLog( @"%@\n", jsonObj ) CfDictionaryRef dict = @{ @"blue": @[@1, @2], @"ocean": @"water"} CFDataRef jsonData = fn JSONSerializationDataWithJSONObject( dict, 0, @err ) if err then NSLog( @"%@", fn ErrorLocalizedDescription( err ) ) CFStringRef jsonString2 = fn StringWithData( jsonData, NSUTF8StringEncoding ) NSLog( @"%@\n", jsonString2 )end fnfn DoItHandleEvents
{ bar = ( 10, apples ); foo = 1;}{"blue":[1,2],"ocean":"water"}
Example below shows simple correspondence between JSON objects and Go maps, and shows that you don't have to know anything about the structure of the JSON data to read it in.
packagemainimport"encoding/json"import"fmt"funcmain(){vardatainterface{}err:=json.Unmarshal([]byte(`{"foo":1, "bar":[10, "apples"]}`),&data)iferr==nil{fmt.Println(data)}else{fmt.Println(err)}sample:=map[string]interface{}{"blue":[]interface{}{1,2},"ocean":"water",}json_string,err:=json.Marshal(sample)iferr==nil{fmt.Println(string(json_string))}else{fmt.Println(err)}}
map[bar:[10 apples] foo:1]{"blue":[1,2],"ocean":"water"}
Example below demonstrates more typical case where you have an expected correspondence between JSON data and some composite data types in your program, and shows how the correspondence doesn't have to be exact.
packagemainimport"encoding/json"import"fmt"typePersonstruct{Namestring`json:"name"`Ageint`json:"age,omitempty"`Addr*Address`json:"address,omitempty"`Ph[]string`json:"phone,omitempty"`}typeAddressstruct{Streetstring`json:"street"`Citystring`json:"city"`Statestring`json:"state"`Zipstring`json:"zip"`}funcmain(){// compare with output, note apt field ignored, missing fields// have zero values.jData:=[]byte(`{ "name": "Smith", "address": { "street": "21 2nd Street", "apt": "507", "city": "New York", "state": "NY", "zip": "10021" } }`)varpPersonerr:=json.Unmarshal(jData,&p)iferr!=nil{fmt.Println(err)}else{fmt.Printf("%+v\n %+v\n\n",p,p.Addr)}// compare with output, note empty fields omitted.pList:=[]Person{{Name:"Jones",Age:21,},{Name:"Smith",Addr:&Address{"21 2nd Street","New York","NY","10021"},Ph:[]string{"212 555-1234","646 555-4567"},},}jData,err=json.MarshalIndent(pList,""," ")iferr!=nil{fmt.Println(err)}else{fmt.Println(string(jData))}}
{Name:Smith Age:0 Addr:0xf840026080 Ph:[]} &{Street:21 2nd Street City:New York State:NY Zip:10021}[ { "name": "Jones", "age": 21 }, { "name": "Smith", "address": { "street": "21 2nd Street", "city": "New York", "state": "NY", "zip": "10021" }, "phone": [ "212 555-1234", "646 555-4567" ] }]
Gosu consumes JSON as a Dynamic type via this core API:
gw.lang.reflect.json.Json#fromJson(Stringjson):javax.script.Bindings
As the signature of the method suggests, you pass in a JSON string and receive standard script Bindings in return. Bindings is basically a map mirroring the tree structure of the JSON object. Internally Gosu supports any Bindings instance as a Dynamic Expando object. Essentially this means you can directly cast any Bindings instance to Dynamic and treat it as an Expando.
The following JSON example illustrates this:
Sample Person JSON (fromhttp://gosu-lang.github.io/data/person.json):
{"Name":"Dickson Yamada","Age":39,"Address":{"Number":9604,"Street":"Donald Court","City":"Golden Shores","State":"FL"},"Hobby":[{"Category":"Sport","Name":"Baseball"},{"Category":"Recreation","Name":"Hiking"}]}
And the dynamic Gosu code to access it:
varpersonUrl=newURL("http://gosu-lang.github.io/data/person.json")varperson:Dynamic=personUrl.JsonContentprint(person.Name)
Notice the JsonContent property on URL:
personUrl.JsonContent
This is a convenient enhancement property Gosu provides for Java’s URL class. It does all the work to get the JSON text and calls the new Json#fromJson() method for you. It also declares the Dynamic type for you as its return type, so the declared Dynamic type on the person var is unnecessary; it’s there to clearly demonstrate that the person var is indeed Dynamic.
As you can see we can access the Name property from the JSON object from the person var. This is all well and good, but falls short of our desired level of JSON support. Gosu being a static language, we really want that Name reference to be statically verified as well as code-completed in the IDE.
Here’s how we make the previous example work statically:
print(person.toStructure("Person",false))
Gosu enhances Bindings with the method, toStructure( name: String, mutable: boolean ). Note the resulting structure is optionally mutable via the mutable argument. This method generates the complete nesting of types plus convenient factory methods:
structurePerson{staticfunctionfromJson(jsonText:String):Person{returngw.lang.reflect.json.Json.fromJson(jsonText)asPerson}staticfunctionfromJsonUrl(url:String):Person{returnnewjava.net.URL(url).JsonContent}staticfunctionfromJsonUrl(url:java.net.URL):Person{returnurl.JsonContent}staticfunctionfromJsonFile(file:java.io.File):Person{returnfromJsonUrl(file.toURI().toURL())}propertygetAddress():AddresspropertygetHobby():List<Hobby>propertygetAge():IntegerpropertygetName():StringstructureAddress{propertygetNumber():IntegerpropertygetState():StringpropertygetStreet():StringpropertygetCity():String}structureHobby{propertygetCategory():StringpropertygetName():String}}
The Person structure reflects the JSON object’s implied type nesting. You can do whatever you like with this type. You can embed it as an inner structure in an existing class or make a top-level type. In any case all the types in the JSON object are uniquely preserved in one structure. Use it like this:
varperson=Person.fromJsonUrl(personUrl)print(person.Name)print(person.Address.City)print(person.Hobby[0].Name)
All statically verified and fully code completion friendly!
Other features:
print(person.toJson())// toJson() generates the Expando bindings to a JSON stringprint(person.toGosu())// toGosu() generates any Bindings instance to a Gosu Expando initializer stringprint(person.toXml())// toXml() generates any Bindings instance to standard XML
And similar to JavaScript, you can directly evaluate a Gosu Expando initializer string:
varclone=eval(person.toGosu())
Solution requires Groovy 1.8 or later.
Note that JsonSlurper accepts an extra comma such as [1,2,3,]. This is an extension to the [JSON grammar].
defslurper=newgroovy.json.JsonSlurper()defresult=slurper.parseText('''{ "people":[ {"name":{"family":"Flintstone","given":"Frederick"},"age":35,"relationships":{"wife":"people[1]","child":"people[4]"}}, {"name":{"family":"Flintstone","given":"Wilma"},"age":32,"relationships":{"husband":"people[0]","child":"people[4]"}}, {"name":{"family":"Rubble","given":"Barnard"},"age":30,"relationships":{"wife":"people[3]","child":"people[5]"}}, {"name":{"family":"Rubble","given":"Elisabeth"},"age":32,"relationships":{"husband":"people[2]","child":"people[5]"}}, {"name":{"family":"Flintstone","given":"Pebbles"},"age":1,"relationships":{"mother":"people[1]","father":"people[0]"}}, {"name":{"family":"Rubble","given":"Bam-Bam"},"age":1,"relationships":{"mother":"people[3]","father":"people[2]"}}, ]}''')
Test:
result.each{printlnit.key;it.value.each{person->printlnperson}}assertresult.people[0].name==[family:'Flintstone',given:'Frederick']assertresult.people[4].age==1assertresult.people[2].relationships.wife=='people[3]'assertresult.people[3].name==[family:'Rubble',given:'Elisabeth']assertEval.x(result,'x.'+result.people[2].relationships.wife+'.name')==[family:'Rubble',given:'Elisabeth']assertEval.x(result,'x.'+result.people[1].relationships.husband+'.name')==[family:'Flintstone',given:'Frederick']
people[age:35, name:[given:Frederick, family:Flintstone], relationships:[child:people[4], wife:people[1]]][age:32, name:[given:Wilma, family:Flintstone], relationships:[child:people[4], husband:people[0]]][age:30, name:[given:Barnard, family:Rubble], relationships:[child:people[5], wife:people[3]]][age:32, name:[given:Elisabeth, family:Rubble], relationships:[child:people[5], husband:people[2]]][age:1, name:[given:Pebbles, family:Flintstone], relationships:[mother:people[1], father:people[0]]][age:1, name:[given:Bam-Bam, family:Rubble], relationships:[mother:people[3], father:people[2]]]
$data = json_decode(''{ "foo": 1, "bar": [10, "apples"] }'');$sample = ["blue" => [1, 2], "ocean" => "water"];$jsonstring = json_encode($sample, ["pretty_print" => true]);
Parse JSON string into thearr variable:
LOCAL arrhb_jsonDecode('[101,[26,"Test1"],18,false]', @arr )
the JSON representation of an arrayarr
LOCAL arr := { 101, { 18,"Test1" }, 18,.F. }? hb_jsonEncode( arr )// The output is:// [101,[26,"Test1"],18,false]
Uses the Aeson library from hackage (http://hackage.haskell.org/package/aeson).
{-# LANGUAGE OverloadedStrings #-}importData.AesonimportData.Attoparsec(parseOnly)importData.TextimportqualifiedData.ByteString.Lazy.Char8asBimportqualifiedData.ByteString.Char8asStestdoc=object["foo".=(1::Int),"bar".=([1.3,1.6,1.9]::[Double]),"baz".=("some string"::Text),"other".=object["yes".=("sir"::Text)]]main=doletout=encodetestdocB.putStrLnoutcaseparseOnlyjson(S.concat$B.toChunksout)ofLefte->error$"strange error re-parsing json: "++(showe)Rightv|v/=testdoc->error"documents not equal!"Rightv|otherwise->printv
An example using Aeson and TemplateHaskell. Note that it can handle the absence of keys.
{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}importData.AesonimportData.Aeson.THdataPerson=Person{firstName::String,lastName::String,age::MaybeInt}deriving(Show,Eq)$(deriveJSONdefaultOptions''Person)main=dolettest1="{\"firstName\":\"Bob\",\"lastName\":\"Smith\"}"test2="{\"firstName\":\"Miles\",\"lastName\":\"Davis\",\"age\": 45}"print(decodetest1::MaybePerson)print(decodetest2::MaybePerson)
An example using Aeson and GHC.Generics. Note that it can handle the absence of keys.
{-# LANGUAGE DeriveGeneric, OverloadedStrings #-}importData.AesonimportGHC.GenericsdataPerson=Person{firstName::String,lastName::String,age::MaybeInt}deriving(Show,Eq,Generic)instanceFromJSONPersoninstanceToJSONPersonmain=dolettest1="{\"firstName\":\"Bob\",\"lastName\":\"Smith\"}"test2="{\"firstName\":\"Miles\",\"lastName\":\"Davis\",\"age\": 45}"print(decodetest1::MaybePerson)print(decodetest2::MaybePerson)
:- %say|= [^ [in=@tas ~] ~]:- %noun =+ obj=(need (poja in)) :: try parse to json =+ typ=$:(name=@tas age=@ud) :: datastructure =+ spec=(ot name/so age/ni ~):jo :: parsing spec ?. ?=([%o *] obj) :: isnt an object? ~ =+ ^= o %. %. (spec obj) :: parse with spec need :: panic if failed ,typ :: cast to type =. age.o +(age.o) :: increment its age... %: crip %: pojo :: pretty-print result (jobe [%name s/name.o] [%age n/(crip <age.o>)] ~) :: convert back to json
Usage: Put code in gen/json.hoon
> +json '{"name":"pojo", "age":4}''{"age":5,"name":"pojo"}'
(var object {:a 1 :b "Hello, world!" [1 2 3] :c} serialised (to-json object) deserialised (from-json serialised))(print "Object: " object)(print "Serialised: " serialised)(str "Deserialised: " deserialised)
Object: {:a 1, :b "Hello, world!", [1 2 3] :c}Serialised: {":a":1,":b":"Hello, world!","[1 2 3]":":c"}Deserialised: {":a" 1, ":b" "Hello, world!", "[1 2 3]" ":c"}
Observe that JSON is incapable of lossless serialisation and deserialisation of Insitux data structures, with the recommended approach rather beingstr
andsafe-eval
.
Here is a minimal implementation based onan old email message.
NB. character classes:NB. 0: whitespaceNB. 1: "NB. 2: \NB. 3: [ ] , { } :NB. 4: ordinaryclasses=.3<.'"\[],{}:'(#@[|&>:i.)a.classes=.0(I.a.e.' ',CRLF,TAB)}(]+4*0=])classeswords=:(0;(010#:10*".;._2]0 :0);classes)&;: NB. states: 0.0 1.1 2.1 3.1 4.1 NB. 0 whitespace 1.0 5.0 6.0 1.0 1.0 NB. 1 " 4.0 4.0 4.0 4.0 4.0 NB. 2 \ 0.3 1.2 2.2 3.2 4.2 NB. 3 { : , } [ ] 0.3 1.2 2.0 3.2 4.0 NB. 4 ordinary 0.3 1.2 2.2 3.2 4.2 NB. 5 "" 1.0 1.0 1.0 1.0 1.0 NB. 6 "\)tokens=.;:'[ ] , { } :'actions=:lBra`rBracket`comma`lBra`rBrace`colon`valueNB. action verbs argument conventions:NB. x -- boxed json wordNB. y -- boxed json state stackNB. result -- new boxed json state stackNB.NB. json state stack is an list of boxes of incomplete listsNB. (a single box for complete, syntactically valid json)jsonParse=:0{::(,a:),&.>[:actions@.(tokens&i.@[)/[:|.a:,wordslBra=:a:,~]rBracket=:_2&}.@],[:<_2&{::@],_1&{@]comma=:]rBrace=:_2&}.@],[:<_2&{::@](,<)[:|:(2,~[:-:@$_1&{::@])$_1&{::@]colon=:]value=:_1&}.@],[:<_1&{::@],jsonValue&.>@[NB. hypothetically, jsonValue should strip double quotesNB. interpret back slashesNB. and recognize numbersjsonValue=:]require'strings'jsonSer2=:jsonSer1@(<"_1^:(0>.#@$-1:))jsonSer1=:']',~'['}:@;@;(',',~jsonSerialize)&.>jsonSer0=:'"',jsonEsc@:":,'"'"_jsonEsc=:rplc&(<;._1' \ \\ " \"')jsonSerialize=:jsonSer0`jsonSer2@.(*@L.)
Example use:
jsonParse'{ "blue": [1,2], "ocean": "water" }'┌────────────────┐│┌──────┬───────┐│││"blue"│"ocean"│││├──────┼───────┤│││┌─┬─┐ │"water"│││││1│2│ │ ││││└─┴─┘ │ │││└──────┴───────┘│└────────────────┘└──────────────────────────────┘ jsonSerialize jsonParse'{ "blue": [1,2], "ocean": "water" }'[[["\"blue\"","\"ocean\""],[["1","2"],"\"water\""]]]
Note that these are not strict inverses of each other. These routines allow data to be extracted from json and packed into json format, but only in a minimalistic sense. No attempts are made to preserve the subtleties of type and structure which json can carry. This should be good enough for most applications which are required to deal with json but will not be adequate for ill behaved applications which exploit the typing mechanism to carry significant information.
Also, a different serializer will probably be necessary, if you are delivering json to legacy javascript. Nevertheless, these simplifications are probably appropriate for practical cases.
This usesGson, a library to convert JSON to Java objects and vice-versa.
importcom.google.gson.Gson;publicclassJsonExample{publicstaticvoidmain(String[]args){Gsongson=newGson();Stringjson="{ \"foo\": 1, \"bar\": [ \"10\", \"apples\"] }";MyJsonObjectobj=gson.fromJson(json,MyJsonObject.class);System.out.println(obj.getFoo());for(Stringbar:obj.getBar()){System.out.println(bar);}obj=newMyJsonObject(2,newString[]{"20","oranges"});json=gson.toJson(obj);System.out.println(json);}}classMyJsonObject{privateintfoo;privateString[]bar;publicMyJsonObject(intfoo,String[]bar){this.foo=foo;this.bar=bar;}publicintgetFoo(){returnfoo;}publicString[]getBar(){returnbar;}}
Requires JSON library, now present in all major browsers.
vardata=JSON.parse('{ "foo": 1, "bar": [10, "apples"] }');varsample={"blue":[1,2],"ocean":"water"};varjson_string=JSON.stringify(sample);
JSON is calledJavaScript Object Notation, but JSON differs form JavaScript object literal. cf.MDN/JSON
JSON is jq's native data format, so nothing need be done to parse JSON input. For example, to "pretty print" a stream of JSON entities (including scalars), it would be sufficient to use the jq program:
.
Here are the jq equivalents of the examples given in the section on Julia, assuming the file data.json holds the following JSON text:
{ "blue": [1,2], "ocean": "water" }
jq -c . data.json
produces:
{"blue":[1,2],"ocean":"water"}
jq tostring data.json
produces:"{\"blue\":[1,2],\"ocean\":\"water\"}"
prompt$jsishJsishinteractive:see'help [cmd]'#vardata=JSON.parse('{ "foo": 1, "bar": [10, "apples"] }');variable#data{bar:[10,"apples"],foo:1}#varsample={blue:[1,2],ocean:"water"};variable#sample{blue:[1,2],ocean:"water"}#puts(JSON.stringify(sample)){"blue":[1,2],"ocean":"water"}
# Pkg.add("JSON") ... an external library http://docs.julialang.org/en/latest/packages/packagelist/usingJSONsample=Dict()sample["blue"]=[1,2]sample["ocean"]="water"@showsamplejsonstring=json(sample)@showjsonobj=JSON.parse(jsonstring)@assertjsonstring=="{\"ocean\":\"water\",\"blue\":[1,2]}"@assertjsonobj==Dict("ocean"=>"water","blue"=>[1,2])@asserttypeof(jsonobj)==Dict{String,Any}
We use Kotlin JS here to obtain access to the JavaScript JSON object:
// version 1.2.21dataclassJsonObject(valfoo:Int,valbar:Array<String>)dataclassJsonObject2(valocean:String,valblue:Array<Int>)funmain(args:Array<String>){// JSON to objectvaldata:JsonObject=JSON.parse("""{ "foo": 1, "bar": ["10", "apples"] }""")println(JSON.stringify(data))// object to JSONvaldata2=JsonObject2("water",arrayOf(1,2))println(JSON.stringify(data2))}
{"foo":1,"bar":["10","apples"]}{"ocean":"water","blue":[1,2]}
// Javascript objects are represented by maps in Lassolocal(mymap=map('success'=true,'numeric'=11,'string'='Eleven'))json_serialize(#mymap)// {"numeric": 11,"string": "Eleven","success": true}'<br />'// Javascript arrays are represented by arrayslocal(opendays=array('Monday','Tuesday'))local(closeddays=array('Wednesday','Thursday','Friday'))json_serialize(#opendays)// ["Monday", "Tuesday"]'<br />'json_serialize(#closeddays)// ["Wednesday", "Thursday", "Friday"]'<br />'#mymap->insert('Open'=#opendays)#mymap->insert('Closed'=#closeddays)local(myjson=json_serialize(#mymap))#myjson// {"Closed": ["Wednesday", "Thursday", "Friday"],"numeric": 11,"Open": ["Monday", "Tuesday"],"string": "Eleven","success": true}'<br />'json_deserialize(#myjson)// map(Closed = array(Wednesday, Thursday, Friday), numeric = 11, Open = array(Monday, Tuesday), string = Eleven, success = true)
This example uses the third-party library "Jiffy".
(:jiffyencode(list123'"apple"'true3.14))
The result from that can be made a little more legible with the following:
(:erlangbinary_to_list(:jiffyencode(list123'"apple"'true3.14)))
We can run the encoding example in reverse, and get back what we put in above with the following:
(:jiffydecode'"[1,2,3,[97,112,112,108,101],true,3.14]")
Here's a key-value example:
(:jiffydecode'"{\"foo\": [1, 2, 3]}")
We can also extract the key and value using Erlang patterns:
(let(((tuple(list(tuplekeyvalue)))(:jiffydecode'"{\"foo\": [1, 2, 3]}")))(:ioformat'"~p: ~p~n"(listkeyvalue)))
Lingo has no native JSON support. A JSON library could of course be written in pure Lingo or as binary plugin ("Xtra").
But since Director - the only implementation of Lingo - also includes a SpiderMonkey JS engine (rather outdated and without native JSON object), we can implement a simple (unsafe) JSON encoder/decoder with the following two movie scripts:
JavaScript movie script "JSON":
//--------------------------------------// Simple (unsafe) JSON decoder based on eval()// @param {string} json// @return {any}//--------------------------------------functionjson_decode(json){varo;eval('o='+json);return_json_decode_val(o);}function_json_decode_val(o){if(o==null)returnundefined;switch(typeof(o)){case"object":if(oinstanceofArray){varv=list();varcnt=o.length;for(i=0;i<cnt;i++){v.add(_json_decode_val(o[i]));}}else{varv=propList();for(variino){varp=i;v.setAProp(_json_decode_val(p),_json_decode_val(o[i]));}}returnv;case"string":// optional support of special Lingo data type 'symbol' unknown to JavaScriptif(o.substr(0,7)=='__sym__')returnsymbol(o.substr(7));returno;default:returno;}}function_json_escape_string(str){varhash={"\\":"\\\\","/":"\\/","\n":"\\n","\t":"\\t","\r":"\\r","\b":"\\b","\f":"\\f","\"":"\\\""};varpatt="[";for(iinhash)patt+=i;patt+="]";returnstr.replace(RegExp(patt,"g"),function(c){returnhash[c]});}
Lingo movie script "JSON":
------------------------------------------ JSON encoder-- Supported Lingo data types: VOID, integer, float, string, symbol, list, propList-- @param {any} o-- @return {string}----------------------------------------on json_encode (o) case ilk(o) of #void: return "null" #integer, #float: return string(o) #string: return QUOTE & _json_escape_string(o) & QUOTE #list: res = [] repeat with v in o res.add(json_encode(v)) end repeat return "[" & _cimplode(res) & "]" #propList: res = [] cnt = count(o) repeat with i = 1 to cnt p = o.getPropAt(i) v = o[i] res.add( json_encode(p)&":"&json_encode(v) ) end repeat return "{" & _cimplode(res) & "}" #symbol: -- optional support of special Lingo data type 'symbol' unknown to JavaScript return QUOTE &"__sym__"&_json_escape_string(string(o)) & QUOTE otherwise: put "ERROR: unsupported data type" end caseend------------------------------------------ Implodes list into comma-separated string-- @param {list} l-- @return {string}----------------------------------------on _cimplode (l) str="" repeat with i=1 to l.count put l[i]&"," after str end repeat delete the last char of str return strend
Usage:
data_org = [\ 42,\ 3.14159,\ [2, 4, #fooBar, "apples", "bananas", "cherries" ],\ ["foo": 1, #bar: VOID, "Hello": "world!"],\ VOID\]json_str = json_encode(data_org) -- valid according to JSONLintdata_decoded = json_decode(json_str)put data_org-- [42, 3.1416, [2, 4, #fooBar, "apples", "bananas", "cherries"], ["foo": 1, #bar: <Void>, "Hello": "world!"], <Void>]put data_decoded-- [42, 3.1416, [2, 4, #fooBar, "apples", "bananas", "cherries"], ["foo": 1, #bar: <Void>, "Hello": "world!"], <Void>]
Using theluajson library:
localjson=require("json")localjson_data=[=[[ 42, 3.14159, [ 2, 4, 8, 16, 32, 64, "apples", "bananas", "cherries" ], { "H": 1, "He": 2, "X": null, "Li": 3 }, null, true, false]]=]print("Original JSON: "..json_data)localdata=json.decode(json_data)json.util.printValue(data,'Lua')print("JSON re-encoded: "..json.encode(data))localdata={42,3.14159,{2,4,8,16,32,64,"apples","bananas","cherries"},{H=1,He=2,X=json.util.null(),Li=3},json.util.null(),true,false}print("JSON from new Lua data: "..json.encode(data))
Since in Lua, a variable or table entry withnil
is treated as the same as an undefined variable or non-existing table entry, anull
value in JSON is decoded to a special function value, which ensures that it can be re-encoded properly tonull
again. To manually insert anull
value in the JSON output, use thejson.util.null
function.
Original JSON: [ 42, 3.14159, [ 2, 4, 8, 16, 32, 64, "apples", "bananas", "cherries" ], { "H": 1, "He": 2, "X": null, "Li": 3 }, null, true, false ] Lua= { 1=42 2=3.14159 3= { 1=2 2=4 3=8 4=16 5=32 6=64 7=apples 8=bananas 9=cherries 4= { Li=3 He=2 H=1 X=function: 0x8f6f00 5=function: 0x8f6f00 6=true 7=false JSON re-encoded: [42,3.14159,[2,4,8,16,32,64,"apples","bananas","cherries"],{"Li":3,"He":2,"H":1,"X":null},null,true,false] JSON from new Lua data: [42,3.14159,[2,4,8,16,32,64,"apples","bananas","cherries"],{"Li":3,"He":2,"H":1,"X":null},null,true,false]
We use a class written in M2000 for JsonM2000 Interpreter Json Class in a module LIB1
you can paste the module LIB1 as first item in module A, or before module A using Module Global LIB1 (so the name LIB1 can be used from module A. You can make a new module from the editor as LIB1 and copy the code of module LIB1 (this module is global by default).
MODULEA{\\Processdatainjsonformat\\WecanloadfromexternalfilewithInline"libName"\\ormultiplefilesInline"file1"&&"file2"\\butherewehavethelibraryinamoduleInlineCodeLib1\\SonowwemakeaParserobject(agrouptypeinM2000)Parser=ParserClass()\\Wecandisplayanyfunction,modulethatispublicandknownlistModules?\\Andthisareallknownvariables(orandobjects)List!Documentjson$\\Wecanloadfromfile\\Load.Docjson$,"alfa.json"json$={{"alfa":-0.11221e+12,"array":[-0.67,"alfa1",[10,20],"beta1",1.21e12,21.12145,"ok"],"delta":false,"epsilon":true,"Null Value":null}}Save.Docjson$,"json2.json"\\bydefaultinUtf-8withBOM\\justshowmultilinetext\\Reportdisplaylinesandstopafter3/4ofconsoleheightlines\\justpressakeyorclickmousebuttonReportjson$\\sonowwegettexttoanewobjectalfa=Parser.Eval(json$)\\checkitPrintType$(alfa)' it is a groupPrint"alfa.type$=";alfa.type$\\thisisareadonlypropertyReport"as one line"ReportParser.Ser$(alfa,0)Report"as multiline"ReportParser.Ser$(alfa,1)Print"Using Print"PrintParser.ReadAnyString$(alfa)Print"Value for alfa, id alfa"PrintParser.ReadAnyString$(alfa,"alfa")Report"as multiline"ReportParser.Ser$(Parser.Eval(Parser.ReadAnyString$(alfa,"array",2)),1)\\WegetacopyofanarrayasaGroup(agroupwhichreturnanarray)Alfa3=Parser.Eval(Parser.ReadAnyString$(alfa,"array",2))\\Firstvalueisforactualobject,secondvalueisareadonlypropertyofthisobjectPrinttype$(Alfa3),Alfa3.type$DimB()\\NowAlfa3runValuepartandpassapointerofarray\\B()isanarrayandheretakeapointertoAlfa3array(asvalueofAlfa3)B()=Alfa3\\each()makeaniteratorforB()N=each(B())WhileN{\\UsingB()wegetvaluesalways.butifwehave"object"or"array"thenPrintprintsitems**PrintB(N^)}\\Printshowherenothingbecauseifvalueisobjectthen"print"justleaveacolumnandcontinuetonextonePrintB()\\wehavetouseGroup()togetgroupnotvalueofgroup(ifany).\\Group()worksfor"named"group,notforstoredinanarrayoraninventoryorastackPrintParser.StringValue$(Group(Alfa3),0)PrintParser.StringValue$(Group(Alfa3),1)\\Nowwewanttopassanewvalue\\Interpreterwanttomatchtypeofexpressionfromleftsidetorightside\\BecauseParser.StringValue$isactualaGroup(Asproperty),\\wehaveasecondlinkedname:Parser.StringValue\\wehavetouseParser.StringValue()\\andallvaluesmustbegroups,asthoseprovidedbyParserParser.StringValue(Group(Alfa3),1)=Parser.Numeric(1234)PrintParser.StringValue$(Group(Alfa3),1)PrintParser.StringValue$(Group(Alfa),"array",2,0)\\wehavetouseParser.StringValue$()Parser.StringValue$(Group(Alfa),"array",2,0)=Parser.JString$("Changed to String")PrintParser.StringValue$(Group(Alfa),"array",2,0)Tryok{PrintParser.StringValue$(Group(Alfa),"array",2)}IfErrorornotokThenPrintError$Parser.StringValue.Add=TrueParser.StringValue$(Group(Alfa),"array",2,10)=Parser.JString$("Changed to String 2")Parser.StringValue(Group(Alfa),"Last value")=Parser.Boolean(true)Report"as multiline"ReportParser.Ser$(alfa3,1)ReportParser.Ser$(alfa,1)Parser.StringValue.Add=FalseParser.StringValue.Del=TrueParser.StringValue(Group(Alfa),"array",0)=Parser.Null()Parser.StringValue(Group(Alfa),"delta")=Parser.Null()Parser.StringValue.Del=FalseForParser{.StringValue(Group(Alfa),"array",1,5)=.Arr((.Numeric(10),.Jstring$("ok 20"),.Boolean(true)))}ReportParser.Ser$(alfa,1)}//callAA
> JSON:-ParseString("[{\"tree\": \"maple\", \"count\": 21}]"); [table(["tree" = "maple", "count" = 21])]> JSON:-ToString( [table(["tree" = "maple", "count" = 21])] ); "[{\"count\": 21, \"tree\": \"maple\"}]"
data=ImportString["{ \"foo\": 1, \"bar\": [10, \"apples\"] }","JSON"]ExportString[data,"JSON"]
>>jsondecode('{ "foo": 1, "bar": [10, "apples"] }')ans=structwithfields:foo:1bar:{2×1cell}>>jsonencode(ans)ans={"foo":1,"bar":[10,"apples"]}
The toolboxJSONlab is doing a nice job to read (loadjson.m) and write (savejson.m) data in JSON format.
This uses a library provided byjson.org to serialize/deserialize JSON objects.
/* NetRexx */optionsreplaceformatcommentsjavacrossrefsymbolsnobinaryimportjava.util.Listimportorg.json.JSONObjectimportorg.json.JSONArrayimportorg.json.JSONTokenerimportorg.json.JSONException/** * Using library from json.org * * @see http://www.json.org/java/index.html */classRJson01publicpropertiesprivateconstantJSON_DWARFS=''-'{\n'-' "F1937_1" : {\n'-' "title" : "Snow White and the Seven Dwarfs",\n'-' "year" : 1937,\n'-' "medium" : "film",\n'-' "dwarfs" : [ "Grumpy", "Happy", "Sleepy", "Bashful", "Sneezy", "Dopey", "Doc" ]\n'-' },\n'-' "F2012_1" : {\n'-' "title" : "Mirror, Mirror",\n'-' "year" : 2012,\n'-' "medium" : "film",\n'-' "dwarfs" : [ "Grimm", "Butcher", "Wolf", "Napoleon", "Half Pint", "Grub", "Chuckles" ]\n'-' },\n'-'}'/** * A bean that looks like the following JSON * <pre> * { * "F2012_2" : { * "title" : "Snow White & the Huntsman", * "year" : 2012, * "medium" : "film", * "dwarfs" : [ "Beith", "Quert", "Muir", "Coll", "Duir", "Gus", "Gort", "Nion" ] * } * } * </pre> */SAMPLE_BEAN=DwarfBean(-"F2012_2",-"Snow White & the Huntsman",-Long(2012),-"film",-Arrays.asList([String"Beith","Quert","Muir","Coll","Duir","Gus","Gort","Nion"])-)methodmain(args=String[])publicstaticsayjson2bean(JSON_DWARFS)saysaybean2json(SAMPLE_BEAN)sayreturnmethodjson2bean(dwarfs)publicstaticreturnsListsay"Make beans from this JSON string:"saydwarfsjsonBeans=ArrayList()dojd=JSONObject(JSONTokener(dwarfs))ns=JSONObject.getNames(jd)name=Stringloopnameovernsdwarves=ArrayList()jn=jd.getJSONObject(name)title=jn.getString('title')year=Long(jn.getLong('year'))medium=jn.getString('medium')dwa=jn.getJSONArray('dwarfs')loopdi=0todwa.length()-1dwarves.add(dwa.getString(di))enddijb=DwarfBean(name,title,year,medium,dwarves)jsonBeans.add(jb.toString())endnamecatchex=JSONExceptionex.printStackTrace()endreturnjsonBeansmethodbean2json(sb=DwarfBean)publicstaticreturnsStringsay"Make JSONObject from this bean:"saysbjsonString=Stringdojd=JSONObject(sb)jo=JSONObject()jo=jo.put(sb.keyGet(),jd)jsonString=jo.toString(2)catchex=JSONExceptionex.printStackTrace()endreturnjsonString--=============================================================================classRJson01.DwarfBeanpublicbinarypropertiesprivatekey=String--notpartofbeanpropertiesindirecttitle=Stringyear=Longmedium=Stringdwarfs=ListmethodDwarfBean(key_=Stringnull,title_=Stringnull,year_=Longnull,medium_=Stringnull,dwarfs_=Listnull)publickeyPut(key_)setTitle(title_)setYear(year_)setMedium(medium_)setDwarfs(dwarfs_)returnmethodkeyPut(key_=String)publickey=key_returnmethodkeyGet()returnsStringreturnkeymethodtoStringpublicreturnsStringts=StringBuilder()ts.append(String.format("%s@%08x ",[Objectthis.getClass().getSimpleName(),Integer(hashCode())]))ts.append('[')ts.append('key='String.valueOf(keyGet())', ')ts.append('title='String.valueOf(getTitle())', ')ts.append('year='String.valueOf(getYear())', ')ts.append('medium='String.valueOf(getMedium())', ')ts.append('dwarfs='String.valueOf(getDwarfs()))ts.append(']')returnts.toString()
Make beans from this JSON string: { "F1937_1" : { "title" : "Snow White and the Seven Dwarfs", "year" : 1937, "medium" : "film", "dwarfs" : [ "Grumpy", "Happy", "Sleepy", "Bashful", "Sneezy", "Dopey", "Doc" ] }, "F2012_1" : { "title" : "Mirror, Mirror", "year" : 2012, "medium" : "film", "dwarfs" : [ "Grimm", "Butcher", "Wolf", "Napoleon", "Half Pint", "Grub", "Chuckles" ] }, }[DwarfBean@07377711 [key=F2012_1, title=Mirror, Mirror, year=2012, medium=film, dwarfs=[Grimm, Butcher, Wolf, Napoleon, Half Pint, Grub, Chuckles]], DwarfBean@19f16e6e [key=F1937_1, title=Snow White and the Seven Dwarfs, year=1937, medium=film, dwarfs=[Grumpy, Happy, Sleepy, Bashful, Sneezy, Dopey, Doc]]]Make JSONObject from this bean:DwarfBean@39890510 [key=F2012_2, title=Snow White & the Huntsman, year=2012, medium=film, dwarfs=[Beith, Quert, Muir, Coll, Duir, Gus, Gort, Nion]]{"F2012_2": { "title": "Snow White & the Huntsman", "dwarfs": [ "Beith", "Quert", "Muir", "Coll", "Duir", "Gus", "Gort", "Nion" ], "year": 2012, "medium": "film"}}
This usesGson, a library to convert JSON to Java objects and vice-versa.
/* NetRexx */optionsreplaceformatcommentsjavacrossrefsymbolsnobinaryimportcom.google.gson.importjava.util.List/** * Using google-gson library * * @see https://code.google.com/p/google-gson/ */classRJson02publicpropertiesprivateconstantJSON_DWARFS=''-'{\n'-' "title" : "Snow White and the Seven Dwarfs",\n'-' "year" : 1937,\n'-' "medium": "film",\n'-' "dwarfs": [ "Grumpy", "Happy", "Sleepy", "Bashful", "Sneezy", "Dopey", "Doc" ]\n'-'}'/** * A bean that looks like the following JSON * <pre> * { * "title" : "Snow White & the Huntsman", * "year" : 2012, * "medium" : "film", * "dwarfs" : [ "Beith", "Quert", "Muir", "Coll", "Duir", "Gus", "Gort", "Nion" ] * } * </pre> */SAMPLE_BEAN=RJSON02.DwarfBean(-/*"F2012_2",*/-"Snow White and the Huntsman",-Long(2012),-"film",-Arrays.asList([String"Beith","Quert","Muir","Coll","Duir","Gus","Gort","Nion"])-)--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~methodmain(args=String[])publicstaticgsonObj=GsonBuilder().setPrettyPrinting().create()jsonBean=RJson02.DwarfBeangsonObj.fromJson(JSON_DWARFS,RJson02.DwarfBean.class)sayJSON_DWARFSsayjsonBean.toString()sayjson=gsonObj.toJson(SAMPLE_BEAN);sayjsonsaySAMPLE_BEAN.toString()sayreturn--=============================================================================classRJson02.DwarfBeanpublicbinarypropertiesindirecttitle=Stringyear=Longmedium=Stringdwarfs=ListmethodDwarfBean(title_=Stringnull,year_=Longnull,medium_=Stringnull,dwarfs_=Listnull)publicsetTitle(title_)setYear(year_)setMedium(medium_)setDwarfs(dwarfs_)returnmethodtoStringpublicreturnsStringts=StringBuilder()ts.append(String.format("%s@%08x ",[Objectthis.getClass().getSimpleName(),Integer(hashCode())]))ts.append('[')ts.append('title='String.valueOf(getTitle())', ')ts.append('year='String.valueOf(getYear())', ')ts.append('medium='String.valueOf(getMedium())', ')ts.append('dwarfs='String.valueOf(getDwarfs()))ts.append(']')returnts.toString()
{ "title" : "Snow White and the Seven Dwarfs", "year" : 1937, "medium": "film", "dwarfs": [ "Grumpy", "Happy", "Sleepy", "Bashful", "Sneezy", "Dopey", "Doc" ] }DwarfBean@63f5e4b6 [title=Snow White and the Seven Dwarfs, year=1937, medium=film, dwarfs=[Grumpy, Happy, Sleepy, Bashful, Sneezy, Dopey, Doc]]{ "title": "Snow White and the Huntsman", "year": 2012, "medium": "film", "dwarfs": [ "Beith", "Quert", "Muir", "Coll", "Duir", "Gus", "Gort", "Nion" ]}DwarfBean@6d63de20 [title=Snow White and the Huntsman, year=2012, medium=film, dwarfs=[Beith, Quert, Muir, Coll, Duir, Gus, Gort, Nion]]
importjsonvardata=parseJson("""{ "foo": 1, "bar": [10, "apples"] }""")echodata["foo"]echodata["bar"]varjs=%*[{"name":"John","age":30},{"name":"Susan","age":31}]echojs
1[10,"apples"][{"name":"John","age":30},{"name":"Susan","age":31}]
use Struct;use JSON;bundle Default { class Json { function : Main(args : String[]) ~ Nil { parser := JSONParser->New("{ \"foo\": 1, \"bar\": [10, \"apples\"] }"); root := parser->Parse(); if(root <> Nil) { root->ToString()->PrintLine(); }; } }}
NSString*jsonString=@"{\"foo\": 1,\"bar\": [10,\"apples\"] }";idobj=[NSJSONSerializationJSONObjectWithData:[jsonStringdataUsingEncoding:NSUTF8StringEncoding]options:0error:NULL];NSLog(@"%@",obj);NSDictionary*dict=@{@"blue":@[@1,@2],@"ocean":@"water"};NSData*jsonData=[NSJSONSerializationdataWithJSONObject:dictoptions:0error:NULL];NSString*jsonString2=[[NSStringalloc]initWithData:jsonDataencoding:NSUTF8StringEncoding];NSLog(@"%@",jsonString2);
typejsonitem=<name"Name":string;kingdom"Kingdom":string;phylum"Phylum":string;class_"Class":string;order"Order":string;family"Family":string;tribe"Tribe":string>letstr=" {\"Name\":\"camel\",\"Kingdom\":\"Animalia\",\"Phylum\":\"Chordata\",\"Class\":\"Mammalia\",\"Order\":\"Artiodactyla\",\"Family\":\"Camelidae\",\"Tribe\":\"Camelini\" }"let()=letj=Json_io.json_of_stringstrinprint_endline(Json_io.string_of_jsonj);
compile with:
ocamlfind opt -o j.opt j.ml -linkpkg -package json-static -syntax camlp4o
openYojson.Basic.Utillets="{\"name\":\"John Doe\",\"pages\": [ {\"id\": 1,\"title\":\"The Art of Flipping Coins\",\"url\":\"http://example.com/398eb027/1\" }, {\"id\": 2,\"deleted\": true }, {\"id\": 3,\"title\":\"Artichoke Salad\",\"url\":\"http://example.com/398eb027/3\" }, {\"id\": 4,\"title\":\"Flying Bananas\",\"url\":\"http://example.com/398eb027/4\" } ]}"letextract_titlesjson=[json]|>filter_member"pages"|>flatten|>filter_member"title"|>filter_stringlet()=letjson=Yojson.Basic.from_stringsinList.iterprint_endline(extract_titlesjson)
Compile and run:
$ ocamlfind ocamlopt -o filtering filtering.ml -package yojson -linkpkg$ ./filteringThe Art of Flipping CoinsArtichoke SaladFlying Bananas
In oforth, Json objects are builtin and can be interpreted natively
A String can be converted to Json object using #perform
A Json object can be converted to a string using #asString
>{"parents":["Otmar Gutmann", "Silvio Mazzola"], "name":"Pingu", "born":1986} .s[1] (Json) {"parents" : ["Otmar Gutmann", "Silvio Mazzola"], "name" : "Pingu", "born" : 1986 }ok>asString .s[1] (String) {"parents" : ["Otmar Gutmann", "Silvio Mazzola"], "name" : "Pingu", "born" :1986 }ok>perform .s[1] (Json) {"parents" : ["Otmar Gutmann", "Silvio Mazzola"], "name" : "Pingu", "born" : 1986 }ok>
Ol comes with library that provides JSON parsing and forming.
(import(filejson))(defineo(read-json-string" { 'name': 'John', 'full name': 'John Smith', 'age': 42, 'weight': 156.18, 'married': false, 'address': { 'street': '21 2nd Street', 'city': 'New York', }, 'additional staff': [ { 'type': 'numbers', 'numbers': [ 1, -2, 0.75, -4.567 ] }, { 'type': 'phone', 'number': '222 222-2222' } ] }"))(printo)(print-json-withdisplayo)(print-json-withdisplay{'name"John"'|fullname|"John Smith"'age42'married#false'address{'street"21 2nd Street"'city"New York"}'|additionalstaff|[{'type"numbers"'numbers[1234]}{'type"phone"'number"222 222-2222"}]
#ff((name . John) (|full name| . John Smith) (age . 42) (married . #false) (address . #ff((street . 21 2nd Street) (city . New York))) (|additional staff| . #(#ff((type . numbers) (numbers . #(1 2 3 4))) #ff((type . phone) (number . 222 222-2222))))){"name":"John","|full name|":"John Smith","age":42,"married":false,"address":{"street":"21 2nd Street","city":"New York"},"|additional staff|":[{"type":"numbers","numbers":[1,2,3,4]},{"type":"phone","number":"222 222-2222"}]}{"name":"John","|full name|":"John Smith","age":42,"married":false,"address":{"street":"21 2nd Street","city":"New York"},"|additional staff|":[{"type":"numbers","numbers":[1,2,3,4]},{"type":"phone","number":"222 222-2222"}]}
The WRITE-JSON and READ-JSON methods were introduced in Progress OpenEdge 10.2B.
/* using a longchar to read and write to, can also be file, memptr, stream */DEFINEVARIABLElcjsonASLONGCHARNO-UNDO./* temp-table defines object, can also be dataset */DEFINETEMP-TABLEexampleFIELDblueASINTEGEREXTENT2FIELDoceanASCHARACTER.CREATEexample.ASSIGNexample.blue[1]=1example.blue[2]=2example.ocean="water"./* write-json to put result in lcjson, true indicates formatted */TEMP-TABLEexample:DEFAULT-BUFFER-HANDLE:WRITE-JSON("LONGCHAR",lcjson,TRUE)./* display result */MESSAGESTRING(lcjson)VIEW-ASALERT-BOX./* empty results */EMPTYTEMP-TABLEexample./* read-json to get result from lcjson */TEMP-TABLEexample:DEFAULT-BUFFER-HANDLE:READ-JSON("LONGCHAR",lcjson).FINDexample./* display results */MESSAGEexample.blue[1]example.blue[2]SKIPexample.oceanVIEW-ASALERT-BOX.
write-json
---------------------------Message---------------------------{"example": [ { "blue": [ 1, 2 ], "ocean": "water" }]}---------------------------OK ---------------------------
read-json
---------------------------Message---------------------------1 2 water---------------------------OK ---------------------------
Using thegoogle.com/oz-code JSON library:
declare [JSON] = {Module.link ['JSON.ozf']} {System.show {JSON.decode "{ \"foo\": 1, \"bar\": [10, \"apples\"] }"}} Sample = object(blue:array(1 2) ocean:"water") {System.showInfo {JSON.encode Sample}}
object(bar:array(10 [97 112 112 108 101 115]) foo:1){"blue":[1,2],"ocean":"water"}
Works with FPC (tested with version 3.2.2).
programtest;{$mode objfpc}{$h+}usesFpJson,JsonParser;constJsonValue='{ '+LineEnding+' "answer": { '+LineEnding+' "everything": 42 '+LineEnding+' }, '+LineEnding+' "happy": true, '+LineEnding+' "list": [ '+LineEnding+' 0, '+LineEnding+' 1, '+LineEnding+' 2 '+LineEnding+' ], '+LineEnding+' "name": "Pierrot", '+LineEnding+' "nothing": null, '+LineEnding+' "object": { '+LineEnding+' "product": "unknown",'+LineEnding+' "amount": 1001 '+LineEnding+' }, '+LineEnding+' "pi": 3.1416 '+LineEnding+'} ';functionJsonsEqual(L,R:TJsonData):Boolean;varI:Integer;e:TJsonEnum;d:TJsonData;beginif(L=nil)or(R=nil)thenexit(False);ifL=Rthenexit(True);if(L.JSONType<>R.JSONType)or(L.Count<>R.Count)thenexit(False);caseL.JSONTypeofjtUnknown:exit(False);jtNull:;jtBoolean:exit(L.AsBoolean=R.AsBoolean);jtNumber:exit(L.AsFloat=R.AsFloat);jtString:exit(L.AsString=R.AsString);jtArray:forI:=0toPred(L.Count)doifnotJsonsEqual(L.Items[I],R.Items[I])thenexit(False);jtObject:foreinLdobeginifnotTJsonObject(R).Find(e.Key,d)thenexit(False);ifnotJsonsEqual(e.Value,d)thenexit(False);end;end;Result:=True;end;varExpected,HandMade:TJsonData;beginExpected:=GetJson(JsonValue);HandMade:=CreateJSONObject(['answer',CreateJSONObject(['everything',42]),'happy',True,'list',CreateJSONArray([0,1,2]),'name','Pierrot','nothing',CreateJSON,'object',CreateJSONObject(['product','unknown','amount',1001]),'pi',3.1416]);WriteLn(HandMade.FormatJson);WriteLn;ifJsonsEqual(Expected,HandMade)thenWriteLn('Objects look identical')elseWriteLn('Oops, something went wrong');Expected.Free;HandMade.Free;end.
{$reference System.Web.Extensions.dll}usesSystem.Web.Script.Serialization;beginvarserializer:=newJavaScriptSerializer;varpeople:=newDictionary<string,object>;people.Add('1','John');people.Add('2','Susan');varjson:=serializer.Serialize(people);Println(json);varres:=serializer.Deserialize&<Dictionary<string,object>>(json);Println(TypeName(res));Println(res);varjsonObject:=serializer.DeserializeObject('{ "foo": 1, "bar": [10, "apples"] }')asDictionary<string,object>;Println(jsonObject);vararr:=jsonObject['bar']asarrayofobject;arr.Println;end.
{"1":"John","2":"Susan"}Dictionary<string, Object>{(1,John),(2,Susan)}{(foo,1),(bar,[10,apples])}10 apples
useJSON;my$data=decode_json('{ "foo": 1, "bar": [10, "apples"] }');my$sample={blue=>[1,2],ocean=>"water"};my$json_string=encode_json($sample);
The distribution now contains a simple json module
-- demo\rosetta\JSON.exwwithjavascript_semanticsincludebuiltins/json.eputs(1,"roundtrip (10 examples):\n")sequencejson_strings={`{"this":"that","age":{"this":"that","age":29}}`,`1`,`"hello"`,`null`,`[12]`,`[null,12]`,`[]`,`{"this":"that","age":29}`,`{}`,`[null,[null,12]]`}fori=1tolength(json_strings)dostrings=json_strings[i]puts(1,s&"\n")objectjson_object=parse_json(s)puts(1,print_json("",json_object,true)&"\n")ifnotequal(print_json("",json_object,true),s)then?9/0endifendfor
roundtrip (10 examples):{"this":"that","age":{"this":"that","age":29}}{"this":"that","age":{"this":"that","age":29}}11"hello""hello"nullnull[12][12][null,12][null,12][][]{"this":"that","age":29}{"this":"that","age":29}{}{}[null,[null,12]][null,[null,12]]
<?php$data=json_decode('{ "foo": 1, "bar": [10, "apples"] }');// dictionaries will be returned as objects$data2=json_decode('{ "foo": 1, "bar": [10, "apples"] }',true);// dictionaries will be returned as arrays$sample=array("blue"=>array(1,2),"ocean"=>"water");$json_string=json_encode($sample);?>
PicoLisp has no JSON library, but it is easy enough to write one. The following supports only fixpoint numbers (no floating point, as it doesn't exist in PicoLisp). Arrays and objects are both mapped to lists.
(de checkJson (X Item) (unless (= X Item) (quit "Bad JSON" Item) ) )(de readJson () (case (read "_") ("{" (make (for (X (readJson) (not (= "}" X)) (readJson)) (checkJson ":" (readJson)) (link (cons X (readJson))) (T (= "}" (setq X (readJson)))) (checkJson "," X) ) ) ) ("[" (make (link T) # Array marker (for (X (readJson) (not (= "]" X)) (readJson)) (link X) (T (= "]" (setq X (readJson)))) (checkJson "," X) ) ) ) (T (let X @ (cond ((pair X) (pack X)) ((and (= "-" X) (format (peek))) (- (read)) ) (T X) ) ) ) ) )(de printJson (Item) # For simplicity, without indentation (cond ((atom Item) (if Item (print @) (prin "{}"))) ((=T (car Item)) (prin "[") (map '((X) (printJson (car X)) (and (cdr X) (prin ", ")) ) (cdr Item) ) (prin "]") ) (T (prin "{") (map '((X) (print (caar X)) (prin ": ") (printJson (cdar X)) (and (cdr X) (prin ", ")) ) Item ) (prin "}") ) ) )
This reads/prints JSON from/to files, pipes, sockets etc. To read from a string, a pipe can be used:
: (pipe (prinl "{ \"foo\": 1, \"bar\": [10, \"apples\"] }") (readJson) )-> (("foo" . 1) ("bar" T 10 "apples")): (printJson (quote ("name" . "Smith") ("age" . 25) ("address" ("street" . "21 2nd Street") ("city" . "New York") ("state" . "NY") ("zip" . "10021") ) ("phone" T "212 555-1234" "646 555-4567") ) ){"name": "Smith", "age": 25, ... {"street": ... "phone": ["212 555-1234", ...
intmain(){// Decodingstringjson="{\"cake\":[\"desu\",1,2.3],\"foo\":1}";write("%O\n",Standards.JSON.decode(json));// Encodingmappingm=(["foo":({1,2,3}),"bar":"hello"]);write("%s\n",Standards.JSON.encode(m));}
([ /* 2 elements */ "cake": ({ /* 3 elements */ "desu", 1, 2.3 }), "foo": 1]){"foo":[1,2,3],"bar":"hello"}
# JSON input is being stored in ordered hashtable.# Ordered hashtable is available in PowerShell v3 and higher.[ordered]@{"foo"=1;"bar"=10,"apples"}|ConvertTo-Json# ConvertFrom-Json converts a JSON-formatted string to a custom object.# If you use the Invoke-RestMethod cmdlet there is not need for the ConvertFrom-Json cmdletInvoke-WebRequest-Uri"http://date.jsontest.com"|ConvertFrom-Json
{"foo":1,"bar":[10,"apples"]}timemilliseconds_since_epochdate--------------------------------12:25:25PM141432632592310-26-2014
Using SWI-Prolog 7's library(http/json), and the new dict datatype, there is nearly transparent handling of JSON objects. All of the serialization and parsing in the following code is accomplished with two predicates. The rest of the code is for the sake of example.
:-use_module([library(http/json),library(func)]).test_json('{"widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 }, "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center" }, "text": { "data": "Click Here", "size": 36, "style": "bold", "name": "text1", "hOffset": 250, "vOffset": 100, "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" }}}').reading_JSON_term:-atom_json_dict(test_json(~),Dict,[]),%% This accomplishes reading in the JSON datawriteln('JSON as Prolog dict: ~w~n'$Dict),writeln('Access field "widget.text.data": ~s~n'$Dict.widget.text.data),writeln('Alter field "widget": ~w~n'$Dict.put(widget,"Altered")).searalize_a_JSON_term:-Dict=_{book:_{title:"To Mock a Mocking Bird",author:_{first_name:"Ramond",last_name:"Smullyan"},publisher:"Alfred A. Knopf",year:1985}},json_write(current_output,Dict).%% This accomplishes serializing the JSON object.
from these two example predicates
?-reading_JSON_term.JSONasPrologdict:_G5217{widget:_G5207{debug:on,image:_G5123{alignment:center,hOffset:250,name:sun1,src:Images/Sun.png,vOffset:250},text:_G5189{alignment:center,data:ClickHere,hOffset:250,name:text1,onMouseUp:sun1.opacity=(sun1.opacity/100)*90;,size:36,style:bold,vOffset:100},window:_G5077{height:500,name:main_window,title:SampleKonfabulatorWidget,width:500}}}Accessfield"widget.text.data":ClickHereAlterfield"widget":_G5217{widget:Altered}true.?-searalize_a_JSON_term.{"book":{"author":{"first_name":"Ramond","last_name":"Smullyan"},"publisher":"Alfred A. Knopf","title":"To Mock a Mocking Bird","year":1985}}true.
OpenConsole()IfCreateJSON(1)PB_Team_Members=SetJSONObject(JSONValue(1))SetJSONString(AddJSONMember(PB_Team_Members,"PB_Team_Member_1"),"Frederic Laboureur")SetJSONString(AddJSONMember(PB_Team_Members,"PB_Team_Member_2"),"Andre Beer")SetJSONString(AddJSONMember(PB_Team_Members,"PB_Team_Member_3"),"Timo Harter")EndIfIfCreateJSON(2)Former_Team_Members=SetJSONArray(JSONValue(2))SetJSONString(AddJSONElement(Former_Team_Members),"Richard Andersson")SetJSONString(AddJSONElement(Former_Team_Members),"Benny Sels")SetJSONString(AddJSONElement(Former_Team_Members),"Danilo Krahn")EndIfPrintN("PureBasic - Team Members:")PrintN(ComposeJSON(1,#PB_JSON_PrettyPrint)+#CRLF$)PrintN("PureBasic - Former Team Members:")PrintN(ComposeJSON(2,#PB_JSON_PrettyPrint)+#CRLF$)#DL=Chr(34)PB_Special_thanks$="[ "+#DL+"Gary Willoughby"+#DL+", "+#DL+"Mark James"+#DL+", "+#DL+"Neil Hodgson"+#DL+" ]"NewListotherpersons.s()IfParseJSON(3,PB_Special_thanks$)ExtractJSONList(JSONValue(3),otherpersons())PrintN("Pure Basic - and others:")ForEachotherpersons():PrintN(otherpersons()):NextElsePrintN(JSONErrorMessage()+" : "+Str(JSONErrorPosition()))PrintN(Left(PB_Special_thanks$,JSONErrorPosition()))PrintN(Mid(PB_Special_thanks$,JSONErrorPosition()+1))EndIfInput()
PureBasic - Team Members:{ "PB_Team_Member_1": "Frederic Laboureur", "PB_Team_Member_2": "Andre Beer", "PB_Team_Member_3": "Timo Harter"}PureBasic - Former Team Members:[ "Richard Andersson", "Benny Sels", "Danilo Krahn"]Pure Basic - and others:Gary WilloughbyMark JamesNeil Hodgson
>>>importjson>>>data=json.loads('{ "foo": 1, "bar": [10, "apples"] }')>>>sample={"blue":[1,2],"ocean":"water"}>>>json_string=json.dumps(sample)>>>json_string'{"blue": [1, 2], "ocean": "water"}'>>>sample{'blue':[1,2],'ocean':'water'}>>>data{'foo':1,'bar':[10,'apples']}
Because most of JSON is valid Python syntax (except "true", "false", and "null", and a few obscure escape sequences), it is also possible (but not recommended) to parse JSON using eval():
>>>true=True;false=False;null=None>>>data=eval('{ "foo": 1, "bar": [10, "apples"] }')>>>data{'foo':1,'bar':[10,'apples']}
library(rjson)data<-fromJSON('{ "foo": 1, "bar": [10, "apples"] }')data
data$foo[1] 1$bar$bar[[1]][1] 10$bar[[2]][1] "apples"
cat(toJSON(data))
{"foo":1,"bar":[10,"apples"]}
#langracket(requirejson)(string->jsexpr"{\"foo\":[1,2,3],\"bar\":null,\"baz\":\"blah\"}")(write-json'(12"three"#hash((x.1)(y.2)(z.3))))
(formerly Perl 6)
UsingJSON::Tiny
useJSON::Tiny;sayfrom-json'{ "foo": 1, "bar": [10, "apples"] }';sayto-json %(blue => [1,2],ocean =>"water" );
{bar => [10 apples], foo => 1}{ "blue" : [ 1, 2 ], "ocean" : "water" }
Usingjson.org/json.r
json-str:{{"menu": { "id": "file", "string": "File:", "number": -3, "boolean": true, "boolean2": false, "null": null, "array": [1, 0.13, null, true, false, "\t\r\n"], "empty-string": "" }}}res:json-to-reboljson-strjs:rebol-to-jsonres
json-to-rebol Result:
make object! [ menu: make object! [ id: "file" string: "File:" number: -3 boolean: true boolean2: false null: none array: [1 0.13 none true false "^-^M^/"] empty-string: "" ]]
rebol-to-json Result:
{ "menu": { "id": "file", "string": "File:", "number": -3, "boolean": true, "boolean2": false, "null": null, "array": [1, 0.13, null, true, false, "\t\r\n"], "empty-string": "" }}
require'json'ruby_obj=JSON.parse('{"blue": [1, 2], "ocean": "water"}')putsruby_objruby_obj["ocean"]={"water"=>["fishy","salty"]}putsJSON.generate(ruby_obj)putsJSON.pretty_generate(ruby_obj)
{"blue"=>[1, 2], "ocean"=>"water"}{"blue":[1,2],"ocean":{"water":["fishy","salty"]}}{ "blue": [ 1, 2 ], "ocean": { "water": [ "fishy", "salty" ] }}
Serializing and deserializing JSON in Rust is done by libraries.
[dependencies]serde={version="1.0",features=["derive"]}serde_json="1.0"
Serde is a general serialization/deserialization library. Serde-JSON implements JSON serialization for Serde.
Using said library is quite straight forward, one simply derivesSerialize
/Deserialize
onto the types they want to convert into and from JSON strings.
useserde::{Serialize,Deserialize};#[derive(Serialize, Deserialize, Debug)]structPoint{x:i32,y:i32,}
Said type could then be used as such:
fnmain(){letpoint=Point{x:1,y:2};letserialized=serde_json::to_string(&point).unwrap();letdeserialized:Point=serde_json::from_str(&serialized).unwrap();println!("serialized = {}",serialized);println!("deserialized = {:?}",deserialized);}
The result of which is type-checked JSON (where extra entries get ignored), without need of a key-value container.
serialized = {"x":1,"y":2}deserialized = Point { x: 1, y: 2 }
It also handles more Rust specific types like enums, tuples, struct tuples, and zero-sized types.
#[derive(Serialize, Deserialize)]struct W { a: i32, b: i32 } // => { "a": 0, "b": 0 }#[derive(Serialize, Deserialize)]struct X(i32, i32); // => [0, 0]#[derive(Serialize, Deserialize)]struct Y(i32); // => 0#[derive(Serialize, Deserialize)]struct Z; // => null#[derive(Serialize, Deserialize)]enum E { W { a: i32, b: i32 }, // => { "W": { "a": 0, "b": 0 } } X(i32, i32), // => { "X": [0, 0] } Y(i32), // => { "Y": 0 } Z, // => { "Z" }}
The traits are also implemented forHashMap
andVec
which can be used as conventional objects/arrays, on top of macros andserde_json::Value
to handle all other potentially weird edge cases.
use std::collections::HashMap;use serde_json::Value;#[derive(Serialize, Deserialize)]struct Data { points: Vec<Points>, #[serde(flatten)] metadata: HashMap<String, Value>,}
In this examplemetadata
would simply capture all other additional entries, for example:
fn main() { let data = { let mut metadata = HashMap::new(); metadata.insert("triangle".to_string(), Value::Number(3.into())); metadata.insert("square".to_string(), Value::Bool(false)); Data { points: vec![Point { x: 1, y: 2 }, Point { x: 15, y: 32 }], metadata, } }; let serialized = serde_json::to_string(&data).unwrap(); let deserialized: Data = serde_json::from_str(&serialized).unwrap(); println!("serialized = {}", serialized); println!("deserialized = {:?}", deserialized);}
serialized = {"points":[{"x":1,"y":2},{"x":15,"y":32}],"square":false,"triangle":3}deserialized = Data { points: [Point { x: 1, y: 2 }, Point { x: 15, y: 32 }], metadata: {"triangle": Number(3), "square": Bool(false)} }
Using the builtin parsing lib (debatably slower than third-party libs such as lift-json from Liftweb).
scala> import scala.util.parsing.json.{JSON, JSONObject}import scala.util.parsing.json.{JSON, JSONObject}scala> JSON.parseFull("""{"foo": "bar"}""")res0: Option[Any] = Some(Map(foo -> bar))scala> JSONObject(Map("foo" -> "bar")).toString()res1: String = {"foo" : "bar"}
Using thejson egg:
(use json)(define object-example (with-input-from-string "{\"foo\": \"bar\", \"baz\": [1, 2, 3]}" json-read))(pp object-example); this prints #(("foo" . "bar") ("baz" 1 2 3))(json-write #([foo . bar] [baz 1 2 3] [qux . #((rosetta . code))])); this writes the following:; {"foo": "bar", "baz": [1, 2, 3], "qux": {"foo": "bar"}}
set jsonString to <<{"foo": 10, "bar": [1, 2, 3]}>>put JSONValue(jsonString)set dataObject to (string_value: "lorem ipsum", int_value: 314, array_value: (2, 4, 6))put JSONFormat(dataObject)
var json = require('JSON::PP').newvar data = json.decode('{"blue": [1, 2], "ocean": "water"}')say datadata{:ocean} = Hash(water => %w[fishy salty])say json.encode(data)
Hash( "blue" => [1, 2], "ocean" => "water"){"blue":[1,2],"ocean":{"water":["fishy","salty"]}}
Use the NeoJSON library:NeoJSON
NeoJSONReader fromString: '{ "foo": 1, "bar": [10, "apples"] }'.
a Dictionary('bar'->#(10 'apples') 'foo'->1 )
Uses the the SML/NJ library[2].
JSONParser.parse(JSONParser.openString("{\"fruit\":\"apple\", \"numbers\": [2,7,1,8,2,8], \"tau\": 6.28318530718}"));(* val it = OBJECT [("fruit", STRING "apple"), ("numbers", ARRAY [INT 2, INT 7, INT 1, INT 8, INT 2, INT 8]), ("tau", FLOAT 6.283185307)]: JSON.value*)JSONPrinter.print(TextIO.stdOut, it);(* {"fruit":"apple","numbers":[2,7,1,8,2,8],"tau":6.28319} *)JSONPrinter.print' {strm=TextIO.stdOut, pretty=true} it;(*{ "fruit" : "apple", "numbers" : [ 2, 7, 1, 8, 2, 8 ], "tau" : 6.28319 }*)
Works on Unix/Linux/BSD with jq (github.com/stedolan/jq/ ) installed. Data storage in strings, so floating point numbers can be written back as received, in a recursive polymorphic structure, which can also be used to store the data as SML-types. (Without Jq on the system or on Microsoft systems, delete the Validate function and its call, and the code can be used for valid JSON-strings without any white space outside strings (only).)
val Validate = fn jsonstring =>let val Valid = fn jsonstring => let val json = String.translate (fn #"\"" => "\\\""|n=>str n ) jsonstring ; val textlength = (String.size json ) + 50 ; val app = " jq -c '.' " val fname = "/tmp/jsonval" ^ (String.extract (Time.toString (Posix.ProcEnv.time()),7,NONE) ); val shellCommand = "echo \"" ^ json ^ "\" | " ^ app val me = ( Posix.FileSys.mkfifo (fname, Posix.FileSys.S.flags [ Posix.FileSys.S.irusr,Posix.FileSys.S.iwusr ] ) ; Posix.Process.fork () ) ; in if (Option.isSome me) then let val fin =TextIO.openIn fname in ( Posix.Process.sleep (Time.fromReal 0.1) ; TextIO.inputN (fin,textlength) before (TextIO.closeIn fin ; OS.FileSys.remove fname)) end else ( OS.Process.system ( shellCommand ^ " > " ^fname ^ " 2>&1 ") ; (* remove fmt and validate *) "done\n" before OS.Process.exit OS.Process.success ) end val result = Valid jsonstringin if String.isPrefix "{" result then result else "JSON error\n" end;datatype ('a,'b) element = elem of 'a * 'b | markerb of int ; (* < internal structure v *)datatype 'a content = value of 'a | block of ('a,'a content) element list | arr of 'a content list |marker of int ; exception Dtype of string ;val unarr = fn arr lst => lst | _ => (raise Dtype "unarr" ; []) ;val unblock = fn block lst => lst | _ => (raise Dtype "unblock" ; []) ;(* --- example loop to apply a function 'dothis', which returns type jvals, to the structure ---- *)datatype jvals = St of string | It of IntInf.int | Rl of real | Bl of bool ; (* returned type by 'dothis' *)val rec gothruAndDo = fn dothis => fn storedObject => let val walk = fn elem ( n, value v) => elem (dothis n , value (dothis v) ) | elem ( n, block v) => elem (dothis n , block ( (gothruAndDo dothis) (rev (tl (rev v)))) ) | elem ( n, arr v) => elem (dothis n , arr ( List.map (block o (gothruAndDo dothis) o unblock) (rev (tl (rev v))) ) ) | _ => elem (St "", value (It (IntInf.fromInt ~1))) in List.map walk storedObject end;(* ------------------------------------ end of loop example ------------------------------------ *) local exception Dtype of string ;val markbToInt = fn markerb NrChars => NrChars | _ => (raise Dtype "markerb!" ; ~1) ;val markToInt = fn marker NrChars => NrChars | _ => (raise Dtype "marker!" ; ~1) ;fun readarr rtag rc = fn #"]"::S => [ marker (List.length S) ] (* process array *) | S => let val tmp = (rtag rc ("",S)) in (block tmp) :: ( readarr rtag rc ( List.drop (S,(List.length S) - markbToInt ( hd (rev tmp))) )) end ;val rec readNaVa = fn rc : string * char list -> string content * char list => fn ("",[]) => []| (sr,[]) => [ elem (sr, value "") ]| (sr,#":":: #"["::S) => let val tmp = arr (readarr readNaVa rc S) in (* field is array *) ( elem (sr, tmp )) :: (readNaVa rc ("" , List.drop (S,(List.length S) - (markToInt (hd (rev(unarr tmp)))) ) )) end | (sr, #":":: #"{"::S) => let val tmp = readNaVa rc ("",S ) in (* field is object *) ( elem (sr, block tmp)) :: (readNaVa rc ("" , List.drop (S,(List.length S) -(markbToInt ( hd (rev tmp)))) )) end | (sr,#"}":: #","::S) => [ markerb (List.length S) ]| (sr,#"}"::S) => [ markerb (List.length S) ]| (sr,#":"::S) => let val tmp = rc ("",S) in (* field is basic *) elem ( sr, #1 tmp) :: (readNaVa rc ("", #2 tmp ) ) end| (sr,#","::S) => readNaVa rc (sr , S)| (sr,#"{"::a::S) => readNaVa rc (sr^(str a) , S)| (sr,a::S) => readNaVa rc (sr^(str a) , S) ; (* name field *) val rec readcontent = fn (sc,a::[]) => (value ( sc^(str a) ),[])| (sc,#","::t) => (value sc , t)| (sc, #"}"::t) => (value sc , #"}"::t)| (sc, #"]"::t) => (value sc , #"]"::t)| (sc, a::t) => readcontent( ( sc^(str a) ),t) ;val putall = fn input => let val rec put = fn [] => "" | (elem h)::t => (#1 h) ^ ":" ^ ( ( fn value x=> x | block x => "{" ^ (put x ) | arr x => "[" ^ String.concat (( List.map (fn x=> "{"^( (put o unblock) x)^"," ) (rev (tl (rev x))))) ^ "]" ) (#2 h)) ^ "," ^ (put t) | (markerb h)::t => "}" in "{" ^ (put input) end;val commas = fn tok => fn S => ( Substring.concatWith (str tok) ( List.map (Substring.dropr (fn x=> x= #"," )) (Substring.tokens (fn x=> x= tok ) (Substring.full S) )) ) ^ (if tok = #"}" then str tok else "" )in val storeJsString = fn input => readNaVa readcontent ("" , String.explode ( Validate input ) ) val writeJS = fn storedStruct => ( ( ( commas #"}" ) o ( commas #"]" ) o putall ) storedStruct )end ;
Example
val testString="{\"firstName\":\"John\",\"lastName\":\"Smith\",\"age\":25,\"address\":{\"streetAddress\":\"21 2nd Street\",\"city\":\"New York\",\"state\":\"NY\",\"postalCode\":\"10021\"},\"phoneNumber\":[{\"type\":\"home\",\"numbers\":[{\"o\":\"212 555-1234\",\"h\":\"119 323-1234\"}]},{\"type\":\"fax\",\"number\":\"646 555-4567\"}]}" ;testString = (writeJS o storeJsString) testString ;val it = true : bool (* because the test string was unformatted *) val toMlVal = fn input => case String.isPrefix "\"" input of true => St (String.substring (input,1,(String.size input)-2) ) | _ => case IntInf.fromString input of SOME n => It n | NONE => case Real.fromString input of SOME x => Rl x | NONE => case Bool.fromString input of SOME b => Bl b | NONE => St "" ;val toMlVal = fn: string -> jvalsList.nth (gothruAndDo toMlVal (storeJsString testString ) ,3);val it = elem (St "address", block [elem (St "streetAddress", value (St "21 2nd Street")), elem (St "city", value (St "New York")), elem (St "state", value (St "NY")), elem (St "postalCode", value (St "10021"))]): (jvals, jvals content) element
import Foundationlet jsonString = "{ \"foo\": 1, \"bar\": [10, \"apples\"] }"if let jsonData = jsonString.data(using: .utf8) {if let jsonObject: Any = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) {print("Dictionary: \(jsonObject)")}}let obj = ["foo": [1, "Orange"],"bar": 1] as [String : Any]if let objData = try? JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted) {if let jsonString2 = String(data: objData, encoding: .utf8) {print("JSON: \(jsonString2)")}}
Dictionary: { bar = ( 10, apples ); foo = 1;}JSON: { "foo" : [ 1, "Orange" ], "bar" : 1}
A JSON parser and printer can fairly easily be created
// Not all JSON object member keys can be represented, a fallback would need to be implemented// Currently Tailspin only supports integers so for now we leave numbers as strings, as we do for true, false and nulltemplates hexToInt templates hexDigit <='0'> 0! <='1'> 1! <='2'> 2! <='3'> 3! <='4'> 4! <='5'> 5! <='6'> 6! <='7'> 7! <='8'> 8! <='9'> 9! <'[Aa]'> 10! <'[Bb]'> 11! <'[Cc]'> 12! <'[Dd]'> 13! <'[Ee]'> 14! <'[Ff]'> 15! end hexDigit @: 0; $... -> hexDigit -> @: $@ * 16 + $; $@ !end hexToIntcomposer jsonParser <value> rule value: (<WS>?) <string|number|object|array|true|false|null> (<WS>?) rule string: (<='"'>) <chars> (<='"'>) rule chars: [ <quote|backslash|slash|backspace|formfeed|linefeed|return|tab|unicode|'[^"]'>* ] -> '$...;' rule quote: <='\"'> -> '"' rule backslash: <='\\'> -> '\' rule slash: <='\/'> -> '/' rule backspace: <='\b'> -> '$#8;' rule formfeed: <='\f'> -> '$#12;' rule linefeed: <='\n'> -> '$#10;' rule return: <='\r'> -> '$#13;' rule tab: <='\t'> -> '$#9;' rule unicode: (<='\u'>) <'[0-9A-Fa-f]{4}'> -> hexToInt -> '$#$;' rule number: <'-?(0|[1-9][0-9]*)(\.[0-9]+)?((e|E)(\+|-)?[0-9]+)?'> // TODO: represent this other than string rule object: (<='{'> <WS>?) { <keyValues>? } (<='}'>) rule keyValues: <keyValue> <followingKeyValue>* rule keyValue: <string>: (<WS>? <=':'>) <value> rule followingKeyValue: (<=','> <WS>?) <keyValue> rule array: (<='['>) [ <arrayValues>? ] (<=']'>) rule arrayValues: <value> <followingArrayValue>* rule followingArrayValue: (<=','>) <value> rule true: <='true'> // TODO: represent this other than string rule false: <='false'> // TODO: represent this other than string rule null: <='null'> // TODO: represent this other than stringend jsonParsertemplates printJson templates printKeyValue '$::key -> printJson;: $::value -> printJson;' ! end printKeyValue templates encodeChars <='"'> '\"' ! <='\'> '\\' ! <='/'> '\/' ! <='$#8;'> '\b' ! <='$#12;'> '\f' ! <='$#10;'> '\n' ! <='$#13;'> '\r' ! <='$#9;'> '\t' ! <> $ ! end encodeChars $ -> # when <[]> do '[$(1) -> printJson;$(2..last)... -> ', $ -> printJson;';]' ! when <{}> do [ $... ] -> '{$(1) -> printKeyValue;$(2..last)... -> ', $ -> printKeyValue;';}' ! when <..> do '$;'! when <''> do [ $... -> encodeChars ] -> '"$...;"' ! otherwise 'WTF!' ! // Other types do not yet exist in Tailspinend printJson'{ "foo": 1, "bar": [10, "apples"] }' -> jsonParser -> '$.bar(2);' -> !OUT::write{ blue: [1,2], ocean: 'water' } -> printJson -> '$;' -> !OUT::write'plain string' -> printJson -> '$;' -> !OUT::write
apples{"blue": [1, 2], "ocean": "water"}"plain string\n"
For parsing JSON,
provides the capability (seethe Tcler's Wiki page on it for more discussion):
package require jsonset sample {{ "foo": 1, "bar": [10, "apples"] }}set parsed [json::json2dict $sample]puts $parsed
foo 1 bar {10 apples}
However, that package is very weak in its generation of JSON because Tcl's official type system is substantially different to that envisaged by JSON. It's possible to work around this though the use of Tcl 8.6, as this next example shows:
package require Tcl 8.6package require json::writeproc tcl2json value { # Guess the type of the value; deep *UNSUPPORTED* magic! regexp {^value is a (.*?) with a refcount} \[::tcl::unsupported::representation $value] -> type switch $type {string { return [json::write string $value]}dict { return [json::write object {*}[dict map {k v} $value {tcl2json $v}]]}list { return [json::write array {*}[lmap v $value {tcl2json $v}]]}int - double { return [expr {$value}]}booleanString { return [expr {$value ? "true" : "false"}]}default { # Some other type; do some guessing... if {$value eq "null"} {# Tcl has *no* null value at all; empty strings are semantically# different and absent variables aren't values. So cheat!return $value } elseif {[string is integer -strict $value]} {return [expr {$value}] } elseif {[string is double -strict $value]} {return [expr {$value}] } elseif {[string is boolean -strict $value]} {return [expr {$value ? "true" : "false"}] } return [json::write string $value]} }}
Sample code (note that the value is built withdict create
andlist
so that there is some auxiliary type hints available, which the above procedure can read):
set d [dict create blue [list 1 2] ocean water]puts [tcl2json $d]
{ "blue" : [1,2], "ocean" : "water"}
Note that this is capable of correctly handling the round-trip of values parsed from thejson
package described above.
TXR has built in JSON support.
The TXR Lisp syntax supports JSON literals, which are prefixed with#J
.
1> #J{"foo" : true, [1, 2, "bar", false] : null}#H(() ("foo" t) (#(1.0 2.0 "bar" nil) null))
JSON objects become hash tables, and arrays become vectors. The JSON keywordstrue
,false
andnull
become Lisp symbolst
,nil
andnull
.
The above#J
syntax is a true hash table literal; it isn't an expression which has to be evaluated to construct the object.
Quasiquoting is supported over this syntax, in two usefully different ways. In quasiquoted JSON, an interpolated values are indicated not by the usual unquoting comma, but a tilde.
If we place the quasiquoting circumflex after the#J
, just before the JSON syntax, then we get a form of quasiquote which interpolates values into the implied data structure. The syntax is transliterated into an invocation of a macro calledjson
, which produces code to construct the object, with the dynamic values inserted into it:
1> (let ((str "hello")) #J^{~str : 42})#H(() ("hello" 42.0))
If the syntax is externally quasiquoted, such as by the circumflex being placed just before the#J
or else by the JSON occurring inside a larger Lisp quasiquote, then the literal syntax itself is being quasiquoted. The result of evaluating the quasiquote isn't the object, but the syntax itself, which when evaluated again produces the object:
1> (let ((str "hello")) ^#J{~str : 42})#J{"hello":42}2> (eval *1)#H(() ("hello" 42.0))
Theget-json
andput-json
functions are the basic interface for reading JSON from a stream, and sending data to a stream in JSON format. Surrounding these core functions are a number of convenience functions. For instancefile-get-json
reads a JSON file and returns the data structure, andtojson
returns an object as a JSON character string.
1> (file-get-json "/usr/share/iso-codes/json/iso_15924.json")#H(() ("15924" #(#H(() ("name" "Adlam") ("alpha_4" "Adlm") ("numeric" "166")) #H(() ("name" "Afaka") ("alpha_4" "Afak") ("numeric" "439")) [ ... SNIP ... ] #H(() ("name" "Code for uncoded script") ("alpha_4" "Zzzz") ("numeric" "999")))))
JSON is printed in a "native" formatting by default:
2> (put-jsonl *1){"15924":[{"name":"Adlam","alpha_4":"Adlm","numeric":"166"},{"name":"Afaka","alpha_4":"Afak","numeric":"439"}, {"name":"Caucasian Albanian","alpha_4":"Aghb","numeric":"239"}, {"name":"Ahom, Tai Ahom","alpha_4":"Ahom","numeric":"338"},{"name":"Arabic","alpha_4":"Arab","numeric":"160"}, [ ... SNIP ... ] {"name":"Code for undetermined script","alpha_4":"Zyyy","numeric":"998"}, {"name":"Code for uncoded script","alpha_4":"Zzzz","numeric":"999"}]}t
With the special variable*print-json-format*
we can get the de-facto standard formatting.
3> (let ((*print-json-format* :standard)) (put-jsonl *1)){ "15924" : [ { "name" : "Adlam", "alpha_4" : "Adlm", "numeric" : "166" }, { "name" : "Afaka", "alpha_4" : "Afak", "numeric" : "439" }, { "name" : "Caucasian Albanian", "alpha_4" : "Aghb", "numeric" : "239" }, [ ... SNIP ... ] { "name" : "Code for uncoded script", "alpha_4" : "Zzzz", "numeric" : "999" } ]}t
The*read-bad-json*
variable controls whether the parser is tolerant toward superfluous commas:
4> (get-json "[1, 2, 3,]")** syntax error: read: string: errors encountered4> (let ((*read-bad-json* t)) (get-json "[1, 2, 3,]"))#(1.0 2.0 3.0)
Numbers must be floating-point in order to convert to JSON:
5> (put-jsonl #(1 2 3))[** print: invalid object 1 in JSON** during evaluation at expr-7:1 of form (put-jsonl #(1 2 3))5> (put-jsonl #(1. 2. 3.))[1,2,3]t
This rigidity prevents errors in applications like saving some integer in JSON which unexpectedly comes back as a floating-point value, not necessarily equal to that integer.
The following implements the parsing half of the task. It is a parser closely based on the JSON grammar [[3]]. This exercise shows how the TXR Pattern Language, though geared toward line-oriented, loose matching over entire documents, can nevertheless parse languages.
This is implemented with recursive horizontal pattern matching functions, and so basically the definition resembles a grammar. Horizontal functions allow the language to easily specify LL grammars with indefinite lookahead, not restricted to regular languages (thanks to TXR's backtracking). The numerous occurences of @\ in the code are line continuations. Horizontal functions must be written on one logical line. @\ eats the whitespace at the start of the next physical line, to allow indentation.
The parser translates to a nested list structure in which the types are labeled with the strings "O", "A", "N", "S" and "K". (Object, array, number, string, and keyword).
The largest grammar rule handles JSON string literals. The strategy is to generate a HTML string and then filter from HTML using the:from_html
filter in TXR. For instance \uABCD is translated toꯍ
and then the filter will produce the proper Unicode character. Similarly \" is translated to"
and \n is translated to
etc.
A little liberty is taken: the useless commas in JSON are treated as optional. (TXR's built-in JSON
Superfluous terminating commas (not generated by the JSON grammar but accepted by some other parsers) are not allowed by this parser.
@(define value (v))@\ @(cases)@\ @(string v)@(or)@(num v)@(or)@(object v)@(or)@\ @(keyword v)@(or)@(array v)@\ @(end)@\@(end)@(define ws)@/[\n\t ]*/@(end)@(define string (g))@\ @(local s hex)@\ @(ws)@\ "@(coll :gap 0 :vars (s))@\ @(cases)@\ \"@(bind s """)@(or)@\ \\@(bind s "\\\\")@(or)@\ \/@(bind s "\\/")@(or)@\ \b@(bind s "")@(or)@\ \f@(bind s "")@(or)@\ \n@(bind s " ")@(or)@\ \r@(bind s " ")@(or)@\ \t@(bind s "	")@(or)@\ \u@{hex /[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]/}@\ @(bind s `&#x@hex;`)@(or)@\ @{s /[^"\\]*/}@(filter :to_html s)@\ @(end)@\ @(until)"@\ @(end)"@\ @(ws)@\ @(cat s "")@\ @(filter :from_html s)@\ @(bind g ("S" s))@\@(end)@(define num (v))@\ @(local n)@\ @(ws)@{n /-?[0-9]+((\.[0-9]+)?([Ee][+\-]?[0-9]+)?)?/}@(ws)@\ @(bind v ("N" n))@\@(end)@(define keyword (v))@\ @(local k)@\ @(all)@(ws)@{k /true|false|null/}@(trailer)@/[^A-Za-z0-9_]/@(end)@(ws)@\ @(bind v ("K" k))@\@(end)@(define object (v))@\ @(local p e pair)@\ @(ws){@(ws)@(coll :gap 0 :vars (pair))@\ @(string p):@(value e)@/,?/@\ @(bind pair (p e))@\ @(until)}@\ @(end)}@(ws)@\ @(bind v ("O" pair))@\@(end)@(define array (v))@\ @(local e)@\ @(ws)[@(ws)@(coll :gap 0 :var (e))@(value e)@/,?/@(until)]@(end)]@(ws)@\ @(bind v ("A" e))@\@(end)@(freeform)@(maybe)@(value v)@(end)@badsyntax
A few tests. Note, thebadsyntax
variable is bound to any trailing portion of the input that does not match the syntax. The call to the parser@(value v)
extracts the longest prefix of the input which is consistent with the syntax, leaving the remainder to be matched intobadsyntax
.
$ echo -n '{ "a" : { "b" : 3, "c" : [1,2,3] } }[' | ./txr -l json.txr - (v "O" ((("S" "a") ("O" ((("S" "b") ("N" "3")) (("S" "c") ("A" (("N" "1") ("N" "2") ("N" "3")))))))))(badsyntax . "[\n")$ echo -n '"\u1234"' | ./txr -l json.txr - (v "S" "\11064")(badsyntax . "")
import jsonstruct User {// Adding a [required] attribute will make decoding fail, if that// field is not present in the input.// If a field is not [required], but is missing, it will be assumed// to have its default value, like 0 for numbers, or '' for strings,// and decoding will not fail.name string [required]age int// Use the `skip` attribute to skip certain fieldsfoo int [skip]// If the field name is different in JSON, it can be specifiedlast_name string [json: lastName]possessions []string}fn main() {data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25, "possessions": ["shirt","ring","sting"] }'user := json.decode(User, data) or {eprintln('Failed to decode json, error: $err')return}println(user)println(json.encode(user))}
User{ name: 'Frodo' age: 25 foo: 0 last_name: 'Baggins' possessions: ['shirt', 'ring', 'sting']}{"name":"Frodo","age":25,"lastName":"Baggins","possessions":["shirt","ring","sting"]}
import "/json" for JSONvar s = "{ \"foo\": 1, \"bar\": [ \"10\", \"apples\"] }"var o = JSON.parse(s)System.print(o)o = { "blue": [1, 2], "ocean": "water" }s = JSON.stringify(o)System.print(s)
{foo: 1, bar: [10, apples]}{"ocean":"water","blue":[1,2]}
The XPath 3.1 standard specifies an XML format to store JSON information. Different XQuery processors implement their own JSON parsers in addition to the XPath functions. One such function has been added, to show, how to map JSON into an XPath map using the BaseX processor. As XQuery is a superset of XPath, the following code is valid XQuery 3.1. Except for 'null', which does not exist in the XPath data model, all JSON datatypes have their XPath equivalent. 'Null' is being represented by the empty sequence. This gets shown at the last function invocation, which creates an XPath map. It may be interesting to note, that the different options for the json serializers and parsers have not been used here.
let $json := '{ "Astring" : "string-value", "Anumber" : 5.7, "Anull" : null, "Aarray" : ["One","Two", 3], "Aobject" : { "key1": "value1", "key2": "value2" }, "Atrue" : true, "Afalse" : false}'let $xml := json-to-xml($local:json)return ( "XPath fn:json-to-xml#1 function:" ,"" ,$xml ,"" ,"Round trip, using fn:xml-to-json#1:" ,"" ,xml-to-json($xml) ,"" ,"Using BaseX json:parse#2 function to create an XPath 3.1 map:" ,"" ,json:parse($local:json, map{"format":"xquery"}))
Result:
XPath fn:json-to-xml#1 function:<map xmlns="http://www.w3.org/2005/xpath-functions"> <string key="Astring">string-value</string> <number key="Anumber">5.7</number> <null key="Anull"/> <array key="Aarray"> <string>One</string> <string>Two</string> <number>3</number> </array> <map key="Aobject"> <string key="key1">value1</string> <string key="key2">value2</string> </map> <boolean key="Atrue">true</boolean> <boolean key="Afalse">false</boolean></map>Round trip, using fn:xml-to-json#1:{ "Astring":"string-value", "Anumber":5.7, "Anull":null, "Aarray":[ "One", "Two", 3 ], "Aobject":{ "key1":"value1", "key2":"value2" }, "Atrue":true, "Afalse":false}Using BaseX json:parse#2 function to create an XPath 3.1 map:map { "Aobject": map { "key1": "value1", "key2": "value2" }, "Afalse": false(), "Anull": (), "Anumber": 5.7e0, "Atrue": true(), "Astring": "string-value", "Aarray": ["One", "Two", 3.0e0]}
zkl has a JSON codec based on yajl.
To convert from JSON to zkl:
a,b:=Import.lib("zklYAJL");var [const] YAJL=a, toJSON=b;src:=#<<<0'|{ "pi": 3.14, "large number": 123456789123456791, "an array": [ -1, true, false, null, "foo" ]}|;#<<<obj:=YAJL().write(src).close();// or obj:=src.pump(YAJL()).close(); // for example, from file or socketobj.println();
D(pi:3.14,an array:L(-1,True,False,Void,"foo"),large number:123456789123456791)
From zkl to JSON:
// using above code plus:toJSON(obj).println();
{"pi":3.1400000000,"an array":[-1,true,false,null,"foo"],"large number":123456789123456791}