Skip to content

Commit

Permalink
Stop get_by_id traversal on first match (#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
ypconstante authored May 24, 2024
1 parent 9756307 commit ac18305
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 8 deletions.
7 changes: 1 addition & 6 deletions lib/floki.ex
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,7 @@ defmodule Floki do
"""
@spec get_by_id(html_tree() | html_node(), String.t()) :: html_node() | nil
def get_by_id(html_tree_as_tuple, id)
when is_list(html_tree_as_tuple) or is_html_node(html_tree_as_tuple) do
html_tree_as_tuple
|> Finder.find(%Floki.Selector{id: id})
|> List.first()
end
defdelegate get_by_id(html_tree_as_tuple, id), to: Finder, as: :find_by_id

@doc """
Changes the attribute values of the elements matched by `selector`
Expand Down
22 changes: 22 additions & 0 deletions lib/floki/finder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ defmodule Floki.Finder do
alias Selector.PseudoClass
import Floki, only: [is_html_node: 1]

@spec find_by_id(Floki.html_tree() | Floki.html_node(), String.t()) :: Floki.html_node() | nil
def find_by_id(html_tree_as_tuple, id) do
html_tree_as_tuple = List.wrap(html_tree_as_tuple)
traverse_find_by_id(html_tree_as_tuple, id)
end

defp traverse_find_by_id([{_type, _attributes, children} = html_tuple | rest], id) do
if Selector.id_match?(html_tuple, id) do
html_tuple
else
traverse_find_by_id(children, id) || traverse_find_by_id(rest, id)
end
end

defp traverse_find_by_id([_ | rest], id) do
traverse_find_by_id(rest, id)
end

defp traverse_find_by_id([], _id) do
nil
end

# Find elements inside a HTML tree.
# Second argument can be either a selector string, a selector struct or a list of selector structs.

Expand Down
4 changes: 2 additions & 2 deletions lib/floki/selector.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ defmodule Floki.Selector do

defp can_match_combinator?(_node, _combinator), do: true

defp id_match?(_node, nil), do: true
defp id_match?(node, id), do: attribute_value(node, "id") == id
def id_match?(_node, nil), do: true
def id_match?(node, id), do: attribute_value(node, "id") == id

defp namespace_match?(_node, namespace) when is_wildcard(namespace), do: true

Expand Down

0 comments on commit ac18305

Please sign in to comment.