Q:

Ejabberd Packet parsing using erlang

Ejabberd server receives packet like this:
  {xmlel,<<"message">>,[{<<"from">>,<<"user1@localhost/resource">>},{<<"to">>,<<"user2@localhost">>},{<<"xml:lang">>,<<"en">>},{<<"id">>,<<"947yW-9">>}],[{xmlcdata,<<">">>},{xmlel,<<"body">>,[],[{xmlcdata,<<"Helllo wassup!">>}]}]}

I want to fetch data from this packet.
Needed data : Type, If the body has a certain parameter, say {<<"xml:lang">>,<<"en">>}
I am doing the following operations:
  {_XMLEL, TYPE, DETAILS , _BODY} = Packet

This provides me the type : <<"message">> or <<"iq">> or <<"presence">>.
To check if DETAILS has {<<"xml:lang">>,<<"en">>} I do this:
 Has_Attribute=lists:member({<<"xml:lang">>,<<"en">>},DETAILS)

Is there any better way to do this?
I also need the to and from attributes from the packet.

A:

Use a combination of pattern matching in the function head together with a fold over the details to extract everything you need.
The function below returns a list of key-value tuples, where the <<"type">> tuple is artificially created so the list is homogenous:
extract({xmlel, Type, Details, _}) ->
    [{<<"type">>,Type} |
     lists:foldl(fun(Key, Acc) ->
                         case lists:keyfind(Key, 1, Details) of
                             false -> Acc;
                             Pair -> [Pair|Acc]
                         end
                 end, [], [<<"from">>,<<"to">>,<<"xml:lang">>])];
extract(_) -> [].

The first clause matches the {xmlel, ...} tuple, extracting Type and Details. The return value consists of a list with head {<<"type">>,Type} followed by a tail formed from folding over the list of keys to be extracted from Details. The second clause matches anything not a {xmlel, ...} tuple and just returns the empty list.
Putting this function into a module named z and passing it your data:
1> z:extract({xzlel,<<"message">>,[{<<"from">>,<<"user1@localhost/resource">>},{<<"to">>,<<"user2@localhost">>},{<<"xml:lang">>,<<"en">>},{<<"id">>,<<"947yW-9">>}],[{xmlcdata,<<">">>},{xmlel,<<"body">>,[],[{xmlcdata,<<"Helllo wassup!">>}]}]}).
[{<<"type">>,<<"message">>},
 {<<"xml:lang">>,<<"en">>},
 {<<"to">>,<<"user2@localhost">>},
 {<<"from">>,<<"user1@localhost/resource">>}]

