jsone

hex.pm version

An Erlang library for encoding, decoding JSON data.

Features

QuickStart

# clone
$ git clone git://github.com/sile/jsone.git
$ cd jsone
# compile
$ make compile
# run tests
$ make eunit
# dialyze
$ make dialyze
# Erlang shell
$ make start
1> jsone:decode(<<"[1,2,3]">>).
[1,2,3]

Enable HiPE

If you want to use HiPE compiled version, please add following code to your rebar.config.

{overrides,
[
{override, jsone, [{erl_opts, [{d, 'ENABLE_HIPE'}, inline]}]}
]}.

Usage Example

%% Decode
> jsone:decode(<<"[1,2,3]">>).
[1,2,3]
> jsone:decode(<<"{\"1\":2}">>).
#{<<"1">> => 2}
> jsone:decode(<<"{\"1\":2}">>, [{object_format, tuple}]). % tuple format
{[{<<"1">>, 2}]}
> jsone:decode(<<"{\"1\":2}">>, [{object_format, proplist}]). % proplist format
[{<<"1">>, 2}]
> jsone:try_decode(<<"[1,2,3] \"next value\"">>). % try_decode/1 returns remaining (unconsumed binary)
{ok,[1,2,3],<<" \"next value\"">>}
% error: raises exception
> jsone:decode(<<"1.x">>).
** exception error: bad argument
in function jsone_decode:number_fraction_part_rest/6
called as jsone_decode:number_fraction_part_rest(<<"x">>,1,1,0,[],<<>>)
in call from jsone:decode/1 (src/jsone.erl, line 71)
% error: returns {error, Reason}
> jsone:try_decode(<<"1.x">>).
{error,{badarg,[{jsone_decode,number_fraction_part_rest,
[<<"x">>,1,1,0,[],<<>>],
[{line,228}]}]}}
%% Encode
> jsone:encode([1,2,3]).
<<"[1,2,3]">>
> jsone:encode(#{<<"key">> => <<"value">>}). % map format
> jsone:encode({[{<<"key">>, <<"value">>}]}). % tuple format
> jsone:encode([{<<"key">>, <<"value">>}]). % proplist format
<<"{\"key\":\"value\"}">>
> jsone:encode(#{key => <<"value">>}). % atom key is allowed
<<"{\"key\":\"value\"}">>
% error: raises exception
> jsone:encode(#{123 => <<"value">>}). % non binary|atom key is not allowed
** exception error: bad argument
in function jsone_encode:object_members/3
called as jsone_encode:object_members([{123,<<"value">>}],[],<<"{">>)
in call from jsone:encode/1 (src/jsone.erl, line 97)
% error: returns {error, Reason}
> jsone:try_encode({[{123, <<"value">>}]}).
{error,{badarg,[{jsone_encode,object_members,
[[{123,<<"value">>}],[],<<"{">>],
[{line,138}]}]}}
% 'object_key_type' option allows non-string object key
> jsone:encode({[{123, <<"value">>}]}, [{object_key_type, scalar}]).
<<"{\"123\":\"value\"}">>
%% Pretty Print
> Data = [true, #{<<"1">> => 2, <<"array">> => [[[[1]]], #{<<"ab">> => <<"cd">>}, false]}, null].
> io:format("~s\n", [jsone:encode(Data, [{indent, 1}, {space, 2}])]).
[
true,
{
"1": 2,
"array": [
[
[
[
1
]
]
],
{
"ab": "cd"
},
false
]
},
null
]
ok
%% Number Format
> jsone:encode(1). % integer
<<"1">>
> jsone:encode(1.23). % float
<<"1.22999999999999998224e+00">> % default: scientific notation
> jsone:encode(1.23, [{float_format, [{decimals, 4}]}]). % decimal notation
<<"1.2300">>
> jsone:encode(1.23, [{float_format, [{decimals, 4}, compact]}]). % compact decimal notation
<<"1.23">>

Data Mapping (Erlang <=> JSON)

Erlang JSON Erlang
=================================================================================================
null -> null -> null
true -> true -> true
false -> false -> false
<<"abc">> -> "abc" -> <<"abc">>
abc -> "abc" -> <<"abc">> % non-special atom is regarded as a binary
{{2010,1,1},{0,0,0}} -> "2010-01-01T00:00:00Z" -> <<"2010-01-01T00:00:00Z">> % datetime (see: `jsone:datetime_encode_format/0`)
123 -> 123 -> 123
123.4 -> 123.4 -> 123.4
[1,2,3] -> [1,2,3] -> [1,2,3]
{[]} -> {} -> {[]} % object_format=tuple
{[{key, <<"val">>}]} -> {"key":"val"} -> {[{<<"key">>, <<"val">>}]} % object_format=tuple
[{}] -> {} -> [{}] % object_format=proplist
[{<<"key">>, val}] -> {"key":"val"} -> [{<<"key">>, <<"val">>}] % object_format=proplist
#{} -> {} -> #{} % object_format=map
#{key => val} -> {"key":"val"} -> #{<<"key">> => <<"val">>} % object_format=map

API

See EDoc Document

Benchmark

The results of poison benchmarking.

See the BENCHMARK.md file for more information.

EncoderBench Result

Non HiPE:

jiffyjsonepoisonjazzjsx
maps7.35 μs/op10.00 μs/op (2)13.26 μs/op18.97 μs/op30.03 μs/op
lists214.93 μs/op151.70 μs/op (2)114.34 μs/op197.31 μs/op337.25 μs/op
strings*103.77 μs/op550.78 μs/op (5)350.49 μs/op445.60 μs/op237.08 μs/op
string escaping*141.46 μs/op934.83 μs/op (2)1387.10 μs/op1568.84 μs/op1371.11 μs/op
large value**404.95 μs/op1379.04 μs/op (3)1322.36 μs/op1818.49 μs/op2027.41 μs/op
pretty print**415.19 μs/op1734.20 μs/op (3)1453.36 μs/op2031.73 μs/op5223.72 μs/op

HiPE:

jiffyjsonepoisonjazzjsx
maps7.12 μs/op5.58 μs/op (1)10.71 μs/op21.08 μs/op25.38 μs/op
lists198.89 μs/op64.76 μs/op (1)76.80 μs/op217.64 μs/op220.85 μs/op
strings*109.11 μs/op323.63 μs/op (4)140.58 μs/op363.87 μs/op179.35 μs/op
string escaping*140.35 μs/op481.52 μs/op (2)1222.81 μs/op1312.68 μs/op699.05 μs/op
large value**388.06 μs/op634.06 μs/op (2)744.13 μs/op1572.41 μs/op1667.37 μs/op
pretty print**404.84 μs/op956.29 μs/op (3)802.29 μs/op1795.51 μs/op4434.13 μs/op

* binary representation of UTF-8-demo.txt
** generated.json

ParserBench Result

Non HiPE:

jiffyjsonepoisonjsx
json value*522.25 μs/op1217.44 μs/op (2)1223.37 μs/op1630.77 μs/op
UTF-8 unescaping**59.63 μs/op342.50 μs/op (4)219.79 μs/op243.64 μs/op

HiPE:

jiffyjsonepoisonjsx
json value*504.77 μs/op527.77 μs/op (2)686.90 μs/op1320.74 μs/op
UTF-8 unescaping**59.95 μs/op83.79 μs/op (2)109.70 μs/op159.35 μs/op

* generated.json
** UTF-8-demo.txt

License

This library is released under the MIT License.

See the COPYING file for full license information.