0

我正在使用 ejabberd18.09 进行 IM 应用程序。该应用程序几乎没有需要向 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 代码读取正文和消息 ID,如下所示

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.

我想要的是如何(在 erlang 中)读取mtype标记的属性,在(媒体、位置、测试)值上创建一个 switch 语句,以便我可以分别处理每条消息?

4

1 回答 1

2

你可以传入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>元素吗?看起来你可以只检查 a <location>or<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
于 2018-11-07T09:40:35.643 回答