This repository has been archived by the owner on Jan 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
5. Pre encode and post decode
Richard Jonas edited this page May 17, 2016
·
4 revisions
We have the most powerful tool which we need to use wisely. For almost each type of data we can pre-process values before encoding and also we can post-process values after decoding data from JSON. Let us a simple example for that. Suppose that we need to convert calendar:datetime()
to ISO date format.
%% We serialize log messages where both the message
%% and the time will be binary (string) in JSON.
-json({log, {binary, message},
{binary, time, [{pre_encode, {?MODULE, time_to_binary}},
{post_decode, {?MODULE, binary_to_time}}]
}
}).
-export([time_to_binary/2, binary_to_time/2]).
time_to_binary(_LogRecord, Time) ->
%% We got the whole record and the time before encoding
%% Time is supposed to be a calendar:datetime() format.
%% We convert something like 2011-08-28T15:41:09Z
{{Y, Mo, D}, {H, Mi, S}} = Time,
io_lib:format("~4..0B-~2..0B-~2..0BT~2..0B:~2..0B:~2..0BZ",
[Y, Mo, D, H, Mi, S])).
binary_to_time(_Record, IsoDate) ->
%% Here we have a structure which is half-ready in the first
%% parameter. It is in jsx raw format like:
%% [{<<"attr1">>, <<"value1">>}, ...] where value part can be
%% a binary, a boolean, a number or undefined
parse_iso_to_date(IsoDate).
parse_iso_date(<<Y1, Y2, Y3, Y4, $-, Mo1, Mo2, $-, D1, D2, $T,
H1, H2, $:, Mi1, Mi2, $:, S1, S2, $Z>>) ->
{{list_to_integer([Y1, Y2, Y3, Y4]),
list_to_integer([Mo1, Mo2]),
list_to_integer([D1, D2])},
{list_to_integer([H1, H2]),
list_to_integer([Mi1, Mi2]),
list_to_integer([S1, S2])}}.
In this example the converter functions are a bit long but covers most of the input possibilities. Here is the workflow during encoding:
- we create a log record as
{log, <<"Hello">>, {{2011, 8, 28}, {15, 41, 9}}}
- call
ejson:to_json/1
to that value -
ejson
calls thepre_encode
function for that value - the intermediate result is
[{<<"__rec">>, <<"log">>}, {<<"message">>, <<"Hello">>}, {<<"time">>, <<"2011-08-28T15:41:09Z">>}]
- so the JSON can be resulted from that jsx list
During decoding:
- from JSON string jsx creates the intermediate jsx list:
[{<<"__rec">>, <<"log">>}, {<<"message">>, <<"Hello">>}, {<<"time">>, <<"2011-08-28T15:41:09Z">>}]
-
ejson
knows from the value of<<"__rec">>
that the target type islog
- applies normal decoding process, so we will have a
{log, <<"Hello">>, <<"2011-08-28T15:41:09Z">>}
record - applies
post_decode
function for the ISO date value, so the time will be{{2011, 8, 28}, {15, 41, 9}}
- and we get the record we have in the beginning.