Current section
Files
Jump to
Current section
Files
lib/xml_to_keyword.ex
defmodule XmlToKeyword do
require Record
Record.defrecord :xmlElement, Record.extract(:xmlElement, from_lib: "xmerl/include/xmerl.hrl")
Record.defrecord :xmlText, Record.extract(:xmlText, from_lib: "xmerl/include/xmerl.hrl")
Record.defrecord :xmlAttribute, Record.extract(:xmlAttribute, from_lib: "xmerl/include/xmerl.hrl")
def convert(xml) do
{doc, _} = xml |> :binary.bin_to_list |> :xmerl_scan.string
[elements] = doc
|> get_root_path
|> :xmerl_xpath.string(doc)
|> Enum.map(fn(element) -> parse(xmlElement(element, :content)) end)
[{get_root_name(doc), elements}]
end
defp parse(node) do
cond do
Record.is_record(node, :xmlElement) ->
name = xmlElement(node, :name)
content = xmlElement(node, :content)
case xmlElement(node, :attributes) do
[] ->
[{name, parse(content)}]
attrs ->
Enum.map(attrs, fn(attr) ->
attr_name = xmlAttribute(attr, :name)
attr_val = xmlAttribute(attr, :value)
[{name, Map.put(%{}, attr_name, attr_val), parse(content) }]
end)
end
Record.is_record(node, :xmlText) ->
xmlText(node, :value) |> to_string
is_list(node) ->
case Enum.map(node, &(parse(&1))) do
[text_content] when is_binary(text_content) ->
text_content
elements ->
Enum.reduce(elements, [], fn(x, acc) ->
if is_list(x) do
acc ++ x
else
acc
end
end)
end
true -> IO.inspect "Error in XmlToKeyword not supported"
end
end
defp get_root_name(doc), do: doc |> xmlElement(:name)
defp get_root_path(doc), do: '//#{get_root_name(doc)}'
end