5

I have a var that has some JSON data:

A = <<"{\"job\": {\"id\": \"1\"}}">>. 

Using mochijson2, I decode the data:

 Struct = mochijson2:decode(A). 

And now I have this:

{struct,[{<<"job">>,{struct,[{<<"id">>,<<"1">>}]}}]}

I am trying to read (for example), "job" or "id".

I tried using struct.get_value but it doesn't seem to work.

Any ideas?

Jon Romero
  • 4,062
  • 6
  • 36
  • 34

5 Answers5

13

The data is in {struct, proplist()} format, so here's what you do:

{struct, JsonData} = Struct,
{struct, Job} = proplists:get_value(<<"job">>, JsonData),
Id = proplists:get_value(<<"id">>, Job),

You can read more about proplists at: http://www.erlang.org/doc/man/proplists.html

scatterbrain
  • 354
  • 2
  • 7
5

Another helper function to access json structure:

jsonobj({struct,List}) ->
    fun({contains,Key}) ->
        lists:keymember(Key,1,List);
    ({raw,Key}) ->
        {_,Ret} = lists:keyfind(Key,1,List),Ret;
    (Key) ->
        {_,Ret} = lists:keyfind(Key,1,List),
        jsonobj(Ret)
    end;
jsonobj(List) when is_list(List) ->
    fun(len) ->
        length(List);
    (Index) ->
        jsonobj(lists:nth(Index,List))
    end;
jsonobj(Obj) -> Obj.

Usage:

1> A=mochijson2:decode(<<"{\"job\": {\"id\": \"1\", \"ids\": [4,5,6], \"isok\": true}}">>).
2> B=jsonobj(A).
3> B(<<"job">>).
#Fun<jsonutils.1.33002110>
4> (B(<<"job">>))(<<"id">>).
1
5> (B(<<"job">>))(<<"ids">>).
#Fun<jsonutils.1.9495087>
6> (B(<<"job">>))({raw,<<"ids">>}).
[4,5,6]
7> ((B(<<"job">>))(<<"ids">>))(1).
4
8> B({raw,<<"job">>}).
{struct,[{<<"id">>,<<"1">>},
               {<<"ids">>,[1,2,3]},
               {<<"isok">>,true}]}
9> B({contains,<<"job">>}).
true
10> B({contains,<<"something">>}).
false
11> ((B(<<"job">>))(<<"ids">>))(len)
3

I don't think extracting values from json can be any simpler.

yetihehe
  • 620
  • 8
  • 11
2

Here is another method of accessing the data. Uses records syntax for ease of use.

-record(struct, {lst=[]}).

A = <<"{\"job\": {\"id\": \"1\"}}">>,
Struct = mochijson2:decode(A), 
Job = proplists:get_value(<<"job">>, Struct#struct.lst),
Id = proplists:get_value(<<"id">>, Job#struct.lst),

Does exactly the same thing as the answer using records instead. Just another option when using mochijson2. I personally like this syntax better.

Luigimax
  • 546
  • 1
  • 5
  • 12
1

Adding to the answer given earlier there's also a nice tutorial on mochiweb, json (video).

Community
  • 1
  • 1
YasirA
  • 9,531
  • 2
  • 40
  • 61
1

My favourite way of handeling mochijson data is replacing all the struct's with hash maps after which they can be cleanly pattern matched. To do so I wrote this easy to understand function:

structs_to_maps({struct, Props}) when is_list(Props) ->
    lists:foldl(
        fun({Key, Val}, Map) ->
            Map#{Key => structs_to_maps(Val)}
        end,
        #{},
        Props
    );
structs_to_maps(Vals) when is_list(Vals) ->
    lists:map(
        fun(Val) ->
            structs_to_maps(Val)
        end,
        Vals
    );
structs_to_maps(Val) ->
    Val.

Here is an example of how to use it:

do() ->
    A = <<"{\"job\": {\"id\": \"1\"}}">>,
    Data = structs_to_maps(mochijson2:decode(A)),
    #{<<"job">> := #{<<"id">> := Id}} = Data,
    Id.

This has many advantages especially when working with incoming data that can have an unexpected shape.

Dirk Geurs
  • 2,392
  • 19
  • 24