如何在Erlang中将XML字符串转换为JSON?

bbmckpt7  于 9个月前  发布在  Erlang
关注(0)|答案(2)|浏览(95)

我想把XML字符串解析成erlang列表,然后解析成JSON。
输入示例:

<?xml version="1.0" encoding="UTF-8"?>
<!--some message here-->
<start>
   <data>
      <number id="333">test message</number>
      <data>current date</data>
   </data>
   <mass>
      <client>35</client>
      <address>lattitude</address>
      <code>3454343</code>
      <foo tipo="casa">Some text message 2</foo>
      <product>TEST</product>
   </mass>
</start>

输出应为:

{
  "start": {
    "data": {
      "number": {
        "@id": "333",
        "#text": "test message"
      },
      "data": "current date"
    },
    "mass": {
      "client": "35",
      "address": "lattitude",
      "code": "3454343",
      "foo": {
        "@tipo": "casa",
        "#text": "Some text message 2"
      },
      "product": "TEST"
    }
  }
}

我正在尝试使用erlsom:simple_form(Xml)。
得到:

{ok,{"start",[],
     [{"data",[],
       [{"number",[{"id","333"}],["test message"]},
        {"data",[],["current date"]}]},
      {"mass",[],
       [{"client",[],["35"]},
        {"address",[],["lattitude"]},
        {"code",[],["3454343"]},
        {"foo",[{"tipo","casa"}],["Some text message 2"]},
        {"product",[],["TEST"]}]}]},
    []}

现在我想删除这些空属性。有没有简单的方法可以做到这一点?先谢谢你。
更新:使用Erlang, converting xml to tuples and lists的解决方案使其工作
但让

{"start",
 [{"data",
   [{"number","test message"},{"data","current date"}]},
  {"mass",
   [{"client","35"},
    {"address","lattitude"},
    {"code","3454343"},
    {"foo","Some text message 2"},
    {"product","TEST"}]}]}

没有[{"id","333"}][{"tipo","casa"}]列表。

rwqw0loc

rwqw0loc1#

简单解析的输出是一个集合格式:{Node, Attributes, Children},因此您可以编写一个简单的解析器,将该结构转换为嵌套的proplist。这样,您可以使用mochijsonjsx将proplist转换为JSON字符串。

-module(transform).

-export([test/0]).

test() -> parse(data()).

parse({Node, [], [Value]}) when is_list(Value) ->
    [{Node, Value}];
parse({Node, [], Children}) ->
    V = children_to_struct(Children, []),
    [{Node, V}];
parse({Node, Attributes, Children}) ->
    V = attributes_to_struct(Attributes, []) ++ children_to_struct(Children, []),
    [{Node, V}].

children_to_struct([], Acc) -> Acc;
children_to_struct([Value], Acc) when is_list(Value) ->
    Acc ++ [{"#text", Value}];
children_to_struct([Value | T], Acc) when is_tuple(Value) ->
    children_to_struct(T, Acc ++ parse(Value)).

attributes_to_struct([], Acc) -> Acc;
attributes_to_struct([{K, V}|T], Acc) ->
    attributes_to_struct(T, Acc ++ [{"@" ++ K, V}]).

data() ->
    {"start",[],
     [{"data",[],
       [{"number",[{"id","333"}],["test message"]},
        {"data",[],["current date"]}]},
      {"mass",[],
       [{"client",[],["35"]},
        {"address",[],["lattitude"]},
        {"code",[],["3454343"]},
        {"foo",[{"tipo","casa"}],["Some text message 2"]},
        {"product",[],["TEST"]}]}]}.

使用mochijson在shell中运行它:

Eshell V7.3  (abort with ^G)
1> c(transform).
{ok,transform}
2> T = transform:test().
[{"start",
  [{"data",
    [{"number",[{"@id","333"},{"#text","test message"}]},
     {"data","current date"}]},
   {"mass",
    [{"client","35"},
     {"address","lattitude"},
     {"code","3454343"},
     {"foo",[{"@tipo","casa"},{"#text","Some text message 2"}]},
     {"product","TEST"}]}]}]
3> 
4> iolist_to_binary(mochijson2:encode(T)).
<<"{\"start\":{\"data\":{\"number\":{\"@id\":[51,51,51],\"#text\":[116,101,115,116,32,109,101,115,115,97,103,101]},\"data\":{\"#text"...>>
b1uwtaje

b1uwtaje2#

我建议对JSON使用jiffy,对XML使用exmljiffyexml有本地代码,这意味着它们非常快。
克隆并编译它们。
在编译它们之前,您应该安装g++libexpat-dev
范例:

-module(test).
-export([convert/1]).
-include("exml/include/exml.hrl"). %% In my test



convert(XML) when erlang:is_binary(XML) ->
    {ok, XMLEl} = exml:parse(XML),
    jiffy:encode({[convert2(XMLEl)]}).



convert2(#xmlel{name = Name
              ,attrs = []
              ,children = [{xmlcdata, Data}]}) ->
    {Name, Data};
convert2(#xmlel{name = Name
              ,attrs = Attrs
              ,children = Children}) ->
    {Name,  {convert_attrs(Attrs) ++ convert_children(Children)}}.



convert_attrs(Attrs) ->
    convert_attrs(Attrs,[]).

convert_attrs([Attr|Attrs1], Attrs2) ->
    convert_attrs(Attrs1, [convert_attr(Attr)|Attrs2]);
convert_attrs([], Attrs2) ->
    lists:reverse(Attrs2).



convert_attr({Attr, Value}) ->
    {<<$@, Attr/binary>>, Value}.



convert_children(Children) ->
    convert_children(Children, []).

convert_children([Child|Children1], Children2) ->
    convert_children(Children1, [convert_child(Child)|Children2]);
convert_children([], Children2) ->
    lists:reverse(Children2).



convert_child({xmlcdata, Data}) ->
    {<<"#text">>, Data};
convert_child(#xmlel{}=XMLEl) ->
    convert2(XMLEl).

在shell中:

p@jahanbakhsh ~/Projects/test $ ls
exml                      jiffy                   test.erl

p@jahanbakhsh ~/Projects/test $ erl -pa jiffy/ebin exml/ebin
Erlang/OTP 19 [erts-8.2.2] [source-1ca84a4] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.2.2  (abort with ^G)
1> c(test).
{ok,test}
2> XML = <<"<start><data><number id=\"333\">test message</number><data>current date</data></data><mass><client>35</client><address>lattitude</address><code>3454343</code><foo tipo=\"casa\">Some text message 2</foo><product>TEST</product></mass></start>">>.
<<"<start><data><number id=\"333\">test message</number><data>current date</data></data><mass><client>35</client><address"...>>

3> test:convert(XML).
<<"{\"start\":{\"data\":{\"number\":{\"@id\":\"333\",\"#text\":\"test message\"},\"data\":\"current date\"},\"mass\":{\"client\":\"35\",\"addres"...>>

4> io:format("~s~n", [test:convert(XML)]).
{"start":{"data":{"number":{"@id":"333","#text":"test message"},"data":"current date"},"mass":{"client":"35","address":"lattitude","code":"3454343","foo":{"@tipo":"casa","#text":"Some text message 2"},"product":"TEST"}}}
ok
5>

相关问题