在 ejabberd 中过滤消息包的主体
Filtering message packet's body in ejabberd
我正在尝试过滤 ejabberd 中不需要的消息。我从 this post 那里得到了一些指导。这是通过 filter_packet 挂钩执行的函数片段:
check_stanza({_From, _To, #xmlel{name = StanzaType}} = Input) ->
AccessRule = case StanzaType of
<<"message">> ->
?DEBUG("filtering packet...~nFrom: ~p~nTo: ~p~nPacket: ~p~nResult: ",
[_From, _To, Input]),
Input
%check_stanza_type(AccessRule, Input)
end.
日志中打印的数据包:
{{jid,<<"test25">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>,
<<"test25">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},{jid,
<<"test24">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>,
<<"test24">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},{xmlel,
<<"message">>,[{<<"type">>,<<"chat">>},{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,<<"test24@localhost/Administrators-MacBook-Pro-6">>}],[{xmlel,
<<"active">>,[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},{xmlel,<<"body">>,[],[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
我的要求:提取邮件正文并过滤掉辱骂性词语。例如,如果用户发送 "message body goes here",则应出现以下序列:
- 发件人的数据包被模块拦截,通过钩子(完成)
- 消息正文被提取出来,单词运行通过一组数据进行过滤。数据可以在 Mnesia 或 MySQL(待定)
- 更改后的数据包(过滤后的正文)被传送到接收方客户端
如果 "here" 是一个不需要的词,接收者将收到 "message body goes ****"。
我是 Erlang 的新手,它是一个小社区,那里很少有好文章,所以需要一些关于实现上述目标的最佳方法的建议。关于如何使用长生不老药支持做同样的事情,有一个很好的 post,但我想坚持使用 Erlang。任何帮助将不胜感激。
更新
感谢 Amiramix。这是替换特定单词的代码:
{xmlel,Syntax,Type,OuterBody} = Xmlel.
case Syntax ->
"<<message>>" ,
XmlelBody = lists:keyfind(<<"body">>, 2, OuterBody), %{xmlel,<<"body">>,[],[{xmlcdata,<<"HI">>}]}
{xmlel,BodySyntax,_,Innerbody} = XmlelBody, % [{xmlcdata,<<"HI">>}]
Body = proplists:get_value(xmlcdata, Innerbody), %<<"HI">>
TmpList = re:replace(Body,<<"HI$">>,<<"**">>),
NewBody = binary:list_to_bin(TmpList), %<<"**">>
NewInnerBody = lists:keyreplace(xmlcdata, 1, Innerbody, {xmlcdata, NewBody}). %[{xmlcdata,<<"**">>}]
NewXmlelBody = setelement(4,XmlelBody,NewInnerBody), %{xmlel,<<"body">>,[],[{xmlcdata,<<"**">>}]}
NewOuterBody = lists:keyreplace(<<"body">>, 2, OuterBody, NewXmlelBody),
NewXmlel = setelement(4, Xmlel, NewOuterBody)
因为很难在许多被屏蔽的词上重复正文中的每个词,我想将提取的正文发送到一个 python 脚本,它会为我做这件事。关于如何从 <<"MESSAGE BODY GOES HERE">> 中提取 MESSAGE BODY GOES HERE 的任何建议?
日志与代码不匹配,即输出中没有 "filtering packet...",因此我无法为您提供确切的代码以放入 check_stanza
函数。而且我对 ejabberd
了解不多,无法验证。但是,我想给您一些指导,告诉您如何在 Erlang 中处理此类结构,以便您可以更轻松地自己做自己想做的事。
首先重新格式化结构,以便清楚数据是如何嵌套的:
{
{jid,
<<"test25">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,
<<"test25">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>
},
{jid,
<<"test24">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,
<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>
},
{xmlel, <<"message">>,
[
{<<"type">>, <<"chat">>},
{<<"id">>, <<"purpleaed2ec77">>},
{<<"to">>, <<"test24@localhost/Administrators-MacBook-Pro-6">>}
],
[
{xmlel, <<"active">>,
[{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}], []
},
{xmlel, <<"body">>, [],
[{xmlcdata, <<"MESSAGE BODY GOES HERE">>}]
}
]
}
}.
你有一个外部元组,内部有三个元组:
{ {jid, ...}, {jid, ...}, {xmlel, ...} }.
外部数据是一个元组看起来不太对,我希望它是一个列表,例如:
[ {jid, ...}, {jid, ...}, {xmlel, ...} ].
但也许就是这样,但请确保您正确记录了它。
要修改正文,您需要执行以下步骤:
- 提取包含正文
的xmlcdata
- 修改正文
- 将其存储回主结构
在继续之前,请将整个结构复制到 Erlang shell 并将其存储为一个变量,以便您可以按照自己的 shell 进行操作。不要忘记在开头添加变量名,在末尾添加 '.'
:
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.2.1 (abort with ^G)
1> M =
1> {
1> {jid,
1> <<"test25">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>,
1> <<"test25">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>
1> },
1> {jid,
1> <<"test24">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>,
1> <<"test24">>,
1> <<"localhost">>,<<"Administrators-MacBook-Pro-6">>
1> },
1> {xmlel, <<"message">>,
1> [
1> {<<"type">>, <<"chat">>},
1> {<<"id">>, <<"purpleaed2ec77">>},
1> {<<"to">>, <<"test24@localhost/Administrators-MacBook-Pro-6">>}
1> ],
1> [
1> {xmlel, <<"active">>,
1> [{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}], []
1> },
1> {xmlel, <<"body">>, [],
1> [{xmlcdata, <<"MESSAGE BODY GOES HERE">>}]
1> }
1> ]
1> }
1> }.
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{jid,<<"test24">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
2>
现在只需在 shell 中键入 M.
即可打印出整个结构(为简洁起见,删减):
2> M.
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
(...)
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
如果数据确实是一个元组,你可以用这个代码得到最后一个子元组:
3> {_, _, Xmlel} = M.
同样,在 shell 中键入 Xmlel.
将打印出该变量的内容('_'
表示 不关心 或一个 anonymous variable)。现在要提取最后一个列表,xmlel
本身就是一个元组:
4> {xmlel, _, _, L} = Xmlel.
<<"message">>
与第一个 '_'
匹配,然后第一个列表与第二个 '_'
匹配。然后将第二个列表绑定到 L
:
6> L.
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]
您想要包含 <<"body">>
值的元组,例如:
7> T = lists:keyfind(<<"body">>, 2, L).
{xmlel,<<"body">>,[], [{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}
如果您需要解释这些函数的作用,请检查 lists:keyfind/3
documentation for information about arguments to that function. And check Erlang documentation for particular modules。
最后,我们想要包含正文元素的列表:
8> {xmlel, _, _, BL} = T.
绑定 BL
是一个 proplist,简单地获取正文:
16> Body = proplists:get_value(xmlcdata, BL).
<<"MESSAGE BODY GOES HERE">>
让我们替换字符串并重建结构:
21> TmpList = re:replace(Body, <<"HERE$">>, <<"*****">>).
[<<"MESSAGE BODY GOES ">>,<<"*****">>]
23> binary:list_to_bin(TmpList).
<<"MESSAGE BODY GOES *****">>
24> NewBody = binary:list_to_bin(TmpList).
<<"MESSAGE BODY GOES *****">>
现在新的主体是 NewBody
变量。我们用 lists:keyreplace/4
:
替换列表中的元组
28> NewBL = lists:keyreplace(xmlcdata, 1, BL, {xmlcdata, NewBody}).
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]
然后我们将元组中的元素替换为 setelement/3
:
31> NewT = setelement(4, T, NewBL).
{xmlel,<<"body">>,[], [{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}
公平地说,元组 {xmlel, <<"body">>, [], List}
可能是一个 Erlang record xmlel
,如果您知道该记录的定义,您可以用语义更正确的方式替换它, 比如:
32> NewT = T#xmlel{body = NewBody}
如果那确实是一条记录,那么它的定义必须在 ejabberd
代码中某处可用的 Erlang .hrl
文件之一中,您可以将其包含在代码中并使用。如果该记录的定义发生变化,您只能重新编译您的代码,它应该仍然有效。使用 setelement
存在这样的风险,即如果元组的大小发生变化,代码将停止工作,因此请牢记这一点。我将继续使用 setelement
,因为目前这对我来说更简单(记录定义需要使用 rr
导入到 shell,然后才能使用)。
现在剩下三个操作:替换主列表L
中的<<"body">>
元组,然后替换<<"message">>
元组中的L
,最后替换那个元组在主结构中:
35> NewL = lists:keyreplace(<<"body">>, 2, L, NewT).
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]
41> NewXmlel = setelement(4, Xmlel, NewL).
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]}
42> NewM = setelement(3, M, NewXmlel).
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{jid,<<"test24">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]}}
现在 NewM
包含与 M
相同的消息,但根据需要替换了正文。
这相当长,因为为了清楚起见,我分别对每个步骤进行了编码。实际上,在您的代码中使用它时,您将能够缩短这些步骤,特别是如果您可以包含并使用适当的记录定义。
我正在尝试过滤 ejabberd 中不需要的消息。我从 this post 那里得到了一些指导。这是通过 filter_packet 挂钩执行的函数片段:
check_stanza({_From, _To, #xmlel{name = StanzaType}} = Input) ->
AccessRule = case StanzaType of
<<"message">> ->
?DEBUG("filtering packet...~nFrom: ~p~nTo: ~p~nPacket: ~p~nResult: ",
[_From, _To, Input]),
Input
%check_stanza_type(AccessRule, Input)
end.
日志中打印的数据包:
{{jid,<<"test25">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>,
<<"test25">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},{jid,
<<"test24">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>,
<<"test24">>,<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},{xmlel,
<<"message">>,[{<<"type">>,<<"chat">>},{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,<<"test24@localhost/Administrators-MacBook-Pro-6">>}],[{xmlel,
<<"active">>,[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},{xmlel,<<"body">>,[],[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
我的要求:提取邮件正文并过滤掉辱骂性词语。例如,如果用户发送 "message body goes here",则应出现以下序列:
- 发件人的数据包被模块拦截,通过钩子(完成)
- 消息正文被提取出来,单词运行通过一组数据进行过滤。数据可以在 Mnesia 或 MySQL(待定)
- 更改后的数据包(过滤后的正文)被传送到接收方客户端
如果 "here" 是一个不需要的词,接收者将收到 "message body goes ****"。
我是 Erlang 的新手,它是一个小社区,那里很少有好文章,所以需要一些关于实现上述目标的最佳方法的建议。关于如何使用长生不老药支持做同样的事情,有一个很好的 post,但我想坚持使用 Erlang。任何帮助将不胜感激。
更新
感谢 Amiramix。这是替换特定单词的代码:
{xmlel,Syntax,Type,OuterBody} = Xmlel.
case Syntax ->
"<<message>>" ,
XmlelBody = lists:keyfind(<<"body">>, 2, OuterBody), %{xmlel,<<"body">>,[],[{xmlcdata,<<"HI">>}]}
{xmlel,BodySyntax,_,Innerbody} = XmlelBody, % [{xmlcdata,<<"HI">>}]
Body = proplists:get_value(xmlcdata, Innerbody), %<<"HI">>
TmpList = re:replace(Body,<<"HI$">>,<<"**">>),
NewBody = binary:list_to_bin(TmpList), %<<"**">>
NewInnerBody = lists:keyreplace(xmlcdata, 1, Innerbody, {xmlcdata, NewBody}). %[{xmlcdata,<<"**">>}]
NewXmlelBody = setelement(4,XmlelBody,NewInnerBody), %{xmlel,<<"body">>,[],[{xmlcdata,<<"**">>}]}
NewOuterBody = lists:keyreplace(<<"body">>, 2, OuterBody, NewXmlelBody),
NewXmlel = setelement(4, Xmlel, NewOuterBody)
因为很难在许多被屏蔽的词上重复正文中的每个词,我想将提取的正文发送到一个 python 脚本,它会为我做这件事。关于如何从 <<"MESSAGE BODY GOES HERE">> 中提取 MESSAGE BODY GOES HERE 的任何建议?
日志与代码不匹配,即输出中没有 "filtering packet...",因此我无法为您提供确切的代码以放入 check_stanza
函数。而且我对 ejabberd
了解不多,无法验证。但是,我想给您一些指导,告诉您如何在 Erlang 中处理此类结构,以便您可以更轻松地自己做自己想做的事。
首先重新格式化结构,以便清楚数据是如何嵌套的:
{
{jid,
<<"test25">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,
<<"test25">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>
},
{jid,
<<"test24">>,
<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,
<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>
},
{xmlel, <<"message">>,
[
{<<"type">>, <<"chat">>},
{<<"id">>, <<"purpleaed2ec77">>},
{<<"to">>, <<"test24@localhost/Administrators-MacBook-Pro-6">>}
],
[
{xmlel, <<"active">>,
[{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}], []
},
{xmlel, <<"body">>, [],
[{xmlcdata, <<"MESSAGE BODY GOES HERE">>}]
}
]
}
}.
你有一个外部元组,内部有三个元组:
{ {jid, ...}, {jid, ...}, {xmlel, ...} }.
外部数据是一个元组看起来不太对,我希望它是一个列表,例如:
[ {jid, ...}, {jid, ...}, {xmlel, ...} ].
但也许就是这样,但请确保您正确记录了它。
要修改正文,您需要执行以下步骤:
- 提取包含正文 的
- 修改正文
- 将其存储回主结构
xmlcdata
在继续之前,请将整个结构复制到 Erlang shell 并将其存储为一个变量,以便您可以按照自己的 shell 进行操作。不要忘记在开头添加变量名,在末尾添加 '.'
:
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.2.1 (abort with ^G)
1> M =
1> {
1> {jid,
1> <<"test25">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>,
1> <<"test25">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>
1> },
1> {jid,
1> <<"test24">>,
1> <<"localhost">>,
1> <<"Administrators-MacBook-Pro-6">>,
1> <<"test24">>,
1> <<"localhost">>,<<"Administrators-MacBook-Pro-6">>
1> },
1> {xmlel, <<"message">>,
1> [
1> {<<"type">>, <<"chat">>},
1> {<<"id">>, <<"purpleaed2ec77">>},
1> {<<"to">>, <<"test24@localhost/Administrators-MacBook-Pro-6">>}
1> ],
1> [
1> {xmlel, <<"active">>,
1> [{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}], []
1> },
1> {xmlel, <<"body">>, [],
1> [{xmlcdata, <<"MESSAGE BODY GOES HERE">>}]
1> }
1> ]
1> }
1> }.
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{jid,<<"test24">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
2>
现在只需在 shell 中键入 M.
即可打印出整个结构(为简洁起见,删减):
2> M.
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
(...)
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]}}
如果数据确实是一个元组,你可以用这个代码得到最后一个子元组:
3> {_, _, Xmlel} = M.
同样,在 shell 中键入 Xmlel.
将打印出该变量的内容('_'
表示 不关心 或一个 anonymous variable)。现在要提取最后一个列表,xmlel
本身就是一个元组:
4> {xmlel, _, _, L} = Xmlel.
<<"message">>
与第一个 '_'
匹配,然后第一个列表与第二个 '_'
匹配。然后将第二个列表绑定到 L
:
6> L.
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}]
您想要包含 <<"body">>
值的元组,例如:
7> T = lists:keyfind(<<"body">>, 2, L).
{xmlel,<<"body">>,[], [{xmlcdata,<<"MESSAGE BODY GOES HERE">>}]}
如果您需要解释这些函数的作用,请检查 lists:keyfind/3
documentation for information about arguments to that function. And check Erlang documentation for particular modules。
最后,我们想要包含正文元素的列表:
8> {xmlel, _, _, BL} = T.
绑定 BL
是一个 proplist,简单地获取正文:
16> Body = proplists:get_value(xmlcdata, BL).
<<"MESSAGE BODY GOES HERE">>
让我们替换字符串并重建结构:
21> TmpList = re:replace(Body, <<"HERE$">>, <<"*****">>).
[<<"MESSAGE BODY GOES ">>,<<"*****">>]
23> binary:list_to_bin(TmpList).
<<"MESSAGE BODY GOES *****">>
24> NewBody = binary:list_to_bin(TmpList).
<<"MESSAGE BODY GOES *****">>
现在新的主体是 NewBody
变量。我们用 lists:keyreplace/4
:
28> NewBL = lists:keyreplace(xmlcdata, 1, BL, {xmlcdata, NewBody}).
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]
然后我们将元组中的元素替换为 setelement/3
:
31> NewT = setelement(4, T, NewBL).
{xmlel,<<"body">>,[], [{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}
公平地说,元组 {xmlel, <<"body">>, [], List}
可能是一个 Erlang record xmlel
,如果您知道该记录的定义,您可以用语义更正确的方式替换它, 比如:
32> NewT = T#xmlel{body = NewBody}
如果那确实是一条记录,那么它的定义必须在 ejabberd
代码中某处可用的 Erlang .hrl
文件之一中,您可以将其包含在代码中并使用。如果该记录的定义发生变化,您只能重新编译您的代码,它应该仍然有效。使用 setelement
存在这样的风险,即如果元组的大小发生变化,代码将停止工作,因此请牢记这一点。我将继续使用 setelement
,因为目前这对我来说更简单(记录定义需要使用 rr
导入到 shell,然后才能使用)。
现在剩下三个操作:替换主列表L
中的<<"body">>
元组,然后替换<<"message">>
元组中的L
,最后替换那个元组在主结构中:
35> NewL = lists:keyreplace(<<"body">>, 2, L, NewT).
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]
41> NewXmlel = setelement(4, Xmlel, NewL).
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]}
42> NewM = setelement(3, M, NewXmlel).
{{jid,<<"test25">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test25">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{jid,<<"test24">>,<<"localhost">>,
<<"Administrators-MacBook-Pro-6">>,<<"test24">>,
<<"localhost">>,<<"Administrators-MacBook-Pro-6">>},
{xmlel,<<"message">>,
[{<<"type">>,<<"chat">>},
{<<"id">>,<<"purpleaed2ec77">>},
{<<"to">>,
<<"test24@localhost/Administrators-MacBook-Pro-6">>}],
[{xmlel,<<"active">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],
[]},
{xmlel,<<"body">>,[],
[{xmlcdata,<<"MESSAGE BODY GOES *****">>}]}]}}
现在 NewM
包含与 M
相同的消息,但根据需要替换了正文。
这相当长,因为为了清楚起见,我分别对每个步骤进行了编码。实际上,在您的代码中使用它时,您将能够缩短这些步骤,特别是如果您可以包含并使用适当的记录定义。