defmodule FML do def parse(document, init, mod) do case :erlsom.parse_sax(document, {init, [], mod}, &handle_sax_event(&1, &2)) do {:ok, {state, [], _}, _} -> {:ok, state} error -> {:error, error} end end defp handle_sax_event({:startElement, _, tag_name, prefix, attributes}, {state, stack, mod}) do tag = build_tag(prefix, tag_name, attributes) new_state = mod.on_start_element(tag, stack, state) {new_state, [tag | stack], mod} end defp handle_sax_event({:characters, chars}, {state, stack, mod}) do [{tag_name, attributes, nil} | stack] = stack tag = {tag_name, attributes, to_string(chars)} {state, [tag | stack], mod} end defp handle_sax_event({:endElement, _, _tag_name, _prefix}, {state, stack, mod}) do [tag | stack] = stack new_state = mod.on_end_element(tag, stack, state) {new_state, stack, mod} end defp handle_sax_event(_event, {state, stack, mod}) do {state, stack, mod} end defp build_tag([], tag_name, attributes) do {tag_name, build_attributes(attributes), nil} end defp build_tag(prefix, tag_name, attributes) do {{prefix, tag_name}, build_attributes(attributes), nil} end defp build_attributes(attributes) do Enum.map(attributes, fn {:attribute, name, prefix, _, value} -> {build_attribute_name(prefix, name), to_string(value)} end) end defp build_attribute_name([], name), do: name defp build_attribute_name(prefix, name), do: {prefix, name} end