Skip to content

Commit ef49126

Browse files
committed
Add escape
1 parent b0fa8a0 commit ef49126

File tree

5 files changed

+51
-2
lines changed

5 files changed

+51
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Product.to_struct("<ProductItem><ID>2</ID><Name>Product2</Name></ProductItem>")
3838
## TODO
3939
- [ ] default values
4040
- [ ] value parser callback
41-
- [ ] escape html characters
41+
- [x] escape html characters
4242
- [ ] cdata
4343
- [ ] prefixes
4444
- [ ] override tag name of sub-items in has_many

lib/xml_mapper.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ defmodule XMLMapper do
3333
generate({root_tag(), __MODULE__, []}, xml_content, false, 0)
3434
end
3535
def generate({name, type, opts}, struct, indent) when is_map(struct) and indent == 0 do
36-
generate({name, type, opts}, List.flatten([Map.get(struct, name)]), Code.ensure_loaded?(type), indent + 1)
36+
content = XMLMapper.Value.escape(Map.get(struct, name))
37+
generate({name, type, opts}, List.flatten([content]), Code.ensure_loaded?(type), indent + 1)
3738
end
3839
def generate(_tuple, [nil], is_module, _indent) when is_module == true do
3940
""

lib/xml_mapper/value.ex

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
defmodule XMLMapper.Value do
2+
def escape(string) when is_binary(string) do
3+
string
4+
|> escape(string, 0, 1, [])
5+
|> IO.iodata_to_binary
6+
end
7+
def escape(data), do: data
8+
9+
escapes = [
10+
{?<, "&lt;"},
11+
{?>, "&gt;"},
12+
{?&, "&amp;"},
13+
{?", "&quot;"},
14+
{?', "&apos;"}
15+
]
16+
17+
for {char, swap} <- escapes do
18+
def escape(<<unquote(char), rest::bits>>, string, start, length, acc) do
19+
skipped = binary_part(string, start, length - 1)
20+
escape(rest, string, start + length, 1, [acc, skipped | unquote(swap)])
21+
end
22+
end
23+
24+
def escape(<<_char, rest::bits>>, string, start, length, acc) do
25+
escape(rest, string, start, length + 1, acc)
26+
end
27+
28+
def escape(<<>>, string, start, length, acc) do
29+
[acc | binary_part(string, start, length - 1)]
30+
end
31+
end

test/xml_mapper/escape_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule XMLMapper.EscapeTest do
2+
use ExUnit.Case, async: true
3+
4+
test "escape" do
5+
assert XMLMapper.Value.escape("Lorem & ipsum") == "Lorem &amp; ipsum"
6+
assert XMLMapper.Value.escape("Lorem & <ipsum> 'dolor' \"sit\"") == "Lorem &amp; &lt;ipsum&gt; &apos;dolor&apos; &quot;sit&quot;"
7+
assert XMLMapper.Value.escape(42) == 42
8+
end
9+
end

test/xml_mapper/xml_build_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@ defmodule XmlBuildTest do
1515
assert SimpleTwo.to_xml(%{id: 1, name: "Test"}) == ~s|<?xml version="1.0" encoding="UTF-8"?><SimpleTwo><Id>1</Id><Name>Test</Name></SimpleTwo>|
1616
end
1717

18+
test "Simple struct - escape" do
19+
assert SimpleTwo.to_xml(%{id: 1, name: "Test & test"}) == ~s|<?xml version="1.0" encoding="UTF-8"?><SimpleTwo><Id>1</Id><Name>Test &amp; test</Name></SimpleTwo>|
20+
end
21+
1822
test "Nested struct" do
1923
assert SimpleThree.to_xml(%{id: 1, name: "Test", sub_element: %{id: 2, name: "Sub"}}) == ~s|<?xml version="1.0" encoding="UTF-8"?><SimpleThree><Id>1</Id><Name>Test</Name><SimpleTwo><Id>2</Id><Name>Sub</Name></SimpleTwo></SimpleThree>|
2024
end
2125

26+
test "Nested struct - escape" do
27+
assert SimpleThree.to_xml(%{id: 1, name: "Test", sub_element: %{id: 2, name: "Sub & <sub>"}}) == ~s|<?xml version="1.0" encoding="UTF-8"?><SimpleThree><Id>1</Id><Name>Test</Name><SimpleTwo><Id>2</Id><Name>Sub &amp; &lt;sub&gt;</Name></SimpleTwo></SimpleThree>|
28+
end
29+
2230
test "Renamed tags struct" do
2331
assert SimpleFour.to_xml(%{id: 1, name: "Test"}) == ~s|<?xml version="1.0" encoding="UTF-8"?><SIMPLEFour><ID>1</ID><Name>Test</Name></SIMPLEFour>|
2432
end

0 commit comments

Comments
 (0)