Packages

Fiết is a feed parser in Elixir, which aims to provide extensibility, speed, and standard compliance to feed parsing.

Current section

Files

Jump to
fiet lib fiet.ex
Raw

lib/fiet.ex

defmodule Fiet do
@moduledoc """
Fiet is a feed parser which aims to provide extensibility, speed, and standard
compliance.
Currently Fiet supports [RSS 2.0](cyber.harvard.edu/rss/rss.html) and [Atom](https://tools.ietf.org/html/rfc4287).
## Feed format detecting
There are two main functions in this module: `parse/1` and `parse!/1`, which
provide detecting parsing. That means that it will detect the format of the
XML document input then parse and map it into `Fiet.Feed`, which is the
unified format of all the feed formats supported by Fiet.
Please note that detecting logic works by checking the root tag of the XML
document, it does not mean to validate the XML document.
## Detecting overhead
If you know exactly the feed format of the XML document you are going to parse,
you are recommended to use `Fiet.Atom` or `Fiet.RSS2` to avoid overhead. That
will give you the full data parsed from the feed document.
"""
alias Fiet.{
Atom,
RSS2
}
@doc """
Parse RSS document into a feed.
## Example
rss = File.read!("/path/to/rss")
{:ok, %Fiet.Feed{} = feed} = Fiet.parse(rss)
"""
@spec parse(data :: binary) :: {:ok, feed :: Fiet.Feed.t()} | {:error, reason :: any}
def parse(data) when is_binary(data) do
case detect_format(data) do
:atom -> parse_atom(data)
:rss2 -> parse_rss2(data)
:error -> {:error, "input data format is not supported"}
end
end
@doc """
Same as `parse/1`, but this will raise when error happen.
## Example
rss = File.read!("/path/to/rss")
%Fiet.Feed{} = Fiet.parse(rss)
"""
@spec parse!(data :: binary) :: Fiet.Feed.t()
def parse!(data) do
case parse(data) do
{:ok, feed} ->
feed
{:error, %module{} = error} when module in [RSS2.Engine.ParsingError, Atom.ParsingError] ->
raise(error)
{:error, message} ->
raise RuntimeError, message
end
end
defp parse_rss2(data) do
case RSS2.parse(data) do
{:ok, %RSS2.Channel{} = channel} ->
{:ok, Fiet.Feed.new(channel)}
{:error, _reason} = error ->
error
end
end
defp parse_atom(data) do
case Atom.parse(data) do
{:ok, %Atom.Feed{} = feed} ->
{:ok, Fiet.Feed.new(feed)}
{:error, _reason} = error ->
error
end
end
defp detect_format(data) do
Fiet.StackParser.parse(data, [], fn
:start_element, {"feed", _, _}, [], _ ->
{:stop, :atom}
:start_element, {"rss", _, _}, [], _ ->
{:stop, :rss2}
:start_element, _other, [], _ ->
{:stop, false}
end)
|> case do
{:ok, false} -> :error
{:ok, type} -> type
end
end
end