I have to parse an XML with the following structure:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root >
<node id="1"/>
<node id="2"/>
</root>
And I have tried the following approache based on xpath:
def parse_root(root_xml) do
root_xml
|> xpath(~x"//root",
nodes: ~x"./node"l |> transform_by(&parse_node/1)
)
end
def parse_node(node_xml) do
node_xml
|> xpath(~x"node", id: ~x"@id")
end
test "parse root" do
xml = """
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root >
<node id="1"/>
<node id="2"/>
</root>
"""
assert %{
nodes: [
%{id: "id1"},
%{id: "id2"}
]
} == parse_root(xml)
end
This fails with the following runtime error:
2) test parse root (TestSweet)
test/sweet_test.exs:172
** (ArgumentError) errors were found at the given arguments:
* 1st argument: not a bitstring
code: } == parse_root(xml)
stacktrace:
:erlang.byte_size({:xmlElement, :node, :node, [], {:xmlNamespace, [], []}, [root: 1], 2, [{:xmlAttribute, :id, [], [], [], [node: 2, root: 1], 1, [], ~c"1", false}], [], [], ~c"/Users/ovi/work/eb/playground", :undeclared})
(sweet_xml 0.7.4) lib/sweet_xml.ex:834: SweetXml.split_last_whitespace/1
(sweet_xml 0.7.4) lib/sweet_xml.ex:825: anonymous fn/2 in SweetXml.split_by_whitespace/1
(elixir 1.15.7) lib/stream.ex:990: Stream.do_transform_user/6
(sweet_xml 0.7.4) lib/sweet_xml.ex:788: anonymous fn/4 in SweetXml.continuation_opts/2
(xmerl 1.3.31) xmerl_scan.erl:571: :xmerl_scan.scan_document/2
(xmerl 1.3.31) xmerl_scan.erl:294: :xmerl_scan.string/2
(sweet_xml 0.7.4) lib/sweet_xml.ex:296: SweetXml.do_parse/2
(sweet_xml 0.7.4) lib/sweet_xml.ex:281: SweetXml.parse/2
(sweet_xml 0.7.4) lib/sweet_xml.ex:610: SweetXml.xpath/3
(sweet_xml 0.7.4) lib/sweet_xml.ex:642: SweetXml.xpath/3
(sweet_xml 0.7.4) lib/sweet_xml.ex:737: anonymous fn/3 in SweetXml.xmap/3
(elixir 1.15.7) lib/map.ex:957: Map.get_and_update/3
(sweet_xml 0.7.4) lib/sweet_xml.ex:737: SweetXml.xmap/3
test/sweet_test.exs:187: (test)
I also tried to parse the same XML using xmap as you can see below:
def parse_root2(root_xml) do
root_xml
|> xmap(~x"//root",
nodes: [
~x"./node",
id: ~x"@id"
]
)
end
test "parse root 2" do
xml = """
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root >
<node id="1"/>
<node id="2"/>
</root>
"""
assert %{
nodes: [
%{id: "id1"},
%{id: "id2"}
]
} == parse_root2(xml)
end
…and it fails with the following error:
1) test parse root 2 (TestSweet)
test/sweet_test.exs:200
** (FunctionClauseError) no function clause matching in SweetXml.xmap/3
The following arguments were given to SweetXml.xmap/3:
# 1
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\n<root >\n <node id=\"1\"/>\n <node id=\"2\"/>\n</root>\n"
# 2
%SweetXpath{path: ~c"//root", is_value: true, is_list: false, is_keyword: false, is_optional: false, cast_to: false, transform_fun: &SweetXpath.Priv.self_val/1, namespaces: []}
# 3
[nodes: [%SweetXpath{path: ~c"./node", is_value: true, is_list: false, is_keyword: false, is_optional: false, cast_to: false, transform_fun: &SweetXpath.Priv.self_val/1, namespaces: []}, {:id, %SweetXpath{path: ~c"@id", is_value: true, is_list: false, is_keyword: false, is_optional: false, cast_to: false, transform_fun: &SweetXpath.Priv.self_val/1, namespaces: []}}]]
Attempted function clauses (showing 6 out of 6):
def xmap(nil, _, %{is_optional: true})
def xmap(parent, [], atom) when is_atom(atom)
def xmap(_, [], %{is_keyword: false})
def xmap(_, [], %{is_keyword: true})
def xmap(parent, [{label, spec} | tail], is_keyword) when is_list(spec)
def xmap(parent, [{label, sweet_xpath} | tail], is_keyword)
code: } == parse_root2(xml)
stacktrace:
(sweet_xml 0.7.4) lib/sweet_xml.ex:721: SweetXml.xmap/3
test/sweet_test.exs:215: (test)
Any suggestions will be highly appreciated.
Thanks in advance!






















