JSON decoding/encoding module.
datetime_encode_format() = datetime_format() | {Format::datetime_format(), TimeZone::timezone()}
Datetime encoding format.
The default value of TimeZone
is utc
.
%
% Universal Time
%
> jsone:encode({{2000, 3, 10}, {10, 3, 58}}, [{datetime_format, iso8601}]).
<<"\"2000-03-10T10:03:58Z\"">>
%
% Local Time (JST)
%
> jsone:encode({{2000, 3, 10}, {10, 3, 58}}, [{datetime_format, {iso8601, local}}]).
<<"\"2000-03-10T10:03:58+09:00\"">>
%
% Explicit TimeZone Offset
%
> jsone:encode({{2000, 3, 10}, {10, 3, 58}}, [{datetime_format, {iso8601, -2*60*60}}]).
<<"\"2000-03-10T10:03:58-02:00\"">>
datetime_format() = iso8601
decode_option() = {object_format, tuple | proplist | map} | {allow_ctrl_chars, boolean()} | {keys, binary | atom | existing_atom | attempt_atom}
object_format
:
- Decoded JSON object format
tuple
: An object is decoded as{[]}
if it is empty, otherwise{[{Key, Value}]}
.proplist
: An object is decoded as[{}]
if it is empty, otherwise[{Key, Value}]
.map
: An object is decoded as#{}
if it is empty, otherwise#{Key => Value}
.- default:
map
if OTP version is OTP-17 or more,tuple
otherwise
allow_ctrl_chars
:
- If the value is
true
, strings which contain ununescaped control characters will be regarded as a legal JSON string - default:
false
keys
:
Defines way how object keys are decoded. The default value is binary
.
The option is compatible with labels
option in jsx
.
binary
: The key is left as a string which is encoded as binary. It's default and backward compatible behaviour.atom
: The key is converted to an atom. Results inbadarg
if Key value regarded as UTF-8 is not a valid atom.existing_atom
: Returns existing atom. Any key value which is not existing atom raisesbadarg
exception.attempt_atom
: Returns existing atom asexisting_atom
but returns a binary string if fails find one.
encode_option() = native_utf8 | canonical_form | {float_format, [float_format_option()]} | {datetime_format, datetime_encode_format()} | {object_key_type, string | scalar | value} | {space, non_neg_integer()} | {indent, non_neg_integer()} | undefined_as_null
native_utf8
:
- Encodes UTF-8 characters as a human-readable(non-escaped) string
canonical_form
:
- produce a canonical form of a JSON document
{float_format, Optoins}
:
- Encodes a
float()
value in the format which specified byOptions
- default:
[{scientific, 20}]
{datetime_format, Format}
:
- Encodes a
calendar:datetime()
value in the format which specified byFormat
- default:
{iso8601, utc}
object_key_type
:
- Allowable object key type
string
: Only string values are allowed (i.e.json_string()
type)scalar
: In addition tostring
, following values are allowed: nulls, booleans, numerics (i.e.json_scalar()
type)value
: Any json compatible values are allowed (i.e.json_value()
type)- default:
string
- NOTE: If
scalar
orvalue
option is specified, nonjson_string()
key will be automatically converted to abinary()
value (e.g.1
=><<"1">>
,#{}
=><<"{}">>
)
{space, N}
:
- Inserts
N
spaces after every commna and colon - default:
0
{indent, N}
:
- Inserts a newline and
N
spaces for each level of indentation - default:
0
undefined_as_null
:
- Encodes atom
undefined
as null value
float_format_option() = {scientific, Decimals::0..249} | {decimals, Decimals::0..253} | compact
scientific
:
- The float will be formatted using scientific notation with
Decimals
digits of precision.
decimals
:
- The encoded string will contain at most
Decimals
number of digits past the decimal point. - If
compact
is provided the trailing zeros at the end of the string are truncated.
For more details, see erlang:flaot_to_list/2.
> jsone:encode(1.23).
<<"1.22999999999999998224e+00">>
> jsone:encode(1.23, [{float_format, [{scientific, 4}]}]).
<"1.2300e+00">>
> jsone:encode(1.23, [{float_format, [{scientific, 1}]}]).
<<"1.2e+00">>
> jsone:encode(1.23, [{float_format, [{decimals, 4}]}]).
<<"1.2300">>
> jsone:encode(1.23, [{float_format, [{decimals, 4}, compact]}]).
<<"1.23">>
json_array() = [json_value()]
json_boolean() = boolean()
json_number() = number()
json_object() = json_object_format_tuple() | json_object_format_proplist() | json_object_format_map()
json_object_format_map() = #{}
json_object_format_proplist() = [{}] | json_object_members()
json_object_format_tuple() = {json_object_members()}
json_object_members() = [{json_string(), json_value()}]
json_scalar() = json_boolean() | json_number() | json_string()
json_string() = binary() | atom() | calendar:datetime()
NOTE: decode/1
always returns binary()
value
json_term() = {{json, iolist()}} | {{json_utf8, unicode:chardata()}}
json_term()
allows inline already encoded JSON value. json
variant
expects byte encoded utf8 data values as list members. json_utf8
expect
Unicode code points as list members. Binaries are copied "as is" in both
variants except json_utf8
will check if binary contain valid UTF-8
encoded data. In short, json
uses erlang:iolist_to_binary/1
and
json_utf8
uses unicode:chardata_to_binary/1
for encoding.
A simple example is worth a thousand words.
1> S = "hélo".
"hélo"
2> shell:strings(false).
true
3> S.
[104,233,108,111]
4> B = jsone:encode({{json, S}}). % invalid UTF-8
<<104,233,108,111>>
5> B2 = jsone:encode({{json_utf8, S}}). % valid UTF-8
<<104,195,169,108,111>>
6> jsone:encode({{json, B}}).
<<104,233,108,111>>
7> jsone:encode({{json_utf8, B}}).
** exception error: {invalid_json_utf8,<<104>>,<<233,108,111>>}
in function jsone_encode:value/4
called as jsone_encode:value({json_utf8,<<104,233,108,111>>},
[],<<>>,
{encode_opt_v2,false,
[{scientific,20}],
{iso8601,0},
string,0,0})
in call from jsone:encode/2 (/home/hynek/work/altworx/jsone/_build/default/lib/jsone/src/jsone.erl, line 302)
8> jsone:encode({{json_utf8, B2}}).
<<104,195,169,108,111>>
9> shell:strings(true).
false
10> jsone:encode({{json_utf8, B2}}).
<<"hélo"/utf8>>
11> jsone:encode({{json, binary_to_list(B2)}}). % UTF-8 encoded list leads to valid UTF-8
<<"hélo"/utf8>>
json_value() = json_number() | json_string() | json_array() | json_object() | json_boolean() | null | json_term()
stack_item() = {Module::module(), Function::atom(), Arity::arity() | (Args::[term()]), Location::[{file, Filename::string()} | {line, Line::pos_integer()}]}
An item in a stack back-trace.
Note that the erlang
module already defines the same stack_item/0
type,
but it is not exported from the module.
So, maybe as a temporary measure, we redefine this type for passing full dialyzer analysis.
timezone() = utc | local | utc_offset_seconds()
utc_offset_seconds() = -86399..86399
decode/1 | Equivalent to decode(Json, []). |
decode/2 | Decodes an erlang term from json text (a utf8 encoded binary). |
encode/1 | Equivalent to encode(JsonValue, []). |
encode/2 | Encodes an erlang term into json text (a utf8 encoded binary). |
try_decode/1 | Equivalent to try_decode(Json, []). |
try_decode/2 | Decodes an erlang term from json text (a utf8 encoded binary). |
try_encode/1 | Equivalent to try_encode(JsonValue, []). |
try_encode/2 | Encodes an erlang term into json text (a utf8 encoded binary). |
decode(Json::binary()) -> json_value()
Equivalent to decode(Json, [])
.
decode(Json::binary(), Options::[decode_option()]) -> json_value()
Decodes an erlang term from json text (a utf8 encoded binary)
Raises an error exception if input is not valid json
> jsone:decode(<<"1">>, []).
1
> jsone:decode(<<"wrong json">>, []).
** exception error: bad argument
in function jsone_decode:number_integer_part/4
called as jsone_decode:number_integer_part(<<"wrong json">>,1,[],<<>>)
in call from jsone:decode/1 (src/jsone.erl, line 71)
encode(JsonValue::json_value()) -> binary()
Equivalent to encode(JsonValue, [])
.
encode(JsonValue::json_value(), Options::[encode_option()]) -> binary()
Encodes an erlang term into json text (a utf8 encoded binary)
Raises an error exception if input is not an instance of type json_value()
> jsone:encode([1, null, 2]).
<<"[1,null,2]">>
> jsone:encode([1, self(), 2]). % A pid is not a json value
** exception error: bad argument
in function jsone_encode:value/3
called as jsone_encode:value(<0,34,0>,[{array_values,[2]}],<<"[1,">>)
in call from jsone:encode/1 (src/jsone.erl, line 97)
try_decode(Json::binary()) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [stack_item()]}}
Equivalent to try_decode(Json, [])
.
try_decode(Json::binary(), Options::[decode_option()]) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [stack_item()]}}
Decodes an erlang term from json text (a utf8 encoded binary)
> jsone:try_decode(<<"[1,2,3] \"next value\"">>, []).
{ok,[1,2,3],<<" \"next value\"">>}
> jsone:try_decode(<<"wrong json">>, []).
{error,{badarg,[{jsone_decode,number_integer_part,
[<<"wrong json">>,1,[],<<>>],
[{line,208}]}]}}
try_encode(JsonValue::json_value()) -> {ok, binary()} | {error, {Reason::term(), [stack_item()]}}
Equivalent to try_encode(JsonValue, [])
.
try_encode(JsonValue::json_value(), Options::[encode_option()]) -> {ok, binary()} | {error, {Reason::term(), [stack_item()]}}
Encodes an erlang term into json text (a utf8 encoded binary)
> jsone:try_encode([1, null, 2]).
{ok,<<"[1,null,2]">>}
> jsone:try_encode([1, hoge, 2]). % 'hoge' atom is not a json value
{error,{badarg,[{jsone_encode,value,
[hoge,[{array_values,[2]}],<<"[1,">>],
[{line,86}]}]}}