Packages
floki
0.0.5
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.1
0.37.0
0.36.3
0.36.2
0.36.1
0.36.0
0.35.4
0.35.3
0.35.2
0.35.1
0.35.0
0.34.3
0.34.2
0.34.1
0.34.0
0.33.1
0.33.0
0.32.1
0.32.0
0.31.0
0.30.1
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.0
0.21.0
0.20.4
0.20.3
0.20.2
0.20.1
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.0
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.0
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Floki is a simple HTML parser that enables search for nodes using CSS selectors.
Current section
86 Versions
Jump to
Current section
86 Versions
Compare versions
4
files changed
+57
additions
-11
deletions
| @@ -3,8 +3,6 @@ Floki | |
| 3 3 | |
| 4 4 | [](https://travis-ci.org/philss/floki) |
| 5 5 | |
| 6 | - A HTML parser and seeker. |
| 7 | - |
| 8 6 | This is a simple HTML parser that enables searching using CSS like selectors. |
| 9 7 | |
| 10 8 | You can search elements by class, tag name and id. |
| @@ -16,6 +14,7 @@ You can search elements by class, tag name and id. | |
| 16 14 | Assuming that you have the following HTML: |
| 17 15 | |
| 18 16 | ```html |
| 17 | + <!doctype html> |
| 19 18 | <html> |
| 20 19 | <body> |
| 21 20 | <section id="content"> |
| @@ -94,6 +93,15 @@ Floki.find(html, ".example") | |
| 94 93 | # => ["example"] |
| 95 94 | ``` |
| 96 95 | |
| 96 | + If you want to get the text from an element, try: |
| 97 | + |
| 98 | + ```elixir |
| 99 | + Floki.find(html, ".headline") |
| 100 | + |> Floki.text |
| 101 | + |
| 102 | + # => "Floki" |
| 103 | + ``` |
| 104 | + |
| 97 105 | ## License |
| 98 106 | |
| 99 107 | Floki is under MIT license. Check the `LICENSE` file for more details. |
| @@ -3,7 +3,7 @@ | |
| 3 3 | {<<"contributors">>,[<<"Philip Sampaio Silva">>]}. |
| 4 4 | {<<"description">>, |
| 5 5 | <<"A HTML parser and seeker.\n\nYou can search inside HTML documents using CSS like selectors.\n">>}. |
| 6 | - {<<"elixir">>,<<"~> 1.0.0">>}. |
| 6 | + {<<"elixir">>,<<">= 1.0.0">>}. |
| 7 7 | {<<"files">>, |
| 8 8 | [<<"lib/floki.ex">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>, |
| 9 9 | <<"src/mochinum.erl">>,<<"src/mochiutf8.erl">>, |
| @@ -14,4 +14,4 @@ | |
| 14 14 | <<"GitHub">> => <<"https://github.com/philss/floki">>}}. |
| 15 15 | {<<"name">>,<<"floki">>}. |
| 16 16 | {<<"requirements">>,#{}}. |
| 17 | - {<<"version">>,<<"0.0.4">>}. |
| 17 | + {<<"version">>,<<"0.0.5">>}. |
| @@ -71,7 +71,7 @@ defmodule Floki do | |
| 71 71 | It is possible to compose searches: |
| 72 72 | |
| 73 73 | Floki.find(html_string, ".class") |
| 74 | - |> Floki.find(".another-class-inside-small-scope" |
| 74 | + |> Floki.find(".another-class-inside-small-scope") |
| 75 75 | |
| 76 76 | ## Examples |
| 77 77 | |
| @@ -144,17 +144,48 @@ defmodule Floki do | |
| 144 144 | end |
| 145 145 | |
| 146 146 | |
| 147 | + @doc """ |
| 148 | + Returns the text nodes from a html tree. |
| 149 | + |
| 150 | + ## Examples |
| 151 | + |
| 152 | + iex> Floki.text("<div><span>something else</span>hello world</div>") |
| 153 | + "hello world" |
| 154 | + |
| 155 | + """ |
| 156 | + |
| 157 | + @spec text(html_tree | binary) :: binary |
| 158 | + |
| 159 | + def text(html) when is_binary(html), do: parse(html) |> text |
| 160 | + def text(element) when is_tuple(element), do: text(element, "") |
| 161 | + def text(elements) do |
| 162 | + Enum.reduce elements, "", fn(element, str) -> |
| 163 | + text(element, str) |
| 164 | + end |
| 165 | + end |
| 166 | + |
| 167 | + defp text({_, _, children}, acc) do |
| 168 | + Enum.reduce children, acc, fn(child, istr) -> |
| 169 | + if is_binary(child) do |
| 170 | + (istr <> "\s" <> child) |> String.strip |
| 171 | + else |
| 172 | + istr |
| 173 | + end |
| 174 | + end |
| 175 | + end |
| 176 | + |
| 177 | + |
| 147 178 | defp attribute_match?(attributes, attribute_name) do |
| 148 | - attributes |> Enum.find(fn({attr_name, _}) -> |
| 179 | + Enum.find(attributes, fn({ attr_name, _ }) -> |
| 149 180 | attr_name == attribute_name |
| 150 181 | end) |
| 151 182 | end |
| 152 183 | |
| 153 | - defp attribute_match?(attributes, attribute_name, value) do |
| 184 | + defp attribute_match?(attributes, attribute_name, selector_value) do |
| 154 185 | Enum.find(attributes, fn(attribute) -> |
| 155 186 | { attr_name, attr_value } = attribute |
| 156 187 | |
| 157 | - attr_name == attribute_name && String.contains?(attr_value, value) |
| 188 | + attr_name == attribute_name && value_match?(attr_value, selector_value) |
| 158 189 | end) |
| 159 190 | end |
| 160 191 | |
| @@ -165,6 +196,7 @@ defmodule Floki do | |
| 165 196 | acc = find_by_selector(selector, h, matcher, acc) |
| 166 197 | find_by_selector(selector, t, matcher, acc) |
| 167 198 | end |
| 199 | + # Ignores comments |
| 168 200 | defp find_by_selector(_selector, { :comment, _comment }, _, acc), do: acc |
| 169 201 | defp find_by_selector(selector, node, matcher, acc) when is_tuple(node) do |
| 170 202 | { _, _, child_node } = node |
| @@ -217,4 +249,10 @@ defmodule Floki do | |
| 217 249 | |
| 218 250 | acc |
| 219 251 | end |
| 252 | + |
| 253 | + defp value_match?(attribute_value, selector_value) do |
| 254 | + attribute_value |
| 255 | + |> String.split |
| 256 | + |> Enum.any?(fn(x) -> x == selector_value end) |
| 257 | + end |
| 220 258 | end |
| @@ -3,11 +3,11 @@ defmodule Floki.Mixfile do | |
| 3 3 | |
| 4 4 | def project do |
| 5 5 | [app: :floki, |
| 6 | - version: "0.0.4", |
| 7 | - elixir: "~> 1.0.0", |
| 6 | + version: "0.0.5", |
| 7 | + elixir: ">= 1.0.0", |
| 8 8 | package: package, |
| 9 9 | description: description, |
| 10 | - docs: [readme: true, main: "README"], |
| 10 | + docs: [readme: "README.md"], |
| 11 11 | deps: deps] |
| 12 12 | end |