Skip to content

Commit

Permalink
Add 'use_maps' option to fxml_stream.parse_element/2.
Browse files Browse the repository at this point in the history
  • Loading branch information
slezakattack committed Aug 8, 2024
1 parent a26d40b commit abbfda0
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 14 deletions.
19 changes: 18 additions & 1 deletion c_src/fxml_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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) {
Expand Down Expand Up @@ -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}
Expand Down
8 changes: 7 additions & 1 deletion src/fxml_stream.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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]).

Expand Down Expand Up @@ -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).
27 changes: 15 additions & 12 deletions test/elixir/fast_xml_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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("<root></root>", [: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, "<root>")
assert receive_stanza == %FastXML.StreamStart{name: "root"}
s3 = :fxml_stream.parse(s2, "<xmlelement>content cdata</xmlelement>")
assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]}
s4 = :fxml_stream.parse(s3, "<xmlelement><empty/><subelement attribute='true'>content cdata</subelement></xmlelement>")
assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]}
s5 = :fxml_stream.parse(s4, "</root>")
assert receive_stanza == %FastXML.StreamEnd{name: "root"}
:fxml_stream.close(s5)
:fxml_stream.new(self(), :infinity, [:no_gen_server, :use_maps])
|> :fxml_stream.parse("<root>")
|> :fxml_stream.parse("<xmlelement>content cdata</xmlelement>")
|> :fxml_stream.parse("<xmlelement><empty/><subelement attribute='true'>content cdata</subelement></xmlelement>")
|> :fxml_stream.parse("</root>")
|> :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
Expand All @@ -49,7 +52,7 @@ defmodule FastXMLTest do

# TODO test mismatched tags

defp receive_stanza do
defp receive_stanza() do
receive do
result ->
result
Expand Down
3 changes: 3 additions & 0 deletions test/fxml_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ tag_with_tags_test() ->
{xmlcdata, <<"cdata2">>}]},
fxml_stream:parse_element(<<"<root><a/>cdata1<b/>cdata2</root>">>)).

use_maps_test() ->
?assertEqual(#{'__struct__' => 'Elixir.FastXML.El', name => <<"root">>, attrs => #{}, children => []}, fxml_stream:parse_element(<<"<root></root>">>, [use_maps])).

receiver(Acc) ->
receive
{'$gen_event', Msg} ->
Expand Down

0 comments on commit abbfda0

Please sign in to comment.