如何模式mochijson2返回的匹配结构?

时间:2011-06-10 16:25:23

标签: erlang mochiweb webmachine mochijson2

我刚刚开始修补Erlang并正在构建一个非常简单的测试网络应用程序,它只是为了显示我的推特时间线。

我正在使用webmachine编写应用程序,使用erlyDTL来渲染模板。

我的问题与mochiweb的mochijson2:decode/1函数返回的结构有关。

我可以成功获取和取消时间轴,如下例所示:

1> Url = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=<TWITTER_SCREEN_NAME_HERE>".
2> inets:start().
3> {ok, {_, _, Response}} = httpc:request(Url).
4> DecodedJson = mochijson2:decode(Response).

mochijson2:decode/1函数返回格式的元组列表:

[{struct, proplist()}, {struct, proplist()}, ...]

但是,要将时间轴传递给erlyDTL,我需要删除struct atom标记,并简单地将一个proplists列表传递给webmachine资源(由erlyDTL呈现)。作为模式匹配的新手,我认为以下列表理解可以达到这个目的:

Timeline = [Tweet || {struct, Tweet} <- DecodedJson].

实际上,这适用于每个推文列表中的所有项目,除了一个<<"user">>,其值本身一个{struct, proplist()}元组。我不能为我的生活弄清楚如何从这个嵌套元组中查找struct原子,并想知道是否有人可以提供一个Erlang代码示例,它将模式匹配{{1}中的外部推文每个推文中都包含用户{struct, Tweet}

最终目标是能够以Django模板语言访问每条推文,如下例所示:

{struct, User}

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:2)

以下是我们在内部用于类似目的的内容:

%% @doc Flatten {struct, [term()]} to [term()] recursively.
destruct({struct, L}) ->
    destruct(L);
destruct([H | T]) ->
    [destruct(H) | destruct(T)];
destruct({K, V}) ->
    {K, destruct(V)};
destruct(Term) ->
    Term.

对于mochijson2术语的其他用途,KVC可能对您有用:https://github.com/etrepum/kvc

答案 1 :(得分:2)

在我最近开展的一个项目中,我们正在处理来自 EXT JS 前端应用程序的大型JSON数据结构。下面是JSON对象的一个​​示例(这只是JSON的骨架):

{
        "presence_token":"734737328233HDHSBSHSYEYEYWYWGWE",
        "presence_time":"HH:Mins:Secs",
        "friend_requests":
        [
            {
                "from":"Username",
                "type":"buddy",
                "date":"DD/MM/YY",
                "time":"HH:Mins:Secs",
                "name":"Your Full name",
                "email":"user@example.com"
            }
        ],
        "group_status":
        [
            {
                "group_name":"ecampus",
                "status":"running",
                "members":["phil","josh","shazz"],
                "start_date":"DD/MM/YY",
                "start_time":"HH:Mins:Secs"             
            },
            {
                "group_name":"buganda",
                "status":"off"
            }
        ],
        "friend_status":
        [
            {
                "friend":"Friend_username",
                "status":"online",
                "log_on_time":"HH:Mins:Secs",
                "state":"available",
                "name":"Friend_Fullname",
                "email":"user@example.com"              
            },
            {
                "friend":"Friend_username",
                "status":"offline",                 
                "name":"Friend_Fullname",
                "email":"user@example.com"              
            }           
        ]           
    }

mochijson2:decode/1之后,我看起来像这样的结构对象:

        {struct,[{<<"presence_token">>,
                  <<"734737328233HDHSBSHSYEYEYWYWGWE">>},
                 {<<"presence_time">>,<<"HH:Mins:Secs">>},
                 {<<"friend_requests">>,
                  [{struct,[{<<"from">>,<<"Username">>},
                            {<<"type">>,<<"buddy">>},
                            {<<"date">>,<<"DD/MM/YY">>},
                            {<<"time">>,<<"HH:Mins:Secs">>},
                            {<<"name">>,<<"Your Full name">>},
                            {<<"email">>,<<"user@example.com">>}]}]},
                 {<<"group_status">>,
                  [{struct,[{<<"group_name">>,<<"ecampus">>},
                            {<<"status">>,<<"running">>},
                            {<<"members">>,[<<"phil">>,<<"josh">>,<<"shazz">>]},
                            {<<"start_date">>,<<"DD/MM/YY">>},
                            {<<"start_time">>,<<"HH:Mins:Secs">>}]},
                   {struct,[{<<"group_name">>,<<"buganda">>},
                            {<<"status">>,<<"off">>}]}]},
                 {<<"friend_status">>,
                  [{struct,[{<<"friend">>,<<"Friend_username">>},
                            {<<"status">>,<<"online">>},
                            {<<"log_on_time">>,<<"HH:Mins:Secs">>},
                            {<<"state">>,<<"available">>},
                            {<<"name">>,<<"Friend_Fullname">>},
                            {<<"email">>,<<"user@example.com">>}]},
                   {struct,[{<<"friend">>,<<"Friend_username">>},
                            {<<"status">>,<<"offline">>},
                            {<<"name">>,<<"Friend_Fullname">>},
                            {<<"email">>,<<"user@example.com">>}]}]}]}

