Разбор пакета ejabberd с помощью erlang - PullRequest
0 голосов
/ 06 ноября 2018

Я использую ejabberd18.09 для приложения чата. Приложение имеет несколько функций, необходимых для добавления расширений в сообщения ejabberd (xmpp).

Я создал пользовательский модуль в offline_message_hook для захвата автономных сообщений и отправки их на мой собственный URL для дальнейшей обработки.

сообщения, отправляемые в ejabberd, имеют разные случаи в зависимости от типа сообщения, следующего за

если я отправляю фото, сообщение будет выглядеть следующим образом

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="media" />
   <url xmlns="urn:xmpp:url" id="myId" mediaType="photo" link="myphotourl.com" />
   <body>thumbnail string</body>
</message>

при отправке текста

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="text" />
   <body>Hi John</body>
</message>

при отправке местоположения

<message xmlns="jabber:client" xml:lang="en" to="someuserjid2" from="{someuserjid}" type="chat" id="mP8tO-8">
   <mtype xmlns="urn:xmpp:mtype" value="location" />
   <location xmlns="urn:xmpp:geo" lat="1.2" lng="2.2 " />
   <body>location thumbnailstring</body>
</message>

Я использовал код .erl, чтобы прочитать тело и идентификатор сообщения следующим образом

create_message(_From, _To, Packet) when (Packet#message.type == chat) and (Packet#message.body /= []) ->
  Body = fxml:get_path_s(Packet, [{elem, list_to_binary("body")}, cdata]),
  MessageId = fxml:get_tag_attr_s(list_to_binary("id"), Packet),
  post_offline_message(_From, _To, Body, MessageId),
  ok.

я хочу, чтобы (на эрланге) я мог прочитать атрибут value тега mtype , для которого был создан оператор switch (media, location, test) значения, чтобы я мог обрабатывать каждое сообщение отдельно?

1 Ответ

0 голосов
/ 07 ноября 2018

Вы можете передать attr в списке аргументов fxml:get_path_s, чтобы выбрать значение атрибута определенного элемента:

case fxml:get_path_s(Packet, [{elem, <<"mtype">>}, {attr, <<"value">>}]) of
    <<"media">> ->
        %% handle media...
    <<"location">> ->
        %% handle location...
    <<"">> ->
        %% no mtype element, or missing value attribute!
        %% let's handle that case as well
end

Еще одна мысль: вам действительно нужен элемент <mtype>? Похоже, вы можете просто проверить наличие элемента <location> или <url>. Вы можете сделать это так:

case fxml:get_subtag(Packet, <<"location">>) of
    false ->
        %% No location. Try url
        case fxml:get_subtag(Packet, <<"url">>) of
            false ->
                %% Neither location nor url
                %% Handle this case somehow...
            Url ->
                %% Do something with Url...
        end
    Location ->
        %% Do something with Location...
end

Код становится немного запутанным, поскольку нам нужно вложить выражения case, в отличие от предыдущей версии, в которой мы только что проверили значение одного выражения. Одна вещь, которую вы могли бы сделать, это написать вспомогательную функцию, которая пробует каждый элемент по очереди:

find_one_of(Packet, []) ->
    not_found;
find_one_of(Packet, [ElementName | Rest]) ->
    case fxml:get_subtag(Packet, ElementName) of
        false ->
            find_one_of(Packet, Rest);
        Element ->
            {ElementName, Element}
    end.

А затем назовите это как:

case find_one_of(Packet, [<<"location">>, <<"url">>]) of
    {<<"location">>, Location} ->
        %% Do something with Location...
    {<<"url">>, Url} ->
        %% Do something with Url...
    not_found ->
        %% Neither location nor url
end
...