FML
Flexible, fast, fun XML parser in Elixir, powered by erlsom.
It has nothing to do with my life or your life.
Installation
elixir def deps do [ {:fml, "~> 0.1.0"} ] end
Why FML?
FML is powered by erlsom SAX parser, so it has all the perks that a SAX parser provides:
- Less overhead, no intermediate DOM tree representation created.
- The result after parsing is done is the desired end result.
- Somewhat xpath support, you can trace back to the parents of the element using the parsing stack.
Usage
FML is a wrapper around erlsom SAX parser, so to get started you need to define
a list of events happen during parsing time.
Callbacks to implement.
on_start_element(element, stack, state)on_end_element(element, stack, state)
Element is the current element that being parsed (begin tag or end tag), is a 3-element tuple of tag name, attributes and tag content
Stack is the current elements stack during parsing time, including all the
parents of the current element. For example, if we
are handling bar element ending event in the following XML.
<?xml version="1.0"?>
<rss version="2.0">
<foo>
<bar>The awesome RSS</bar>
</foo>
</rss>
Then the stack will be a list of two element: <foo> and <rss>, note that
element would look like the element specified above.
State is the current state of your result, basically the data you would like to retrieve after done parsing.
Example
Given an RSS file as below
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>The awesome RSS</title>
<dc:creator><![CDATA[Cẩm Huỳnh]]></dc:creator>
</channel>
</rss>Implement all the required callbacks and handle elements that we are interested in.
defmodule MyRSSParser do
@behaviour FML.Parser
def on_start_element({'channel', _, _}, _stack, state) do
Map.put(state, :channel, %{})
end
# Match other element start events and ignore
def on_start_element(_element, _stack, state) do
state
end
# Handle channel/title element
def on_end_element({'title', attributes, content}, [{'channel', _, _} | _], state) do
%{channel: channel} = state
channel = Map.put(channel, :title, content)
Map.put(state, :channel, channel)
end
# Handle channel/dc:creator element
def on_end_element({{'dc', 'creator'}, _, content}, [{'channel', _, _} | _], state) do
%{channel: channel} = state
channel = Map.put(channel, :creator, content)
Map.put(state, :channel, channel)
end
def on_end_element(_element, _stack, state) do
state
end
endNow start parsing.
FML.parse(the_rss_string_above, _init_state = %{}, MyRSSParser)
%{
title: "The awesome RSS",
creator: "Cẩm Huỳnh"
}Contribute
- Fork the repo.
- Write the code.
- Submit the pull request.