Xml in Erlang

-module(xml_example).
-export([main/0]).

-record(plant, {id, name, origin}).

main() ->
    Coffee = #plant{id = 27, name = "Coffee", origin = ["Ethiopia", "Brazil"]},

    % Emit XML representing our plant
    {ok, CoffeeXml} = xmerl:export_simple([to_simple_form(Coffee)], xmerl_xml, [{indent, 2}]),
    io:format("~s~n", [CoffeeXml]),

    % To add a generic XML header to the output, prepend it explicitly
    XmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>~n",
    io:format(XmlHeader ++ CoffeeXml),

    % Parse XML back into a data structure
    {ParsedPlant, _} = xmerl_scan:string(CoffeeXml),
    ParsedRecord = from_simple_form(ParsedPlant),
    io:format("Plant id=~p, name=~p, origin=~p~n", [ParsedRecord#plant.id, ParsedRecord#plant.name, ParsedRecord#plant.origin]),

    Tomato = #plant{id = 81, name = "Tomato", origin = ["Mexico", "California"]},

    % Create a nesting structure
    Nesting = {nesting, [], [
        {parent, [], [
            {child, [], [
                to_simple_form(Coffee),
                to_simple_form(Tomato)
            ]}
        ]}
    ]},

    {ok, NestingXml} = xmerl:export_simple([Nesting], xmerl_xml, [{indent, 2}]),
    io:format("~s~n", [NestingXml]).

to_simple_form(#plant{id = Id, name = Name, origin = Origin}) ->
    {plant, [{id, integer_to_list(Id)}], [
        {name, [], [Name]},
        [{origin, [], [O]} || O <- Origin]
    ]}.

from_simple_form({plant, Attrs, Content}) ->
    Id = list_to_integer(proplists:get_value(id, Attrs)),
    Name = extract_content(name, Content),
    Origin = [extract_content(origin, C) || {origin, _, _} = C <- Content],
    #plant{id = Id, name = Name, origin = Origin}.

extract_content(Tag, Content) ->
    case lists:keyfind(Tag, 1, Content) of
        {Tag, _, [Value]} -> Value;
        _ -> undefined
    end.

This Erlang code demonstrates XML processing using the built-in xmerl library. Here’s a breakdown of the key points:

  1. We define a plant record to represent our data structure.

  2. The to_simple_form/1 function converts our record to a simple form that xmerl can process.

  3. We use xmerl:export_simple/3 to convert our data structure to XML.

  4. To parse XML back into our data structure, we use xmerl_scan:string/1 and then convert the parsed structure back to our record with from_simple_form/1.

  5. We demonstrate nesting by creating a more complex structure with multiple plants.

  6. The extract_content/2 helper function is used to extract content from the parsed XML structure.

To run this program, save it as xml_example.erl and use the Erlang shell:

$ erl
1> c(xml_example).
{ok,xml_example}
2> xml_example:main().

This will output the XML representations and the parsed data structure.

Note that Erlang’s approach to XML processing is quite different from other languages. It uses a simple form representation of XML that consists of tuples and lists. This approach can be more verbose but offers great flexibility in handling XML data.