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

发布于 2024-11-15 04:05:23 字数 1333 浏览 12 评论 0原文

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

我正在使用 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 原子标签,并简单地将 proplist 列表传递给 webmachine 资源(由 erlyDTL 渲染)。作为模式匹配的新手,我认为以下列表理解可以实现这一点:

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

事实上,这对于每个推文 proplist 中的所有项目都非常有效,除了一个 <<"user">> 。,其值本身是一个{struct, proplist()}元组。我一生都无法弄清楚如何从这个嵌套元组中删除 struct 原子,并且想知道是否有人可以提供一个 Erlang 代码示例,该示例将模式匹配 < 中的外部推文code>{struct, Tweet} 和每条推文中包含的 User {struct, User}

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

{{ tweet.text }}  <- works
{{ tweet.created_at }}  <- works
{{ tweet.user.profile_image_url }}  <- ???

任何帮助将不胜感激!

I've just started tinkering with Erlang and am building a very simple test web application which is just intended to show my twitter timeline.

I'm using webmachine to write the app and erlyDTL to render the templates.

My question is related to the structures returned by mochiweb's mochijson2:decode/1 function.

I can successfully fetch and deocde my timeline as in the following example:

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).

The mochijson2:decode/1 function returns a list of tuples of the format:

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

However, to pass the timeline into erlyDTL I need to get rid of the struct atom tag and simply pass a list of proplists to the webmachine resource (rendered by erlyDTL). Being quite new to pattern matching, I figured that the following list comprehension would achieve this:

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

Indeed, this works perfectly for all of the items in each Tweet proplist except for one, <<"user">>, the value of which is itself a {struct, proplist()} tuple. I can't for the life of me figure out how to nuke the struct atom from this nested tuple and was wondering if anyone could provide an example of Erlang code which would pattern match both the outer Tweet in {struct, Tweet} and the User {struct, User} contained within each Tweet.

The end goal is to be able to access each tweet in Django template language as in the following example:

{{ tweet.text }}  <- works
{{ tweet.created_at }}  <- works
{{ tweet.user.profile_image_url }}  <- ???

Any help would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

书间行客 2024-11-22 04:05:23

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

%% @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

Here's what we use internally for a similar purpose:

%% @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.

For other uses of mochijson2 terms, KVC might be useful to you: https://github.com/etrepum/kvc

疯了 2024-11-22 04:05:23

在我最近从事的一个项目中,我们正在处理来自 EXT JS 前端应用程序。下面是 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":"[email protected]"
            }
        ],
        "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":"[email protected]"              
            },
            {
                "friend":"Friend_username",
                "status":"offline",                 
                "name":"Friend_Fullname",
                "email":"[email protected]"              
            }           
        ]           
    }

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">>,<<"[email protected]">>}]}]},
                 {<<"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">>,<<"[email protected]">>}]},
                   {struct,[{<<"friend">>,<<"Friend_username">>},
                            {<<"status">>,<<"offline">>},
                            {<<"name">>,<<"Friend_Fullname">>},
                            {<<"email">>,<<"[email protected]">>}]}]}]}

现在我决定创建一个模块它将将此结构转换为“深层”proplist,该模块将包含一个函数 struct:all_keys/1 ,如果我向它提供结构对象,它将以有组织的方式生成列表和元组。代码如下:

-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","[email protected]"}]]},
 {"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","[email protected]"}],
   [{"friend","Friend_username"},
    {"status","offline"},
    {"name","Friend_Fullname"},
    {"email","[email protected]"}]]}]

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

In a recent project ive worked on, we were dealing with big JSON data structures coming from EXT JS front end apps. One example of the JSON object is here below (this is just the skeleton of the 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":"[email protected]"
            }
        ],
        "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":"[email protected]"              
            },
            {
                "friend":"Friend_username",
                "status":"offline",                 
                "name":"Friend_Fullname",
                "email":"[email protected]"              
            }           
        ]           
    }

After mochijson2:decode/1, the struct object i had appears like this:

        {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">>,<<"[email protected]">>}]}]},
                 {<<"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">>,<<"[email protected]">>}]},
                   {struct,[{<<"friend">>,<<"Friend_username">>},
                            {<<"status">>,<<"offline">>},
                            {<<"name">>,<<"Friend_Fullname">>},
                            {<<"email">>,<<"[email protected]">>}]}]}]}

Now i decided to create a module which will convert this struct into a "deep" proplist, this module would contain a function struct:all_keys/1 which if i feed it with the struct object it generates lists and tuples in an organised way. Here is the code:

-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].

Now, calling struct:all_keys(Struct_object) will give this output:

[{"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","[email protected]"}]]},
 {"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","[email protected]"}],
   [{"friend","Friend_username"},
    {"status","offline"},
    {"name","Friend_Fullname"},
    {"email","[email protected]"}]]}]

The above proplist is easier to work with than the struct object. However, you may find another version of the struct module especially in a famous mochiweb example called Sticky Notes whose link i do not have right now.The struct module i have pasted above should be able to help you with using mochijson2.
success

淑女气质 2024-11-22 04:05:23

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

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">>_ 取决于您的具体需求。您可能还想引入某种异常处理,因为您正在处理来自外部世界的输入。

Based on the structure you described, you could try:

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).

I put that code in a module called twitter:

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

You may want to replace <<"user">> with _ depending on your specific needs. You probably also want to introduce some kind of exception handling since you are dealing with input from the outside world.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文