Packages
floki
0.32.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
4
files changed
+57
additions
-71
deletions
| @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. | |
| 7 7 | |
| 8 8 | ## [Unreleased][unreleased] |
| 9 9 | |
| 10 | + ## [0.32.1] - 2022-03-24 |
| 11 | + |
| 12 | + ### Fixed |
| 13 | + |
| 14 | + - Allow root nodes to be selected using pseudo-classes - thanks [@rzane](https://github.com/rzane) |
| 15 | + |
| 10 16 | ## [0.32.0] - 2021-10-18 |
| 11 17 | |
| 12 18 | ### Added |
| @@ -590,7 +596,8 @@ of the parent element inside HTML. | |
| 590 596 | |
| 591 597 | - Elixir version requirement from "~> 1.0.0" to ">= 1.0.0". |
| 592 598 | |
| 593 | - [unreleased]: https://github.com/philss/floki/compare/v0.32.0...HEAD |
| 599 | + [unreleased]: https://github.com/philss/floki/compare/v0.32.1...HEAD |
| 600 | + [0.32.1]: https://github.com/philss/floki/compare/v0.32.0...v0.32.1 |
| 594 601 | [0.32.0]: https://github.com/philss/floki/compare/v0.31.0...v0.32.0 |
| 595 602 | [0.31.0]: https://github.com/philss/floki/compare/v0.30.1...v0.31.0 |
| 596 603 | [0.30.1]: https://github.com/philss/floki/compare/v0.30.0...v0.30.1 |
| @@ -4,27 +4,28 @@ | |
| 4 4 | <<"Floki is a simple HTML parser that enables search for nodes using CSS selectors.">>}. |
| 5 5 | {<<"elixir">>,<<"~> 1.8">>}. |
| 6 6 | {<<"files">>, |
| 7 | - [<<"lib/floki">>,<<"lib/floki/entities.ex">>,<<"lib/floki/html_parser.ex">>, |
| 8 | - <<"lib/floki/html">>,<<"lib/floki/html/numeric_charref.ex">>, |
| 9 | - <<"lib/floki/html/tokenizer.ex">>,<<"lib/floki/html_parser">>, |
| 7 | + [<<"lib/floki">>,<<"lib/floki/deep_text.ex">>,<<"lib/floki/entities.ex">>, |
| 8 | + <<"lib/floki/filter_out.ex">>,<<"lib/floki/finder.ex">>, |
| 9 | + <<"lib/floki/flat_text.ex">>,<<"lib/floki/html">>, |
| 10 | + <<"lib/floki/html/numeric_charref.ex">>,<<"lib/floki/html/tokenizer.ex">>, |
| 11 | + <<"lib/floki/html_parser.ex">>,<<"lib/floki/html_parser">>, |
| 10 12 | <<"lib/floki/html_parser/fast_html.ex">>, |
| 11 | - <<"lib/floki/html_parser/mochiweb.ex">>, |
| 12 | - <<"lib/floki/html_parser/html5ever.ex">>,<<"lib/floki/selector">>, |
| 13 | - <<"lib/floki/selector/functional.ex">>,<<"lib/floki/selector/parser.ex">>, |
| 13 | + <<"lib/floki/html_parser/html5ever.ex">>, |
| 14 | + <<"lib/floki/html_parser/mochiweb.ex">>,<<"lib/floki/html_tree.ex">>, |
| 15 | + <<"lib/floki/html_tree">>,<<"lib/floki/html_tree/comment.ex">>, |
| 16 | + <<"lib/floki/html_tree/html_node.ex">>, |
| 17 | + <<"lib/floki/html_tree/id_seeder.ex">>,<<"lib/floki/html_tree/text.ex">>, |
| 18 | + <<"lib/floki/parse_error.ex">>,<<"lib/floki/raw_html.ex">>, |
| 19 | + <<"lib/floki/selector.ex">>,<<"lib/floki/selector">>, |
| 14 20 | <<"lib/floki/selector/attribute_selector.ex">>, |
| 15 | - <<"lib/floki/selector/pseudo_class.ex">>, |
| 21 | + <<"lib/floki/selector/combinator.ex">>, |
| 22 | + <<"lib/floki/selector/functional.ex">>,<<"lib/floki/selector/parser.ex">>, |
| 16 23 | <<"lib/floki/selector/tokenizer.ex">>, |
| 17 | - <<"lib/floki/selector/combinator.ex">>,<<"lib/floki/deep_text.ex">>, |
| 18 | - <<"lib/floki/filter_out.ex">>,<<"lib/floki/flat_text.ex">>, |
| 19 | - <<"lib/floki/finder.ex">>,<<"lib/floki/traversal.ex">>, |
| 20 | - <<"lib/floki/raw_html.ex">>,<<"lib/floki/parse_error.ex">>, |
| 21 | - <<"lib/floki/html_tree">>,<<"lib/floki/html_tree/id_seeder.ex">>, |
| 22 | - <<"lib/floki/html_tree/comment.ex">>,<<"lib/floki/html_tree/text.ex">>, |
| 23 | - <<"lib/floki/html_tree/html_node.ex">>,<<"lib/floki/selector.ex">>, |
| 24 | - <<"lib/floki/html_tree.ex">>,<<"lib/floki.ex">>, |
| 25 | - <<"src/floki_selector_lexer.xrl">>,<<"src/floki_mochi_html.erl">>, |
| 26 | - <<"src/floki.gleam">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>, |
| 27 | - <<"CODE_OF_CONDUCT.md">>,<<"CONTRIBUTING.md">>,<<"CHANGELOG.md">>]}. |
| 24 | + <<"lib/floki/selector/pseudo_class.ex">>,<<"lib/floki/traversal.ex">>, |
| 25 | + <<"lib/floki.ex">>,<<"src/floki_selector_lexer.xrl">>, |
| 26 | + <<"src/floki_mochi_html.erl">>,<<"src/floki.gleam">>,<<"mix.exs">>, |
| 27 | + <<"README.md">>,<<"LICENSE">>,<<"CODE_OF_CONDUCT.md">>, |
| 28 | + <<"CONTRIBUTING.md">>,<<"CHANGELOG.md">>]}. |
| 28 29 | {<<"licenses">>,[<<"MIT">>]}. |
| 29 30 | {<<"links">>, |
| 30 31 | [{<<"Changelog">>,<<"https://hexdocs.pm/floki/changelog.html">>}, |
| @@ -38,4 +39,4 @@ | |
| 38 39 | {<<"optional">>,false}, |
| 39 40 | {<<"repository">>,<<"hexpm">>}, |
| 40 41 | {<<"requirement">>,<<"~> 0.5.0">>}]]}. |
| 41 | - {<<"version">>,<<"0.32.0">>}. |
| 42 | + {<<"version">>,<<"0.32.1">>}. |
| @@ -28,54 +28,36 @@ defmodule Floki.Selector.PseudoClass do | |
| 28 28 | end |
| 29 29 | end |
| 30 30 | |
| 31 | - def match_nth_child?(_tree, %HTMLNode{parent_node_id: nil}, _pseudo_class), do: false |
| 32 | - |
| 33 31 | def match_nth_child?(tree, html_node, %__MODULE__{value: value}) do |
| 34 | - relative_position = |
| 35 | - tree |
| 36 | - |> children_nodes(html_node.parent_node_id) |
| 37 | - |> Enum.with_index(1) |
| 38 | - |> node_position(html_node) |
| 39 | - |
| 40 | - match_position?(value, relative_position, "nth-child") |
| 32 | + tree |
| 33 | + |> pseudo_nodes(html_node) |
| 34 | + |> Enum.reverse() |
| 35 | + |> node_position(html_node) |
| 36 | + |> match_position?(value, "nth-child") |
| 41 37 | end |
| 42 38 | |
| 43 | - def match_nth_of_type?(_, %HTMLNode{parent_node_id: nil}, _), do: false |
| 44 | - |
| 45 39 | def match_nth_of_type?(tree, html_node, %__MODULE__{value: value}) do |
| 46 | - relative_position = |
| 47 | - tree |
| 48 | - |> children_nodes(html_node.parent_node_id) |
| 49 | - |> filter_nodes_by_type(tree.nodes, html_node.type) |
| 50 | - |> Enum.with_index(1) |
| 51 | - |> node_position(html_node) |
| 52 | - |
| 53 | - match_position?(value, relative_position, "nth-of-type") |
| 40 | + tree |
| 41 | + |> pseudo_nodes(html_node) |
| 42 | + |> filter_nodes_by_type(tree.nodes, html_node.type) |
| 43 | + |> Enum.reverse() |
| 44 | + |> node_position(html_node) |
| 45 | + |> match_position?(value, "nth-of-type") |
| 54 46 | end |
| 55 47 | |
| 56 | - def match_nth_last_child?(_, %HTMLNode{parent_node_id: nil}, _), do: false |
| 57 | - |
| 58 48 | def match_nth_last_child?(tree, html_node, %__MODULE__{value: value}) do |
| 59 | - relative_position = |
| 60 | - tree |
| 61 | - |> reverse_children_nodes(html_node.parent_node_id) |
| 62 | - |> Enum.with_index(1) |
| 63 | - |> node_position(html_node) |
| 64 | - |
| 65 | - match_position?(value, relative_position, "nth-last-child") |
| 49 | + tree |
| 50 | + |> pseudo_nodes(html_node) |
| 51 | + |> node_position(html_node) |
| 52 | + |> match_position?(value, "nth-last-child") |
| 66 53 | end |
| 67 54 | |
| 68 | - def match_nth_last_of_type?(_, %HTMLNode{parent_node_id: nil}, _), do: false |
| 69 | - |
| 70 55 | def match_nth_last_of_type?(tree, html_node, %__MODULE__{value: value}) do |
| 71 | - relative_position = |
| 72 | - tree |
| 73 | - |> reverse_children_nodes(html_node.parent_node_id) |
| 74 | - |> filter_nodes_by_type(tree.nodes, html_node.type) |
| 75 | - |> Enum.with_index(1) |
| 76 | - |> node_position(html_node) |
| 77 | - |
| 78 | - match_position?(value, relative_position, "nth-last-of-type") |
| 56 | + tree |
| 57 | + |> pseudo_nodes(html_node) |
| 58 | + |> filter_nodes_by_type(tree.nodes, html_node.type) |
| 59 | + |> node_position(html_node) |
| 60 | + |> match_position?(value, "nth-last-of-type") |
| 79 61 | end |
| 80 62 | |
| 81 63 | def match_contains?(tree, html_node, %__MODULE__{value: value}) do |
| @@ -90,7 +72,7 @@ defmodule Floki.Selector.PseudoClass do | |
| 90 72 | res != nil |
| 91 73 | end |
| 92 74 | |
| 93 | - defp match_position?(value, relative_position, name) do |
| 75 | + defp match_position?(relative_position, value, name) do |
| 94 76 | case value do |
| 95 77 | position when is_integer(position) -> |
| 96 78 | relative_position == position |
| @@ -149,20 +131,16 @@ defmodule Floki.Selector.PseudoClass do | |
| 149 131 | end |
| 150 132 | |
| 151 133 | defp node_position(ids, %HTMLNode{node_id: node_id}) do |
| 152 | - {_node_id, position} = Enum.find(ids, fn {id, _} -> id == node_id end) |
| 153 | - |
| 154 | - position |
| 134 | + position = Enum.find_index(ids, fn id -> id == node_id end) |
| 135 | + position + 1 |
| 155 136 | end |
| 156 137 | |
| 157 | - defp children_nodes(tree, parent_node_id) do |
| 158 | - parent_node = Map.get(tree.nodes, parent_node_id) |
| 159 | - |
| 160 | - parent_node.children_nodes_ids |
| 161 | - |> Enum.reverse() |
| 138 | + defp pseudo_nodes(tree, %HTMLNode{parent_node_id: nil}) do |
| 139 | + tree.root_nodes_ids |
| 162 140 | |> filter_only_html_nodes(tree.nodes) |
| 163 141 | end |
| 164 142 | |
| 165 | - defp reverse_children_nodes(tree, parent_node_id) do |
| 143 | + defp pseudo_nodes(tree, %HTMLNode{parent_node_id: parent_node_id}) do |
| 166 144 | parent_node = Map.get(tree.nodes, parent_node_id) |
| 167 145 | |
| 168 146 | parent_node.children_nodes_ids |
| @@ -3,7 +3,7 @@ defmodule Floki.Mixfile do | |
| 3 3 | |
| 4 4 | @description "Floki is a simple HTML parser that enables search for nodes using CSS selectors." |
| 5 5 | @source_url "https://github.com/philss/floki" |
| 6 | - @version "0.32.0" |
| 6 | + @version "0.32.1" |
| 7 7 | |
| 8 8 | def project do |
| 9 9 | [ |
| @@ -59,8 +59,8 @@ defmodule Floki.Mixfile do | |
| 59 59 | {:html_entities, "~> 0.5.0"}, |
| 60 60 | {:jason, "~> 1.1", only: [:dev, :test, :docs]}, |
| 61 61 | {:earmark, "~> 1.2", only: :dev}, |
| 62 | - {:ex_doc, "~> 0.25.0", only: :dev, runtime: false}, |
| 63 | - {:benchee, "~> 1.0.1", only: :dev}, |
| 62 | + {:ex_doc, "~> 0.28.2", only: :dev, runtime: false}, |
| 63 | + {:benchee, "~> 1.1.0", only: :dev}, |
| 64 64 | {:credo, ">= 0.0.0", only: [:dev, :test]}, |
| 65 65 | {:dialyxir, "~> 1.0", only: [:dev], runtime: false} |
| 66 66 | ] ++ parsers |