Packages
floki
0.23.1
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
7
files changed
+77
additions
-28
deletions
| @@ -2,7 +2,7 @@ | |
| 2 2 | [](https://hex.pm/packages/floki) |
| 3 3 | [](https://hex.pm/packages/floki) |
| 4 4 | [](https://inch-ci.org/github/philss/floki) |
| 5 | - [](https://ebertapp.io/github/philss/floki) |
| 5 | + [](https://app.sourcelevel.io/github/philss/floki) |
| 6 6 | |
| 7 7 | <img src="assets/images/floki-logo-with-type.svg" width="500" alt="Floki logo"> |
| @@ -4,23 +4,23 @@ | |
| 4 4 | <<"Floki is a simple HTML parser that enables search for nodes using CSS selectors.">>}. |
| 5 5 | {<<"elixir">>,<<"~> 1.5">>}. |
| 6 6 | {<<"files">>, |
| 7 | - [<<"lib">>,<<"lib/floki">>,<<"lib/floki/html_parser.ex">>, |
| 8 | - <<"lib/floki/html_parser">>,<<"lib/floki/html_parser/mochiweb.ex">>, |
| 9 | - <<"lib/floki/html_parser/html5ever.ex">>,<<"lib/floki/selector">>, |
| 10 | - <<"lib/floki/selector/functional.ex">>,<<"lib/floki/selector/parser.ex">>, |
| 7 | + [<<"lib">>,<<"lib/floki">>,<<"lib/floki/html_parser">>, |
| 8 | + <<"lib/floki/html_parser/html5ever.ex">>, |
| 9 | + <<"lib/floki/html_parser/mochiweb.ex">>,<<"lib/floki/traversal.ex">>, |
| 10 | + <<"lib/floki/raw_html.ex">>,<<"lib/floki/selector.ex">>, |
| 11 | + <<"lib/floki/selector">>,<<"lib/floki/selector/combinator.ex">>, |
| 11 12 | <<"lib/floki/selector/attribute_selector.ex">>, |
| 12 | - <<"lib/floki/selector/pseudo_class.ex">>, |
| 13 | - <<"lib/floki/selector/tokenizer.ex">>, |
| 14 | - <<"lib/floki/selector/combinator.ex">>,<<"lib/floki/deep_text.ex">>, |
| 15 | - <<"lib/floki/filter_out.ex">>,<<"lib/floki/flat_text.ex">>, |
| 16 | - <<"lib/floki/finder.ex">>,<<"lib/floki/traversal.ex">>, |
| 17 | - <<"lib/floki/raw_html.ex">>,<<"lib/floki/html_tree">>, |
| 13 | + <<"lib/floki/selector/tokenizer.ex">>,<<"lib/floki/selector/parser.ex">>, |
| 14 | + <<"lib/floki/selector/functional.ex">>, |
| 15 | + <<"lib/floki/selector/pseudo_class.ex">>,<<"lib/floki/html_tree">>, |
| 18 16 | <<"lib/floki/html_tree/id_seeder.ex">>,<<"lib/floki/html_tree/comment.ex">>, |
| 19 | - <<"lib/floki/html_tree/text.ex">>,<<"lib/floki/html_tree/html_node.ex">>, |
| 20 | - <<"lib/floki/selector.ex">>,<<"lib/floki/html_tree.ex">>,<<"lib/floki.ex">>, |
| 21 | - <<"src/floki_selector_lexer.xrl">>,<<"src/floki_mochi_html.erl">>, |
| 22 | - <<"mix.exs">>,<<"README.md">>,<<"LICENSE">>,<<"CODE_OF_CONDUCT.md">>, |
| 23 | - <<"CONTRIBUTING.md">>]}. |
| 17 | + <<"lib/floki/html_tree/html_node.ex">>,<<"lib/floki/html_tree/text.ex">>, |
| 18 | + <<"lib/floki/finder.ex">>,<<"lib/floki/filter_out.ex">>, |
| 19 | + <<"lib/floki/html_tree.ex">>,<<"lib/floki/html_parser.ex">>, |
| 20 | + <<"lib/floki/deep_text.ex">>,<<"lib/floki/flat_text.ex">>, |
| 21 | + <<"lib/floki.ex">>,<<"src/floki_selector_lexer.xrl">>, |
| 22 | + <<"src/floki_mochi_html.erl">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>, |
| 23 | + <<"CODE_OF_CONDUCT.md">>,<<"CONTRIBUTING.md">>]}. |
| 24 24 | {<<"licenses">>,[<<"MIT">>]}. |
| 25 25 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/philss/floki">>}]}. |
| 26 26 | {<<"name">>,<<"floki">>}. |
| @@ -29,5 +29,5 @@ | |
| 29 29 | {<<"name">>,<<"html_entities">>}, |
| 30 30 | {<<"optional">>,false}, |
| 31 31 | {<<"repository">>,<<"hexpm">>}, |
| 32 | - {<<"requirement">>,<<"~> 0.4.0">>}]]}. |
| 33 | - {<<"version">>,<<"0.23.0">>}. |
| 32 | + {<<"requirement">>,<<"~> 0.5.0">>}]]}. |
| 33 | + {<<"version">>,<<"0.23.1">>}. |
| @@ -302,6 +302,37 @@ defmodule Floki do | |
| 302 302 | end |
| 303 303 | end |
| 304 304 | |
| 305 | + @doc """ |
| 306 | + Returns the direct child nodes of a HTML tree. |
| 307 | + |
| 308 | + By default, it will also include all texts. You can disable this behaviour |
| 309 | + by using the option `include_text` to `false` |
| 310 | + |
| 311 | + ## Examples |
| 312 | + |
| 313 | + iex> Floki.children({"div", [], ["text", {"span", [], []}]}) |
| 314 | + ["text", {"span", [], []}] |
| 315 | + |
| 316 | + iex> Floki.children({"div", [], ["text", {"span", [], []}]}, include_text: false) |
| 317 | + [{"span", [], []}] |
| 318 | + |
| 319 | + """ |
| 320 | + |
| 321 | + @spec children(html_tree, Keyword.t()) :: html_tree |
| 322 | + |
| 323 | + def children(html, opts \\ [include_text: true]) do |
| 324 | + case html do |
| 325 | + {_, _, subtree} -> |
| 326 | + filter_children(subtree, opts[:include_text]) |
| 327 | + |
| 328 | + _ -> |
| 329 | + nil |
| 330 | + end |
| 331 | + end |
| 332 | + |
| 333 | + defp filter_children(children, false), do: Enum.filter(children, &is_tuple(&1)) |
| 334 | + defp filter_children(children, _), do: children |
| 335 | + |
| 305 336 | @doc """ |
| 306 337 | Returns a list with attribute values for a given selector. |
| @@ -34,6 +34,7 @@ defmodule Floki.RawHTML do | |
| 34 34 | end |
| 35 35 | |
| 36 36 | defp build_raw_html([], html, _encoder), do: html |
| 37 | + |
| 37 38 | defp build_raw_html(string, _html, encoder) when is_binary(string), do: encoder.(string) |
| 38 39 | |
| 39 40 | defp build_raw_html(tuple, html, encoder) when is_tuple(tuple), |
| @@ -88,11 +89,7 @@ defmodule Floki.RawHTML do | |
| 88 89 | end |
| 89 90 | |
| 90 91 | defp build_attrs({attr, <<value::binary>>}, attrs) do |
| 91 | - if String.contains?(value, "\"") do |
| 92 | - ~s(#{attrs} #{attr}='#{value}') |
| 93 | - else |
| 94 | - ~s(#{attrs} #{attr}="#{value}") |
| 95 | - end |
| 92 | + "#{attrs} #{attr}=\"#{html_escape_attribute_value(value)}\"" |
| 96 93 | end |
| 97 94 | |
| 98 95 | defp build_attrs(<<attr::binary>>, attrs), do: "#{attrs} #{attr}" |
| @@ -116,4 +113,20 @@ defmodule Floki.RawHTML do | |
| 116 113 | & &1 |
| 117 114 | end |
| 118 115 | end |
| 116 | + |
| 117 | + # html_escape |
| 118 | + |
| 119 | + def html_escape_attribute_value(attribute_value) do |
| 120 | + html_escape_chars(attribute_value, ~r/&|"/) |
| 121 | + end |
| 122 | + |
| 123 | + defp html_escape_chars(subject, escaped_chars_regex) do |
| 124 | + Regex.replace(escaped_chars_regex, subject, &html_escape_char/1) |
| 125 | + end |
| 126 | + |
| 127 | + defp html_escape_char("<"), do: "<" |
| 128 | + defp html_escape_char(">"), do: ">" |
| 129 | + defp html_escape_char("&"), do: "&" |
| 130 | + defp html_escape_char("\""), do: """ |
| 131 | + defp html_escape_char("'"), do: "'" |
| 119 132 | end |
| @@ -38,7 +38,7 @@ defmodule Floki.Selector.AttributeSelector do | |
| 38 38 | def match?(attributes, s = %AttributeSelector{match_type: :includes}) do |
| 39 39 | value = get_value(s.attribute, attributes) |
| 40 40 | |
| 41 | - whitespace_values = String.split(value, " ") |
| 41 | + whitespace_values = String.split(value, ~r/\s+/) |
| 42 42 | |
| 43 43 | Enum.any?(whitespace_values, fn v -> v == s.value end) |
| 44 44 | end |
Loading more files…