现在我决定创建一个模块,将这个结构转换为&#34; deep&#34; proplist,这个模块将包含一个函数struct:all_keys/1,如果我用struct对象提供它,它会以有条理的方式生成列表和元组。这是代码:

-module(struct).
-export([all_keys/1]).

is_struct({struct,_}) -> true;
is_struct(_) -> false.

to_binary(S) when is_list(S)-> list_to_binary(S);
to_binary(S) when is_integer(S)-> S;
to_binary(S) when is_atom(S)-> to_binary(atom_to_list(S));
to_binary(S) -> S.

to_value(V) when is_binary(V)-> binary_to_list(V);
to_value(V) when is_integer(V)-> V;
to_value(V) when is_list(V)-> 
    try list_to_integer(V) of
        PP -> PP
    catch
        _:_ -> 
            try list_to_float(V) of
                PP2 -> PP2
            catch
                _:_ -> V
            end
    end;
to_value(A)-> A.

to_value2({struct,L})->
    all_keys({struct,L});
to_value2([{struct,_L}|_Rest] = LL)->
    [all_keys(XX) || XX <- LL];
to_value2(D) when is_binary(D)-> to_value(D);
to_value2(D) when is_list(D)-> 
    [to_value2(Any) || Any <- D].    

all_keys({struct,L})-> 
    [{to_value(Key),to_value2(Val)} || {Key,Val} <- L];
all_keys(List)-> [all_keys(X) || X <- List].

现在,调用struct:all_keys(Struct_object)将提供此输出:

[{"presence_token",P_token},
 {"presence_time",P_time},
 {"friend_requests",
  [[{"from","Username"},
    {"type","buddy"},
    {"date","DD/MM/YY"},
    {"time","HH:Mins:Secs"},
    {"name","Your Full name"},
    {"email","user@example.com"}]]},
 {"group_status",
  [[{"group_name","ecampus"},
    {"status","running"},
    {"members",["phil","josh","shazz"]},
    {"start_date","DD/MM/YY"},
    {"start_time","HH:Mins:Secs"}],
   [{"group_name","buganda"},{"status","off"}]]},
 {"friend_status",
  [[{"friend","Friend_username"},
    {"status","online"},
    {"log_on_time","HH:Mins:Secs"},
    {"state","available"},
    {"name","Friend_Fullname"},
    {"email","user@example.com"}],
   [{"friend","Friend_username"},
    {"status","offline"},
    {"name","Friend_Fullname"},
    {"email","user@example.com"}]]}]

上述proplist比struct对象更容易使用。但是,你可能会发现另一个版本的struct模块,特别是在一个名为Sticky Notes的着名mochiweb示例中,我现在没有链接。我上面粘贴的struct模块应该可以帮助你使用mochijson2。 成功

答案 2 :(得分:0)

根据您描述的结构,您可以尝试:

timeline(List) -> timeline(List, []).

timeline([], Result) -> lists:reverse(Result);
timeline([{struct, S}|T], Result) -> timeline(T, [S|Result]);
timeline([{<<"user">>, {struct, S}}|T], Result) -> timeline(T, [S|Result]);
timeline([_|T], Result) -> timeline(T, Result).

我将该代码放在名为twitter的模块中:

> twitter:timeline([{struct, 1}, {struct, 2}, {<<"user">>, {struct, 3}}, 5]).
[1,2,3]

您可能希望将<<"user">>替换为_,具体取决于您的具体需求。您可能还想介绍某种exception handling,因为您正在处理来自外部世界的输入。