Skip to content

Commit

Permalink
Implement escaping CDATA with a given style
Browse files Browse the repository at this point in the history
  • Loading branch information
NelsonVides committed Dec 17, 2024
1 parent 3e7c9ae commit 6df50a6
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 11 deletions.
22 changes: 19 additions & 3 deletions c_src/exml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,15 @@ bool build_cdata(ErlNifEnv *env, xml_document &doc, const ERL_NIF_TERM elem[],
if (!enif_inspect_iolist_as_binary(env, elem[1], &bin))
return false;

auto child = doc.impl.allocate_node(rapidxml::node_data);
rapidxml::node_type cdata_type;
if (enif_compare(atom_escaped, elem[2]) == 0)
cdata_type = rapidxml::node_data;
else if (enif_compare(atom_cdata, elem[2]) == 0)
cdata_type = rapidxml::node_cdata;
else
return false;

auto child = doc.impl.allocate_node(cdata_type);
child->value(bin.size > 0 ? bin.data : EMPTY, bin.size);
node.append_node(child);
return true;
Expand Down Expand Up @@ -613,7 +621,15 @@ static ERL_NIF_TERM escape_cdata(ErlNifEnv *env, int argc,
if (!enif_inspect_iolist_as_binary(env, argv[0], &bin))
return enif_make_badarg(env);

rapidxml::xml_node<unsigned char> node(rapidxml::node_data);
rapidxml::node_type cdata_type;
if (enif_compare(atom_escaped, argv[1]) == 0)
cdata_type = rapidxml::node_data;
else if (enif_compare(atom_cdata, argv[1]) == 0)
cdata_type = rapidxml::node_cdata;
else
return enif_make_badarg(env);

rapidxml::xml_node<unsigned char> node(cdata_type);
node.value(bin.data, bin.size);
return node_to_binary(env, node, rapidxml::print_no_indenting);
}
Expand Down Expand Up @@ -652,7 +668,7 @@ static ERL_NIF_TERM reset_parser(ErlNifEnv *env, int argc,

static ErlNifFunc nif_funcs[] = {
{"create", 2, create}, {"parse", 1, parse},
{"parse_next", 2, parse_next}, {"escape_cdata", 1, escape_cdata},
{"parse_next", 2, parse_next}, {"escape_cdata", 2, escape_cdata},
{"to_binary", 2, to_binary}, {"reset_parser", 1, reset_parser}};
}

Expand Down
8 changes: 4 additions & 4 deletions src/exml.erl
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ xml_size([]) ->
0;
xml_size([Elem | Rest]) ->
xml_size(Elem) + xml_size(Rest);
xml_size(#xmlcdata{ content = Content }) ->
iolist_size(exml_nif:escape_cdata(Content));
xml_size(#xmlcdata{content = Content, style = Style}) ->
iolist_size(exml_nif:escape_cdata(Content, Style));
xml_size(#xmlel{ name = Name, attrs = Attrs, children = [] }) ->
3 % Self-closing: </>
+ byte_size(Name) + xml_size(Attrs);
Expand Down Expand Up @@ -129,8 +129,8 @@ to_iolist(#xmlstreamstart{name = Name, attrs = Attrs}, _Pretty) ->
[Front, $>];
to_iolist(#xmlstreamend{name = Name}, _Pretty) ->
[<<"</">>, Name, <<">">>];
to_iolist(#xmlcdata{content = Content}, _Pretty) ->
exml_nif:escape_cdata(Content);
to_iolist(#xmlcdata{content = Content, style = Style}, _Pretty) ->
exml_nif:escape_cdata(Content, Style);
to_iolist([Element], Pretty) ->
to_iolist(Element, Pretty);
to_iolist([#xmlstreamstart{name = Name, attrs = Attrs} | Tail] = Elements, Pretty) ->
Expand Down
8 changes: 4 additions & 4 deletions src/exml_nif.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

-module(exml_nif).

-nifs([create/2, escape_cdata/1, to_binary/2, parse/1, parse_next/2, reset_parser/1]).
-nifs([create/2, escape_cdata/2, to_binary/2, parse/1, parse_next/2, reset_parser/1]).

-type parser() :: term().
-type stream_element() :: exml:element() | exml_stream:start() | exml_stream:stop().

-export([create/2, parse/1, parse_next/2, escape_cdata/1,
-export([create/2, parse/1, parse_next/2, escape_cdata/2,
to_binary/2, reset_parser/1]).
-export_type([parser/0, stream_element/0]).

Expand Down Expand Up @@ -44,8 +44,8 @@ load() ->
create(_, _) ->
erlang:nif_error(not_loaded).

-spec escape_cdata(Bin :: iodata()) -> binary().
escape_cdata(_Bin) ->
-spec escape_cdata(Bin :: iodata(), atom()) -> binary().
escape_cdata(_Bin, _Style) ->
erlang:nif_error(not_loaded).

-spec to_binary(Elem :: exml:element(), pretty | not_pretty) -> binary().
Expand Down
6 changes: 6 additions & 0 deletions test/exml_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ size_of_escaped_characters_test() ->
Raw = <<"<a>&amp;</a>">>,
?assertEqual(iolist_size(Raw), exml:xml_size(parse(Raw))).

cdata_size_of_escaped_characters_test() ->
Raw = <<"<a><![CDATA[some stuff]]></a>">>,
CData = #xmlcdata{content = <<"some stuff">>, style = cdata},
Final = #xmlel{name = <<"a">>, children = [CData]},
?assertEqual(iolist_size(Raw), exml:xml_size(Final)).

size_of_exml_with_cdata_test() ->
Raw = <<"<a><![CDATA[ Within this Character Data block I can
use double dashes as much as I want (along with <, &, ', and \")]]></a>">>,
Expand Down

0 comments on commit 6df50a6

Please sign in to comment.