Skip to content

Instantly share code, notes, and snippets.

@parroty
Created March 14, 2015 02:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save parroty/7f96bc11474e9bab38b2 to your computer and use it in GitHub Desktop.
Save parroty/7f96bc11474e9bab38b2 to your computer and use it in GitHub Desktop.
defmodule XmlParser 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")
@xml """
<result>
<event>
<title>My event</title>
<artist>
<name>Michael Jackson</name>
</artist>
</event>
<event>
<title>My event 2</title>
<artist>
<name>Rolling Stones</name>
</artist>
</event>
</result>
"""
def run do
{doc, _} = @xml |> :binary.bin_to_list |> :xmerl_scan.string
event_elements = :xmerl_xpath.string('//event', doc)
events = Enum.map(event_elements, fn(event_element) ->
parse(xmlElement(event_element, :content))
end)
IO.inspect events
# => [%{artist: %{name: "Michael Jackson"}, title: "My event"},
# %{artist: %{name: "Rolling Stones"}, title: "My event 2"}]
event = List.first(events)
IO.puts event.title
# => My event
IO.puts event.artist.name
# => Michael Jackson
end
def parse(node) do
cond do
Record.is_record(node, :xmlElement) ->
name = xmlElement(node, :name)
content = xmlElement(node, :content)
Map.put(%{}, name, parse(content))
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_map(x) do
Map.merge(acc, x)
else
acc
end
end)
end
true -> "Not supported to parse #{inspect node}"
end
end
end
XmlParser.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment