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:

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.

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({&#39;channel&#39;, _, _}, _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({&#39;title&#39;, attributes, content}, [{&#39;channel&#39;, _, _} | _], 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({{&#39;dc&#39;, &#39;creator&#39;}, _, content}, [{&#39;channel&#39;, _, _} | _], 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
end

Now start parsing.

FML.parse(the_rss_string_above, _init_state = %{}, MyRSSParser)

%{
  title: "The awesome RSS",
  creator: "Cẩm Huỳnh"
}

Contribute

  1. Fork the repo.
  2. Write the code.
  3. Submit the pull request.