如何在 Erlang 中将 XML 转换为元组列表?

发布于 2024-09-15 04:11:35 字数 1737 浏览 2 评论 0原文

我正在尝试从 XML 创建键、值对元组。我想从任何嵌套的 XML 中列出一个列表。这似乎是一个很常见的事情,但我找不到任何例子。

例如:

    <something>
        <Item>
            <name>The Name!</name>
            <reviews>
                    <review>
                        <review-by>WE</review-by>
                        <review-points>92</review-points>
                    </review>
        
                    <review>
                        <review-by>WS</review-by>
                        <review-points>90</review-points>
                    </review>
            </reviews>
        </Item>
    </something>

应该是这样的:

    [[{"name", "The Name!"}, {"reviews", [{"review-by", "WE"}, {"review-points", 92}], {"review-by", "WS"}, {"review-points", 90}]} ]]

其中每个 Item 都是主包装器节点。

诚然,我对货物崇拜并调整了下面的代码。它仅返回第一个 Item 的元素的列表。我不知道如何开始嵌套的。

    -module(reader).
    -compile(export_all).
    -include_lib("xmerl/include/xmerl.hrl").

    parse(FileName) ->
        {Records,_} = xmerl_scan:file(FileName),
        extract(Records, []).
    
    extract(Record, Acc) when is_record(Record, xmlElement) ->
        case Record#xmlElement.name of
            'Item' ->
                ItemData = lists:foldl(fun extract/2, [], Record#xmlElement.content),
                [ {item, ItemData} | Acc ];
            _ ->
                lists:foldl(fun extract/2, Acc, Record#xmlElement.content)
        end;

    extract({xmlText, [{Attribute, _}, {'Item', 2}, _], _, _, Value, text}, Acc) ->
        [{Attribute, Value}|Acc];
    
    extract(_, Acc) ->
        Acc.

I'm trying to create key, value pair tuples out of XML. I'd like to make a list out of any nested XML. It seems like a very common thing to do, but I can't find any examples.

For instance:

    <something>
        <Item>
            <name>The Name!</name>
            <reviews>
                    <review>
                        <review-by>WE</review-by>
                        <review-points>92</review-points>
                    </review>
        
                    <review>
                        <review-by>WS</review-by>
                        <review-points>90</review-points>
                    </review>
            </reviews>
        </Item>
    </something>

Should turn out like:

    [[{"name", "The Name!"}, {"reviews", [{"review-by", "WE"}, {"review-points", 92}], {"review-by", "WS"}, {"review-points", 90}]} ]]

Where each Item is the main wrapper node.

I've admittedly cargo culted and tweaked the code below. It only returns a list of the first Item's elements. And I'm not sure how to begin the nested ones.

    -module(reader).
    -compile(export_all).
    -include_lib("xmerl/include/xmerl.hrl").

    parse(FileName) ->
        {Records,_} = xmerl_scan:file(FileName),
        extract(Records, []).
    
    extract(Record, Acc) when is_record(Record, xmlElement) ->
        case Record#xmlElement.name of
            'Item' ->
                ItemData = lists:foldl(fun extract/2, [], Record#xmlElement.content),
                [ {item, ItemData} | Acc ];
            _ ->
                lists:foldl(fun extract/2, Acc, Record#xmlElement.content)
        end;

    extract({xmlText, [{Attribute, _}, {'Item', 2}, _], _, _, Value, text}, Acc) ->
        [{Attribute, Value}|Acc];
    
    extract(_, Acc) ->
        Acc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一袭白衣梦中忆 2024-09-22 04:11:35

尝试一下Erlsom。函数“erlsom:simple_form(XML)”将为您提供 {Node,Attrib,Value}:

  {"something",[],
 [{"Item",[],
   [{"name",[],["The Name!"]},
    {"reviews",[],
     [{"review",[],
       [{"review-by",[],["WE"]},{"review-points",[],["92"]}]},
      {"review",[],
       [{"review-by",[],["WS"]},{"review-points",[],["90"]}]}]}]}]}

但是,如果您想删除属性,那么您可以编写一个 fun 来传递给 erlsom SAX 解析器或重新格式化 simple_form 的输出。像这样的东西(重新格式化输出):

-module(reader).
-compile(export_all).

convert(XML)->
    case erlsom:simple_form(XML) of
        {ok,{Node,_Attrib,Value},_}->
            {Node,xml_to_kv(Value)};
        Err->
            Err
    end.


xml_to_kv([{Node,_Attrib,Value}|T])->
    [{Node,lists:flatten(xml_to_kv(Value))}|xml_to_kv(T)];

xml_to_kv(Value)->
    Value.

这将产生以下输出:

 {"something",
 [{"Item",
   [{"name","The Name!"},
    {"reviews",
     [{"review",[{"review-by","WE"},{"review-points","92"}]},
      {"review",[{"review-by","WS"},{"review-points","90"}]}]}]}]}

注意,我还没有在非常大的 XML 文件上测试过这个。您应该运行一些测试并考虑内存问题。

Give Erlsom a try. The Function "erlsom:simple_form(XML)" will give you {Node,Attrib,Value}:

  {"something",[],
 [{"Item",[],
   [{"name",[],["The Name!"]},
    {"reviews",[],
     [{"review",[],
       [{"review-by",[],["WE"]},{"review-points",[],["92"]}]},
      {"review",[],
       [{"review-by",[],["WS"]},{"review-points",[],["90"]}]}]}]}]}

However, if you want to drop the Attributes then you can write a fun to pass to the erlsom SAX parser or reformat the output of simple_form. Something like this (to reformat output):

-module(reader).
-compile(export_all).

convert(XML)->
    case erlsom:simple_form(XML) of
        {ok,{Node,_Attrib,Value},_}->
            {Node,xml_to_kv(Value)};
        Err->
            Err
    end.


xml_to_kv([{Node,_Attrib,Value}|T])->
    [{Node,lists:flatten(xml_to_kv(Value))}|xml_to_kv(T)];

xml_to_kv(Value)->
    Value.

This would produce the following output:

 {"something",
 [{"Item",
   [{"name","The Name!"},
    {"reviews",
     [{"review",[{"review-by","WE"},{"review-points","92"}]},
      {"review",[{"review-by","WS"},{"review-points","90"}]}]}]}]}

Note, I haven't tested this on very large XML files. You should run a few tests and consider mem issues.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文