JSONX is an Erlang library for efficient JSON decoding and encoding, implemented in Erlang NIFs. Works with binaries as strings, arrays as lists and only knows how to decode UTF-8 (and ASCII).
Check out a benchmark si14/erl_json_test or
davisp/erljson_bench and
record encoding tests in /test/bench_encode_records.erl
- cd jsonx
- make
- make doc
- firefox doc/index.html&
-module(record_example).
-compile(export_all).
-record(person, {name, age, friends}).
-record(person2, {name, age, phone}).
encoder1() ->
jsonx:encoder([{person, record_info(fields, person)},
{person2, record_info(fields, person2)} ]).
decoder1() ->
jsonx:decoder([{person, record_info(fields, person)},
{person2, record_info(fields, person2)}]).
nonstrict_decoder1() ->
jsonx:decoder([{person, record_info(fields, person)},
{person2, record_info(fields, person2)}],
[{format, proplist}]).
1> c(records_examples).
{ok,records_examples}
2> rr(record_examples).
[person,person2]
3> BabaYaga = #person2{name = <<"BabaYaga">>, age = 118, phone = <<"666-66-66">>}.
#person2{name = <<"BabaYaga">>,age = 118,
phone = <<"666-66-66">>}
4> Vasya = #person{name = <<"Vasya">>, age = 18, friends = [BabaYaga]}.
#person{name = <<"Vasya">>,age = 18,
friends = [#person2{name = <<"BabaYaga">>,age = 118,
phone = <<"666-66-66">>}]}
5> Encoder = record_examples:encoder1().
#Fun<jsonx.0.45888425>
6> Decoder = record_examples:decoder1().
#Fun<jsonx.1.21317315>
7> Json = Encoder(BabaYaga).
<<"{\"name\": \"BabaYaga\",\"age\": 118,\"phone\": \"666-66-66\"}">>
8> Decoder(Json).
#person2{name = <<"BabaYaga">>,age = 118,
phone = <<"666-66-66">>}
9> Json2 = Encoder(Vasya).
<<"{\"name\": \"Vasya\",\"age\": 18,\"friends\": [{\"name\": \"BabaYaga\",\"age\": 118,\"phone\": \"666-66-66\"}]}">>
10> Decoder(Json2).
#person{name = <<"Vasya">>,age = 18,
friends = [#person2{name = <<"BabaYaga">>,age = 118,
phone = <<"666-66-66">>}]}
11> Json3 = <<"[{\"name\": \"BabaYaga\",\"age\": 118,\"phone\": \"666-66-66\"}, {\"record\": \"undefined\", \"strict\": false}]">>.
<<"[{\"name\": \"BabaYaga\",\"age\": 118,\"phone\": \"666-66-66\"}, {\"record\": \"undefined\", \"strict\": false}]">>
12> Decoder(Json3).
{error,undefined_record,64}
13> NonStrictDecoder = record_examples:nonstrict_decoder1().
#Fun<jsonx.2.71844966>
14> JTerm = NonStrictDecoder(Json3).
[#person2{name = <<"BabaYaga">>,age = 118,
phone = <<"666-66-66">>},
[{<<"record">>,<<"undefined">>},{<<"strict">>,false}]]
15> Encoder(JTerm).
<<"[{\"name\": \"BabaYaga\",\"age\": 118,\"phone\": \"666-66-66\"},{\"record\":\"undefined\",\"strict\":false}]">>
1> jsonx:encode([1, 2.3, true, false, null, atom, <<"string">>, []]).
<<"[1,2.3,true,false,null,\"atom\",\"string\",[]]">>
%% Object as proplist
2> jsonx:encode( [{name, <<"Ivan">>}, {age, 33}, {phones, [3332211, 4443322]}] ).
<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>
%% Object as struct
3> jsonx:encode( {struct, [{name, <<"Ivan">>}, {age, 33}, {phones, [3332211, 4443322]}]} ).
<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>
%% Object as eep18 propsal
4> jsonx:encode( {[{name, <<"Ivan">>}, {age, 33}, {phones, [3332211, 4443322]}]} ).
<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>
1> jsonx:decode(<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>).
{[{<<"name">>,<<"Ivan">>},
{<<"age">>,33},
{<<"phones">>,[3332211,4443322]}]}
2> jsonx:decode(<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>, [{format, eep18}]).
{[{<<"name">>,<<"Ivan">>},
{<<"age">>,33},
{<<"phones">>,[3332211,4443322]}]}
3> jsonx:decode(<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>, [{format, proplist}]).
[{<<"name">>,<<"Ivan">>},
{<<"age">>,33},
{<<"phones">>,[3332211,4443322]}]
4> jsonx:decode(<<"{\"name\":\"Ivan\",\"age\":33,\"phones\":[3332211,4443322]}">>, [{format, struct}]).
{struct,[{<<"name">>,<<"Ivan">>},
{<<"age">>,33},
{<<"phones">>,[3332211,4443322]}]}
More example see examples/stream_example.erl
.
1> D = jstream:new_decoder(<<"{\"key1\": \"val1\",\n">>).
<<>>
2> jstream:get_event(D).
start_map
3> jstream:get_event(D).
{map_key,<<"key1">>}
4> jstream:get_event(D).
<<"val1">>
5> jstream:get_event(D).
parse_buf
6> ok = jstream:update_decoder(D, <<"\"key2\": \"val2\"}\n">>).
ok
7> jstream:get_event(D).
{map_key,<<"key2">>}
8> jstream:get_event(D).
<<"val2">>
9> jstream:get_event(D).
end_map
10> jstream:get_event(D).
{parse_end,<<>>}
null :-> null
true :-> true
false :-> false
"string" :-> <<"binary">>
[1, 2.3, []] :-> [1, 2.3, []]
{"this": "json"} :-> {[{<<"this">>: <<"json">>}]} %% default eep18
{"this": "json"} :-> [{<<"this">>: <<"json">>}] %% optional proplist
{"this": "json"} :-> {struct, [{<<"this">>: <<"json">>}]} %% optional struct
JSONObject :-> #rec{...} %% decoder must be predefined
null :-> null
true :-> true
false :-> false
atom :-> "atom"
<<"str">> :-> "str"
[1, 2.99] :-> [1, 2.99]
{struct, [{<<"this">>: <<"json">>}]} :-> {"this": "json"}
[{<<"this">>: <<"json">>}] :-> {"this": "json"}
{[{<<"this">>: <<"json">>}]} :-> {"this": "json"}
{json, IOList} :-> `iolist_to_binary(IOList)` %% include with no validation
#rec{...} :-> JSONObject %% encoder must be predefined