Current section

86 Versions

Jump to

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