用erlang解析ejabberd数据包
Parsing ejabberd packet with erlang
我正在使用 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 标签的 value 属性在 ( media, location , test ) 值上创建一个 switch 语句,以便我可以分别处理每条消息 ?
您可以将参数列表中的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
我正在使用 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 标签的 value 属性在 ( media, location , test ) 值上创建一个 switch 语句,以便我可以分别处理每条消息 ?
您可以将参数列表中的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