Current section

Files

Jump to
floki lib floki.ex
Raw

lib/floki.ex

defmodule Floki do
def parse(html) do
:mochiweb_html.parse(html)
end
def find(html, selector) when is_binary(html) do
parse(html)
|> find(selector)
end
def find(html_tree, "." <> class) do
find_by_selector(class, html_tree, &class_matcher/3, [])
|> Enum.reverse
end
def find(html_tree, "#" <> id) do
find_by_selector(id, html_tree, &id_matcher/3, [])
|> List.first
end
def find(html_tree, tag_name) do
find_by_selector(tag_name, html_tree, &tag_matcher/3, [])
|> Enum.reverse
end
def attribute(html, selector, attribute_name) do
html
|> find(selector)
|> get_attribute_values(attribute_name)
end
def attribute(elements, attribute_name) do
elements
|> get_attribute_values(attribute_name)
end
defp class_match?(attributes, class) do
attribute_match?(attributes, "class", class)
end
defp attribute_match?(attributes, attribute_name, value) do
Enum.find(attributes, fn(attribute) ->
{ attr_name, attr_value } = attribute
attr_name == attribute_name && String.contains?(attr_value, value)
end)
end
defp find_by_selector(_selector, {}, _, acc), do: acc
defp find_by_selector(_selector, [], _, acc), do: acc
defp find_by_selector(_selector, tree, _, acc) when is_binary(tree), do: acc
defp find_by_selector(selector, [h|t], matcher, acc) do
acc = find_by_selector(selector, h, matcher, acc)
find_by_selector(selector, t, matcher, acc)
end
defp find_by_selector(_selector, { :comment, _comment }, _, acc), do: acc
defp find_by_selector(selector, node, matcher, acc) when is_tuple(node) do
{ _, _, child_node } = node
acc = matcher.(selector, node, acc)
find_by_selector(selector, child_node, matcher, acc)
end
defp get_attribute_values(elements, attr_name) do
Enum.map(elements, fn(el) ->
{ _name, attributes, _childs } = el
attribute_match?(attributes, attr_name, "")
end)
|> Enum.reject(fn(x) -> is_nil(x) end)
|> Enum.map(fn({_attr_name, value}) -> value end)
end
defp class_matcher(selector, node, acc) do
{ _, attributes, _ } = node
if class_match?(attributes, selector) do
acc = [node|acc]
end
acc
end
defp tag_matcher(tag_name, node, acc) do
{ tag, _, _ } = node
if tag == tag_name do
acc = [node|acc]
end
acc
end
defp id_matcher(id, node, acc) do
{ _, attributes, _ } = node
if attribute_match?(attributes, "id", id) do
acc = [node|acc]
end
acc
end
end