Как сопоставить структуры соответствия, возвращаемые mochijson2? - PullRequest
1 голос
/ 10 июня 2011

Я только что начал работать с Erlang и создаю очень простое тестовое веб-приложение, которое просто предназначено для отображения моей временной шкалы в твиттере.

Я использую webmachine для написания приложения и erlyDTL для рендерингаtemplates.

Мой вопрос связан со структурами, возвращаемыми функцией mochijson2:decode/1 mochiweb.

Я могу успешно извлечь и отменить мою временную шкалу, как в следующем примере:

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, мне нужно избавиться от тега atom struct и просто передать списокиз проплистов на ресурс веб-машины (предоставленный erlyDTL).Будучи совершенно новым для сопоставления с образцом, я решил, что следующее понимание списка достигнет этого:

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

Действительно, это прекрасно работает для всех элементов в каждом твитт-проплисте, кроме одного, <<"user">>,значение которого само по себе a {struct, proplist()} кортеж.Я не могу понять, как обнулить атом struct из этого вложенного кортежа, и мне было интересно, кто-нибудь может привести пример кода Erlang, который будет соответствовать шаблону как внешнего твита в {struct, Tweet}, так и пользователя{struct, User} содержится в каждом твите.

Конечная цель - получить доступ к каждому твиту на языке шаблонов Django, как в следующем примере:

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

Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

2 голосов
/ 11 июня 2011

Вот что мы используем для внутренних целей:

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

2 голосов
/ 13 июня 2011

В недавнем проекте, над которым я работал, мы имели дело с большими структурами данных JSON из 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":"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, который у меня был, выглядит следующим образом:

        {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">>}]}]}]}

Теперь я решил создать модуль, который преобразует эту структуру в «глубокий» проплист, этот модуль будет содержать функцию 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","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"}]]}]

С вышеуказанным проплистом работать легче, чем с объектом struct.Тем не менее, вы можете найти другую версию модуля struct, особенно в известном примере mochiweb, который называется Sticky Notes, ссылку на который у меня сейчас нет. Вставленный выше модуль struct должен помочь вам в использовании mochijson2.успех

0 голосов
/ 11 июня 2011

Исходя из структуры, которую вы описали, вы можете попробовать:

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">> с _ в зависимости от ваших конкретных потребностей.Возможно, вы также захотите ввести какую-то обработку исключений , поскольку вы имеете дело с вводом данных из внешнего мира.

...