Current section

Files

Jump to
elixir_feed_parser lib parsers atom.ex
Raw

lib/parsers/atom.ex

defmodule ElixirFeedParser.Parsers.Atom do
import ElixirFeedParser.Parsers.Helper
alias ElixirFeedParser.XmlNode
@date_format "{ISO}"
def can_parse?(xml) do
xml
|> XmlNode.find("/feed")
|> XmlNode.namespace() == "http://www.w3.org/2005/Atom"
end
def parse(xml) do
feed = XmlNode.find(xml, "/feed")
url = feed |> element("link[@type='text/html']", [attr: "href"])
links = feed |> elements("link", [attr: "href"])
feed_url = feed |> element("link[@rel='self']", [attr: "href"])
%{
authors: feed |> elements("author/name"),
title: feed |> element("title"),
id: feed |> element("id"),
# TODO: handle type attr text/html/xhtml correctly
description: feed |> element("subtitle"),
"atom:subtitle": feed |> element("subtitle"),
links: links,
url: parse_feed_url(url, links, feed_url),
hubs: feed |> elements("link[@rel='hub']", [attr: "href"]),
feed_url: feed |> element("link[@rel='self']", [attr: "href"]),
# TODO: add optional scheme and label attributes
categories: feed |> elements("category", [attr: "term"]),
contributors: feed |> elements("contributor/name"),
updated: feed |> element("updated") |> to_date_time(@date_format),
generator: feed |> element("generator", [attr: "uri"]),
icon: feed |> element("icon"),
logo: feed |> element("logo"),
rights: feed |> element("rights"),
entries: parse_entries(feed)
}
end
def parse_entry(_feed, entry) do
links = entry |> elements("link", [attr: "href"])
enclosure = entry |> element("enclosure", [attr: "href"])
media_content = entry |> element("media:content", [attr: "url"])
content_type = entry |> element("content", [attr: "type"])
content = case content_type do
"xhtml" ->
entry |> XmlNode.find("content") |> XmlNode.element_to_string
_other ->
entry |> element("content")
end
%{
authors: entry |> elements("author/name"),
id: entry |> element("id"),
title: entry |> element("title"),
updated: entry |> element("updated") |> to_date_time(@date_format),
published: entry |> element("published") |> to_date_time(@date_format),
# TODO: add optional scheme and label attributes
categories: entry |> elements("category", [attr: "term"]),
contributors: entry |> elements("contributor/name"),
generator: entry |> element("generator", [attr: "uri"]),
rights: entry |> element("rights"),
source: entry |> element("source"),
links: links,
url: feed_entry_url(entry),
image: enclosure || media_content,
summary: entry |> element("summary"),
content: content
}
end
# always take url if provided
# otherwise take last link entry - the feed_url link entry
# if no feed_url link entry, take last link entry
defp parse_feed_url(url, [], nil), do: url
defp parse_feed_url(nil, links, nil), do: List.last(links)
defp parse_feed_url(nil, links, feed_url), do: List.last(links -- [feed_url])
defp parse_feed_url(url, _links, _feed_url), do: url
defp parse_entries(feed) do
XmlNode.map_children(feed, "entry", fn(e) -> parse_entry(feed, e) end)
end
defp feed_entry_url(entry) do
url = entry |> element("link[@type='text/html' and @rel='alternate']", [attr: "href"])
links = entry |> elements("link", [attr: "href"])
if url do url else List.last(links) end
end
end