JSON: Difference between revisions
(→Java: added C after ANTLR) |
m (→{{header|C}}: corrected my usage of "works with") |
||
Line 131:
{{libheader|YAJL}}
{{works with|YAJL
Reads a snippet of JSON into [https://github.com/lloyd/yajl YAJL'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.
|
Revision as of 07:54, 17 December 2012
You are encouraged to solve this task according to the task description, using any language you may know.
Load a JSON 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 (http://www.jsonlint.com/).
Ada
<lang ada> with Ada.Text_IO; with GNATCOLL.JSON;
procedure JSON_Test is
use Ada.Text_IO; use GNATCOLL.JSON; JSON_String : constant String := "{""name"":""Pingu"",""born"":1986}"; Penguin : JSON_Value := Create_Object; Parents : JSON_Array;
begin
Penguin.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);
end JSON_Test; </lang>
Output:
{"parents":["Linus Torvalds", "Alan Cox", "Greg Kroah-Hartman"], "name":"Linux", "born":1992} {"parents":["Otmar Gutmann", "Silvio Mazzola"], "name":"Pingu", "born":1986}
ANTLR
Java
<lang java> // Parse JSON // // Nigel Galloway - April 27th., 2012 // grammar JSON ; @members { String Indent = ""; } 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);}; </lang> 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"
C
Reads a snippet of JSON into YAJL'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.
<lang C>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <yajl/yajl_tree.h>
- include <yajl/yajl_gen.h>
static void print_callback (void *ctx, const char *str, size_t len) {
FILE *f = (FILE *) ctx; fwrite (str, 1, len, f);
}
static void check_status (yajl_gen_status status) {
if (status != yajl_gen_status_ok) { fprintf (stderr, "yajl_gen_status was %d\n", (int) status); exit (EXIT_FAILURE); }
}
static void serialize_value (yajl_gen gen, yajl_val val, int parse_numbers) {
size_t i;
switch (val->type) { case yajl_t_string: check_status (yajl_gen_string (gen, (const unsigned char *) val->u.string, strlen (val->u.string))); break; case yajl_t_number: if (parse_numbers && YAJL_IS_INTEGER (val)) check_status (yajl_gen_integer (gen, YAJL_GET_INTEGER (val))); else if (parse_numbers && YAJL_IS_DOUBLE (val)) check_status (yajl_gen_double (gen, YAJL_GET_DOUBLE (val))); else check_status (yajl_gen_number (gen, YAJL_GET_NUMBER (val), strlen (YAJL_GET_NUMBER (val)))); break; case yajl_t_object: check_status (yajl_gen_map_open (gen)); for (i = 0 ; i < val->u.object.len ; i++) { check_status (yajl_gen_string (gen, (const unsigned char *) 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; case yajl_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; case yajl_t_true: check_status (yajl_gen_bool (gen, 1)); break; case yajl_t_false: check_status (yajl_gen_bool (gen, 0)); break; case yajl_t_null: check_status (yajl_gen_null (gen)); break; default: fprintf (stderr, "unexpectedly got type %d\n", (int) val->type); exit (EXIT_FAILURE); }
}
static void print_tree (FILE *f, yajl_val tree, int parse_numbers) {
yajl_gen gen;
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); }
int main (int argc, char **argv) {
char err_buf[200]; const char *json = "{\"pi\": 3.14, \"large number\": 123456789123456789123456789, " "\"an array\": [-1, true, false, null, \"foo\"]}"; yajl_val tree;
tree = yajl_tree_parse (json, err_buf, sizeof (err_buf)); if (! tree) { fprintf (stderr, "parsing failed because: %s\n", err_buf); return EXIT_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);
return EXIT_SUCCESS;
}</lang>
Output:
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" ] }
C++
<lang cpp>#include "Core/Core.h"
using namespace Upp;
CONSOLE_APP_MAIN { JsonArray a; a << Json("name", "John")("phone", "1234567") << Json("name", "Susan")("phone", "654321"); String txt = ~a; Cout() << txt << '\n'; Value v = ParseJSON(txt); for(int i = 0; i < v.GetCount(); i++) Cout() << v[i]["name"] << ' ' << v[i]["phone"] << '\n'; } </lang>
C#
This uses the JavaScriptSerializer class which was shipped with .NET 3.5.
<lang csharp>using System; using System.Collections.Generic; using System.Web.Script.Serialization;
class Program {
static void Main() { var people = new Dictionary<string, object> {{"1", "John"}, {"2", "Susan"}}; var serializer = new JavaScriptSerializer(); var json = serializer.Serialize(people); Console.WriteLine(json);
var deserialized = serializer.Deserialize<Dictionary<string, object>>(json); Console.WriteLine(deserialized["2"]);
var jsonObject = serializer.DeserializeObject(@"{ ""foo"": 1, ""bar"": [10, ""apples""] }"); var data = jsonObject as Dictionary<string, object>; var array = data["bar"] as object[]; Console.WriteLine(array[1]); }
}</lang>
CoffeeScript
<lang coffeescript> sample =
blue: [1, 2] ocean: 'water'
json_string = JSON.stringify sample json_obj = JSON.parse json_string
console.log json_string console.log json_obj </lang>
Common Lisp
Library: cl-json <lang lisp> (ql:quickload '("cl-json"))
(json:encode-json
'#( ((foo . (1 2 3)) (bar . t) (baz . #\!)) "quux" 4/17 4.25))
(print (with-input-from-string (s "{\"foo\": [1, 2, 3], \"bar\": true, \"baz\": \"!\"}") (json:decode-json s)))
</lang>
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 . "!"))
Clojure
Library: data.json <lang clojure>(use 'clojure.data.json)
; Load as Clojure data structures and bind the resulting structure to 'json-map'.
(def json-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-str json-map)
- Pretty-print the Clojure representation of JSON. We've come full circle.
(pprint-json json-map)</lang>
D
<lang d>import std.stdio, std.json;
void main() {
auto j = parseJSON("{ \"foo\": 1, \"bar\": [10, \"apples\"] }"); writeln(toJSON(&j));
}</lang>
{"foo":1,"bar":[10,"apples"]}
EGL
Structures used both to construct and to parse JSON strings: <lang EGL>record familyMember person person; relationships relationship[]?; end
record person firstName string; lastName string; age int; end
record relationship relationshipType string; id int; end</lang>
Construct JSON string: <lang EGL>people Person[]; // Array of people
people.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 key family["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 string jsonString string = jsonLib.convertToJSON(family);
// Show JSON string SysLib.writeStdout(jsonString);</lang>
Raw Output:
{ "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}]} }
Validated Output (partial):
{ "1": { "person": { "firstName": "Frederick", "lastName": "Flintstone", "age": 35 }, "relationships": [ { "relationshipType": "spouse", "id": 2 }, { "relationshipType": "child", "id": 3 } ] }, ... }
Parse JSON: <lang EGL>// Convert JSON string into dictionary of family members family Dictionary; jsonLib.convertFromJSON(jsonString, family);
// List family members and their relationships familyMember 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); end
end</lang>
Output:
Flintstone, Frederick - 35 spouse: Flintstone, Wilma child: Flintstone, Pebbles ---------------------------------------------------- Flintstone, Wilma - 34 spouse: Flintstone, Frederick child: Flintstone, Pebbles ---------------------------------------------------- Flintstone, Pebbles - 2 mother: Flintstone, Wilma father: Flintstone, Frederick ---------------------------------------------------- Rubble, Bernard - 32 spouse: Rubble, Elizabeth child: Rubble, Bam Bam ---------------------------------------------------- Rubble, Elizabeth - 29 spouse: Rubble, Bernard child: Rubble, Bam Bam ---------------------------------------------------- Rubble, Bam Bam - 2 mother: Rubble, Elizabeth father: 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.
<lang EGL>// Service function definition function geocode(address String) returns (GoogleGeocoding) {
@Resource{uri = "binding:GoogleGeocodingBinding"}, @Rest{method = _GET, uriTemplate = "/json?address={address}&sensor=false", requestFormat = None, responseFormat = JSON}
}
// Invoke service function call 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</lang>
Factor
<lang Factor> USING: json.writer json.reader ;
SYMBOL: foo
! Load a JSON string into a data structure "[[\"foo\",1],[\"bar\",[10,\"apples\"]]]" json> foo set
! Create a new data structure and serialize into JSON
{ { "blue" { "ocean" "water" } } >json
</lang>
Fantom
<lang fantom> using util
class 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 () }
} </lang>
Output:
Value for 'blue' is: [1, 2] Value for 'ocean/water' is: [cold, blue] {"blue":[1,2], "ocean":{"water":["cold","blue"]}}
Go
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. <lang go>package main
import "encoding/json" import "fmt"
func main() {
var data interface{} err := json.Unmarshal([]byte(`{"foo":1, "bar":[10, "apples"]}`), &data) if err == nil { fmt.Println(data) } else { fmt.Println(err) }
sample := map[string]interface{}{ "blue": []interface{}{1, 2}, "ocean": "water", } json_string, err := json.Marshal(sample) if err == nil { fmt.Println(string(json_string)) } else { fmt.Println(err) }
}</lang>
- Output:
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. <lang>package main
import "encoding/json" import "fmt"
type Person struct {
Name string `json:"name"` Age int `json:"age,omitempty"` Addr *Address `json:"address,omitempty"` Ph []string `json:"phone,omitempty"`
}
type Address struct {
Street string `json:"street"` City string `json:"city"` State string `json:"state"` Zip string `json:"zip"`
}
func main() {
// 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" } }`) var p Person err := json.Unmarshal(jData, &p) if err != 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, "", " ") if err != nil { fmt.Println(err) } else { fmt.Println(string(jData)) }
}</lang>
- Output:
{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" ] } ]
Groovy
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].
<lang groovy>def slurper = new groovy.json.JsonSlurper() def result = 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]"}}, ]
} )</lang>
Test: <lang groovy>result.each { println it.key; it.value.each {person -> println person} }
assert result.people[0].name == [family:'Flintstone', given:'Frederick'] assert result.people[4].age == 1 assert result.people[2].relationships.wife == 'people[3]' assert result.people[3].name == [family:'Rubble', given:'Elisabeth'] assert Eval.x(result, 'x.' + result.people[2].relationships.wife + '.name') == [family:'Rubble', given:'Elisabeth'] assert Eval.x(result, 'x.' + result.people[1].relationships.husband + '.name') == [family:'Flintstone', given:'Frederick']</lang>
Output:
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]]]
Haskell
Uses the Aeson library from hackage (http://hackage.haskell.org/package/aeson).
<lang Haskell> {-# LANGUAGE OverloadedStrings #-}
import Data.Aeson import Data.Attoparsec (parseOnly) import Data.Text import qualified Data.ByteString.Lazy.Char8 as B import qualified Data.ByteString.Char8 as S
testdoc = object [
"foo" .= (1 :: Int), "bar" .= ([1.3, 1.6, 1.9] :: [Double]), "baz" .= ("some string" :: Text), "other" .= object [ "yes" .= ("sir" :: Text) ] ]
main = do
let out = encode testdoc B.putStrLn out case parseOnly json (S.concat $ B.toChunks out) of Left e -> error $ "strange error re-parsing json: " ++ (show e) Right v | v /= testdoc -> error "documents not equal!" Right v | otherwise -> print v
</lang>
J
Here is a minimal implementation based on an old email message.
<lang j>NB. character classes: NB. 0: whitespace NB. 1: " NB. 2: \ NB. 3: [ ] , { } : NB. 4: ordinary classes=.3<. '"\[],{}:' (#@[ |&>: i.) a. classes=.0 (I.a.e.' ',CRLF,TAB)} (]+4*0=])classes
words=:(0;(0 10#: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`rBracket`colon`value
NB. action verbs argument conventions: NB. x -- boxed json word NB. y -- boxed json state stack NB. result -- new boxed json state stack NB. NB. json state stack is an list of boxes of incomplete lists NB. (a single box for complete, syntactically valid json) jsonParse=: 0 {:: (,a:) ,&.> [: actions@.(tokens&i.@[)/ [:|.a:,words
lBra=: a: ,~ ] rBracket=: _2&}.@], [:< _2&{::@], _1&{@] comma=: ] rBrace=: _2&}.@], [:< _2&{::@], [:|: (2,~ [: -:@$ _1&{@]) $ _1&{@] colon=: ] value=: _1&}.@], [:< _1&{::@], jsonValue&.>@[
NB. hypothetically, jsonValue should strip double quotes NB. interpret back slashes NB. and recognize numbers jsonValue=:]
require'strings'
jsonSer1=: ']' ,~ '[' }:@;@; (',' ,~ jsonSerialize)&.>
jsonSer0=: '"', jsonEsc@:":, '"'"_
jsonEsc=: rplc&(<;._1' \ \\ " \"')
jsonSerialize=:jsonSer0`jsonSer1@.(*@L.)</lang>
Example use:
<lang> jsonParse'{ "blue": [1,2], "ocean": "water" }' ┌──────────────────────────────┐ │┌──────┬─────┬───────┬───────┐│ ││"blue"│┌─┬─┐│"ocean"│"water"││ ││ ││1│2││ │ ││ ││ │└─┴─┘│ │ ││ │└──────┴─────┴───────┴───────┘│ └──────────────────────────────┘
jsonSerialize jsonParse'{ "blue": [1,2], "ocean": "water" }'
[["\"blue\"",["1","2"],"\"ocean\"","\"water\""]]</lang>
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.
Java
This uses Gson, a library to convert JSON to Java objects and vice-versa. <lang Java>import com.google.gson.Gson;
public class JsonExample {
public static void main(String[] args) { Gson gson = new Gson(); String json = "{ \"foo\": 1, \"bar\": [ \"10\", \"apples\"] }";
MyJsonObject obj = gson.fromJson(json, MyJsonObject.class);
System.out.println(obj.getFoo());
for(String bar : obj.getBar()) { System.out.println(bar); }
obj = new MyJsonObject(2, new String[] { "20", "oranges" }); json = gson.toJson(obj);
System.out.println(json); }
}
class MyJsonObject {
private int foo; private String[] bar;
public MyJsonObject(int foo, String[] bar) { this.foo = foo; this.bar = bar; }
public int getFoo() { return foo; }
public String[] getBar() { return bar; }
}</lang>
JavaScript
Requires JSON library, now present in some browsers. <lang JavaScript>var data = JSON.parse('{ "foo": 1, "bar": [10, "apples"] }');
var sample = { "blue": [1,2], "ocean": "water" }; var json_string = JSON.stringify(sample);</lang>
Of course, it IS called JavaScript Object Notation, so it is a JavaScript object literal, and you can, alternately, parse it by just eval'ing it. This should work in any browser without a library. (Eval may be dangerous, depending on the source of the data.) However, there is an ambiguity with parsing JavaScript object literals by themselves, where it might be mistakenly interpreted as a block, and the key followed by a colon as a label. To avoid this, remember to surround it in parentheses to force it to be interpreted as an expression: <lang javascript>var data = eval('(' + '{ "foo": 1, "bar": [10, "apples"] }' + ')');</lang>
Mathematica
<lang Mathematica> data = ImportString["{ \"foo\": 1, \"bar\": [10, \"apples\"] }","JSON"] ExportString[data, "JSON"] </lang>
Objective-C
<lang objc>NSString *json_string = @"{ \"foo\": 1, \"bar\": [10, \"apples\"] }"; id obj = [NSJSONSerialization JSONObjectWithData:[json_string dataUsingEncoding:NSUTF8StringEncoding]
options:0 error:NULL];
NSLog(@"%@", obj);
id obj2 = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2], nil], @"blue", @"water", @"ocean", nil];
NSString *json_string2 = [[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:obj2
options:0 error:NULL] encoding:NSUTF8StringEncoding] autorelease];
NSLog(@"%@", json_string2);</lang>
Objeck
<lang objeck> 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(); }; } }
}</lang>
OCaml
compile with:
ocamlfind opt -o j.opt j.ml -linkpkg -package json-static -syntax camlp4o
<lang ocaml>type json item =
< name "Name": string; kingdom "Kingdom": string; phylum "Phylum": string; class_ "Class": string; order "Order": string; family "Family": string; tribe "Tribe": string >
let str = "
{ \"Name\": \"camel\", \"Kingdom\": \"Animalia\", \"Phylum\": \"Chordata\", \"Class\": \"Mammalia\", \"Order\": \"Artiodactyla\", \"Family\": \"Camelidae\", \"Tribe\": \"Camelini\" }"
let () =
let j = Json_io.json_of_string str in print_endline (Json_io.string_of_json j);</lang>
OpenEdge/Progress
The WRITE-JSON and READ-JSON methods were introduced in Progress OpenEdge 10.2B. <lang progress>/* using a longchar to read and write to, can also be file, memptr, stream */ DEFINE VARIABLE lcjson AS LONGCHAR NO-UNDO.
/* temp-table defines object, can also be dataset */ DEFINE TEMP-TABLE example
FIELD blue AS INTEGER EXTENT 2 FIELD ocean AS CHARACTER .
CREATE example. ASSIGN
example.blue [1] = 1 example.blue [2] = 2 example.ocean = "water" .
/* write-json to put result in lcjson, true indicates formatted */ TEMP-TABLE example:DEFAULT-BUFFER-HANDLE:WRITE-JSON( "LONGCHAR", lcjson, TRUE ).
/* display result */ MESSAGE
STRING( lcjson )
VIEW-AS ALERT-BOX.
/* empty results */ EMPTY TEMP-TABLE example.
/* read-json to get result from lcjson */ TEMP-TABLE example:DEFAULT-BUFFER-HANDLE:READ-JSON( "LONGCHAR", lcjson ).
FIND example. /* display results */ MESSAGE
example.blue [1] example.blue [2] SKIP example.ocean
VIEW-AS ALERT-BOX.</lang>
Output write-json:
--------------------------- Message --------------------------- {"example": [ { "blue": [ 1, 2 ], "ocean": "water" } ]} --------------------------- OK ---------------------------
Output read-json:
--------------------------- Message --------------------------- 1 2 water --------------------------- OK ---------------------------
Oz
With the JSON library from here: <lang oz>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}}</lang>
Output:
object(bar:array(10 [97 112 112 108 101 115]) foo:1) {"blue":[1,2],"ocean":"water"}
Perl
<lang perl>use JSON;
my $data = decode_json('{ "foo": 1, "bar": [10, "apples"] }');
my $sample = { blue => [1,2], ocean => "water" }; my $json_string = encode_json($sample);</lang>
Perl 6
Using [1]
<lang perl6>use JSON::Tiny;
my $data = from-json('{ "foo": 1, "bar": [10, "apples"] }');
my $sample = { blue => [1,2], ocean => "water" }; my $json_string = to-json($sample);</lang>
PHP
<lang php><?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); ?></lang>
PicoLisp
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. <lang PicoLisp>(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 @ (if (and (= "-" X) (format (peek))) (- (read)) 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 "}") ) ) )</lang>
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", ...
Pike
<lang pike>int main() { // Decoding string json = "{\"cake\":[\"desu\",1,2.3],\"foo\":1}"; write("%O\n", Standards.JSON.decode(json));
// Encoding mapping m = ([ "foo": ({ 1, 2, 3 }), "bar": "hello" ]);
write("%s\n", Standards.JSON.encode(m)); }</lang>
([ /* 2 elements */ "cake": ({ /* 3 elements */ "desu", 1, 2.3 }), "foo": 1 ]) {"foo":[1,2,3],"bar":"hello"}
Python
<lang Python>>>> import json >>> 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']}</lang>
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(): <lang python>>>> true = True; false = False; null = None >>> data = eval('{ "foo": 1, "bar": [10, "apples"] }') >>> data {'foo': 1, 'bar': [10, 'apples']}</lang>
R
<lang R>library(rjson) data <- fromJSON('{ "foo": 1, "bar": [10, "apples"] }') data</lang>
data $foo [1] 1 $bar $bar[[1]] [1] 10 $bar[[2]] [1] "apples"
<lang R>cat(toJSON(data))</lang>
{"foo":1,"bar":[10,"apples"]}
REBOL
Using json.org/json.r
<lang rebol>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-rebol json-str js: rebol-to-json res </lang>
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": "" } }
Ruby
Uses
package json
<lang ruby>require 'json' ruby_obj = JSON.parse('{"blue": [1, 2], "ocean": "water"}') p ruby_obj puts ruby_obj.class puts ruby_obj["blue"].class ruby_obj["ocean"] = {"water" => %w{fishy salty}} puts JSON.generate(ruby_obj)</lang>
Outputs
{"blue"=>[1, 2], "ocean"=>"water"} Hash Array {"blue":[1,2],"ocean":{"water":["fishy","salty"]}}
Scala
Using the builtin parsing lib (debatably slower than third-party libs such as lift-json from Liftweb).
<lang scala>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"} </lang>
Tcl
For parsing JSON,
provides the capability (see the Tcler's Wiki page on it for more discussion):
<lang tcl>package require json set sample {{ "foo": 1, "bar": [10, "apples"] }}
set parsed [json::json2dict $sample] puts $parsed</lang> Output:
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:
<lang tcl>package require Tcl 8.6
proc 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 { # Skip to the mapping code at the bottom } dict { set result "{" set pfx "" dict for {k v} $value { append result $pfx [tcl2json $k] ": " [tcl2json $v] set pfx ", " } return [append result "}"] } list { set result "\[" set pfx "" foreach v $value { append result $pfx [tcl2json $v] set pfx ", " } return [append result "\]"] } 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"}] } }
}
# For simplicity, all "bad" characters are mapped to \u... substitutions set mapped [subst -novariables [regsub -all {[][\u0000-\u001f\\""]} \
$value {[format "\\\\u%04x" [scan {& } %c]]}]]
return "\"$mapped\""
}</lang>
Sample code (note that the value is built with dict create
and list
so that there is some auxiliary type hints available, which the above procedure can read):
<lang tcl>set d [dict create blue [list 1 2] ocean water]
puts [tcl2json $d]</lang>
Output:
{"blue": [1, 2], "ocean": "water"}
Note that this is capable of correctly handling the round-trip of values parsed from the json
package described above.
TXR
Parsing
The following implements the parsing half of the task. It is a parser closely based on the JSON grammar [[2]].
It is implemented with recursive horizontal pattern matching functions, and so basically the definition resembles a grammar. Horizontal functions are a new feature in TXR, and basically 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.
Superfluous terminating commas (not generated by the JSON grammar but accepted by some other parsers) are not allowed by this parser.
<lang txr>@(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</lang>
A few tests. Note, the badsyntax
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 into badsyntax
.
<lang bash>$ 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 . "")</lang>