Packages
floki
0.17.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
+26
additions
-17
deletions
| @@ -27,4 +27,4 @@ | |
| 27 27 | {<<"name">>,<<"mochiweb">>}, |
| 28 28 | {<<"optional">>,false}, |
| 29 29 | {<<"requirement">>,<<"~> 2.15">>}]]}. |
| 30 | - {<<"version">>,<<"0.17.0">>}. |
| 30 | + {<<"version">>,<<"0.17.1">>}. |
| @@ -58,12 +58,8 @@ defmodule Floki.Finder do | |
| 58 58 | |
| 59 59 | defp get_selectors(selector_as_string) do |
| 60 60 | selector_as_string |
| 61 | - |> String.split(~r/,(?![^(]*\))/i) |
| 62 | - |> Enum.map(fn(s) -> |
| 63 | - tokens = SelectorTokenizer.tokenize(s) |
| 64 | - |
| 65 | - SelectorParser.parse(tokens) |
| 66 | - end) |
| 61 | + |> SelectorTokenizer.tokenize() |
| 62 | + |> SelectorParser.parse() |
| 67 63 | end |
| 68 64 | |
| 69 65 | defp get_matches_for_selectors(tree, html_node, selectors) do |
| @@ -97,8 +97,10 @@ defmodule Floki.HTMLTree do | |
| 97 97 | defp get_ids_for_delete_stack(_), do: [] |
| 98 98 | |
| 99 99 | defp build_tree(tree, [], _, []), do: tree |
| 100 | + defp build_tree(tree, [{:pi, _, _} | children], parent_id, stack), do: build_tree(tree, children, parent_id, stack) |
| 100 101 | defp build_tree(tree, [{tag, attrs, child_children} | children], parent_id, stack) do |
| 101 102 | new_id = IDSeeder.seed(tree.node_ids) |
| 103 | + |
| 102 104 | new_node = %HTMLNode{type: tag, |
| 103 105 | attributes: attrs, |
| 104 106 | node_id: new_id, |
| @@ -106,7 +108,7 @@ defmodule Floki.HTMLTree do | |
| 106 108 | |
| 107 109 | nodes = put_new_node(tree.nodes, new_node) |
| 108 110 | |
| 109 | - build_tree(%{tree | nodes: nodes, node_ids: [new_id | tree.node_ids]}, |
| 111 | + build_tree(%{tree | nodes: nodes, node_ids: [new_id | tree.node_ids]}, |
| 110 112 | child_children, new_id, [{parent_id, children} | stack]) |
| 111 113 | end |
| 112 114 | defp build_tree(tree, [{:comment, comment} | children], parent_id, stack) do |
| @@ -43,6 +43,7 @@ defmodule Floki.Selector do | |
| 43 43 | |
| 44 44 | defp id_match?(_node, nil), do: true |
| 45 45 | defp id_match?(%HTMLNode{attributes: []}, _), do: false |
| 46 | + defp id_match?(%HTMLNode{type: :pi}, _), do: false |
| 46 47 | defp id_match?(%HTMLNode{attributes: attributes}, id) do |
| 47 48 | Enum.any? attributes, fn(attribute) -> |
| 48 49 | case attribute do |
| @@ -72,6 +73,7 @@ defmodule Floki.Selector do | |
| 72 73 | tp == type |
| 73 74 | [tp] -> |
| 74 75 | tp == type |
| 76 | + _ -> false |
| 75 77 | end |
| 76 78 | end |
| 77 79 | defp type_match?(_, _), do: false |
| @@ -9,18 +9,27 @@ defmodule Floki.SelectorParser do | |
| 9 9 | |
| 10 10 | @attr_match_types [:equal, :dash_match, :includes, :prefix_match, :sufix_match, :substring_match] |
| 11 11 | |
| 12 | - # Returns a `Selector` struct with the parsed selector. |
| 13 | - # Note that this parser does not deal with groups of selectors. |
| 12 | + # Returns a list of `Selector` structs with the parsed selectors. |
| 14 13 | |
| 15 14 | def parse(selector) when is_binary(selector) do |
| 16 15 | token_list = SelectorTokenizer.tokenize(selector) |
| 17 16 | parse(token_list) |
| 18 17 | end |
| 19 18 | def parse(tokens) do |
| 20 | - do_parse(tokens, %Selector{}) |
| 19 | + do_parse_all(tokens, []) |
| 21 20 | end |
| 22 21 | |
| 23 | - defp do_parse([], selector), do: selector |
| 22 | + defp do_parse_all([], selectors) do |
| 23 | + Enum.reverse(selectors) |
| 24 | + end |
| 25 | + |
| 26 | + defp do_parse_all(tokens, selectors) do |
| 27 | + {selector, remaining_tokens} = do_parse(tokens, %Selector{}) |
| 28 | + do_parse_all(remaining_tokens, [selector | selectors]) |
| 29 | + end |
| 30 | + |
| 31 | + defp do_parse([], selector), do: {selector, []} |
| 32 | + defp do_parse([{:comma, _}| t], selector), do: {selector, t} |
| 24 33 | defp do_parse([{:identifier, _, namespace}, {:namespace_pipe, _} | t], selector) do |
| 25 34 | do_parse(t, %{selector | namespace: to_string(namespace)}) |
| 26 35 | end |
| @@ -133,9 +142,9 @@ defmodule Floki.SelectorParser do | |
| 133 142 | end |
| 134 143 | defp consume_combinator([], combinator), do: {[], combinator} |
| 135 144 | defp consume_combinator(tokens, combinator) do |
| 136 | - selector = parse(tokens) |
| 145 | + {selector, remaining_tokens} = do_parse(tokens, %Selector{}) |
| 137 146 | |
| 138 | - {[], %{combinator | selector: selector}} |
| 147 | + {remaining_tokens, %{combinator | selector: selector}} |
| 139 148 | end |
| 140 149 | |
| 141 150 | defp do_parse_pseudo_not([{:close_parentesis, _} | t], pseudo_class) do |
| @@ -159,7 +168,7 @@ defmodule Floki.SelectorParser do | |
| 159 168 | do_parse_pseudo_not(t, pseudo_not_selector, pseudo_class) |
| 160 169 | end |
| 161 170 | defp do_parse_pseudo_not([next_token | t], pseudo_not_selector, pseudo_class) do |
| 162 | - pseudo_not_selector = do_parse([next_token], pseudo_not_selector) |
| 171 | + {pseudo_not_selector, _} = do_parse([next_token], pseudo_not_selector) |
| 163 172 | do_parse_pseudo_not(t, pseudo_not_selector, pseudo_class) |
| 164 173 | end |
Loading more files…