diff --git a/c_src/fxml_stream.c b/c_src/fxml_stream.c index f75e203..e9b5677 100644 --- a/c_src/fxml_stream.c +++ b/c_src/fxml_stream.c @@ -862,10 +862,25 @@ static ERL_NIF_TERM parse_element_nif(ErlNifEnv* env, int argc, { ERL_NIF_TERM el; ErlNifBinary bin; + int use_maps = 0; - if (argc != 1) + if (argc != 1 && argc != 2) return enif_make_badarg(env); + if (argc == 2) { + if (!enif_is_list(env, argv[1])) + return enif_make_badarg(env); + + ERL_NIF_TERM head, tail = argv[1]; + while (enif_get_list_cell(env, tail, &head, &tail)) { + char buf[16]; + if (enif_get_atom(env, head, buf, sizeof(buf), ERL_NIF_LATIN1)) { + if (strcmp("use_maps", buf) == 0) + use_maps = 1; + } + } + } + if (!enif_inspect_binary(env, argv[0], &bin)) return enif_make_badarg(env); @@ -874,6 +889,7 @@ static ERL_NIF_TERM parse_element_nif(ErlNifEnv* env, int argc, return enif_make_badarg(env); state->send_env = env; + state->use_maps = use_maps; xmlel_stack_t *xmlel = enif_alloc(sizeof(xmlel_stack_t)); if (!xmlel) { @@ -1060,6 +1076,7 @@ static ErlNifFunc nif_funcs[] = {"new", 3, new_nif}, {"parse", 2, parse_nif}, {"parse_element", 1, parse_element_nif}, + {"parse_element", 2, parse_element_nif}, {"reset", 1, reset_nif}, {"close", 1, close_nif}, {"change_callback_pid", 2, change_callback_pid_nif} diff --git a/src/fxml_stream.erl b/src/fxml_stream.erl index 23f3b1d..046fb47 100644 --- a/src/fxml_stream.erl +++ b/src/fxml_stream.erl @@ -30,7 +30,7 @@ -on_load(init/0). -export([new/1, new/2, new/3, parse/2, close/1, reset/1, - change_callback_pid/2, parse_element/1]). + change_callback_pid/2, parse_element/1, parse_element/2]). -export([load_nif/0, load_nif/1]). @@ -113,3 +113,9 @@ close(_State) -> parse_element(_Str) -> erlang:nif_error(nif_not_loaded). + +-spec parse_element(binary(), [use_maps]) -> xmlel() | + {error, atom()} | + {error, {integer(), binary()}}. +parse_element(_Str, _Options) -> + erlang:nif_error(nif_not_loaded). diff --git a/test/elixir/fast_xml_test.exs b/test/elixir/fast_xml_test.exs index 6ee1cf8..62081ed 100644 --- a/test/elixir/fast_xml_test.exs +++ b/test/elixir/fast_xml_test.exs @@ -15,19 +15,22 @@ defmodule FastXMLTest do use ExUnit.Case - # TODO: we should be able to pass :use_maps option to :fxml_stream.parse_element/2 + test "Parse element can return Elixir structs" do + assert %FastXML.El{name: "root"} == :fxml_stream.parse_element("", [:use_maps]) + end test "Stream parser can return Elixir structs" do - s1 = :fxml_stream.new(self, :infinity, [:no_gen_server, :use_maps]) - s2 = :fxml_stream.parse(s1, "") - assert receive_stanza == %FastXML.StreamStart{name: "root"} - s3 = :fxml_stream.parse(s2, "content cdata") - assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]} - s4 = :fxml_stream.parse(s3, "content cdata") - assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]} - s5 = :fxml_stream.parse(s4, "") - assert receive_stanza == %FastXML.StreamEnd{name: "root"} - :fxml_stream.close(s5) + :fxml_stream.new(self(), :infinity, [:no_gen_server, :use_maps]) + |> :fxml_stream.parse("") + |> :fxml_stream.parse("content cdata") + |> :fxml_stream.parse("content cdata") + |> :fxml_stream.parse("") + |> :fxml_stream.close() + + assert receive_stanza() == %FastXML.StreamStart{name: "root"} + assert receive_stanza() == %FastXML.El{name: "xmlelement", children: ["content cdata"]} + assert receive_stanza() == %FastXML.El{name: "xmlelement", children: [%FastXML.El{name: "empty"}, %FastXML.El{name: "subelement", attrs: %{"attribute" => "true"}, children: ["content cdata"]}]} + assert receive_stanza() == %FastXML.StreamEnd{name: "root"} end test "Size of parsed stanza can be limited" do @@ -49,7 +52,7 @@ defmodule FastXMLTest do # TODO test mismatched tags - defp receive_stanza do + defp receive_stanza() do receive do result -> result diff --git a/test/fxml_test.erl b/test/fxml_test.erl index b2f3f55..6bbfaff 100644 --- a/test/fxml_test.erl +++ b/test/fxml_test.erl @@ -121,6 +121,9 @@ tag_with_tags_test() -> {xmlcdata, <<"cdata2">>}]}, fxml_stream:parse_element(<<"cdata1cdata2">>)). +use_maps_test() -> + ?assertEqual(#{'__struct__' => 'Elixir.FastXML.El', name => <<"root">>, attrs => #{}, children => []}, fxml_stream:parse_element(<<"">>, [use_maps])). + receiver(Acc) -> receive {'$gen_event', Msg} ->