Skip to content

Commit

Permalink
Add :has selector (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jayesh Bhoot committed Jul 24, 2024
1 parent 277e9d9 commit 24f31be
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
9 changes: 9 additions & 0 deletions src/soup.ml
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ struct
| OnlyOfType
| Empty
| Content of string
| Has of simple_selector
| Not of simple_selector

and simple_selector =
Expand Down Expand Up @@ -595,6 +596,11 @@ struct
| OnlyOfType -> element_count_with_name (name node) node = 1
| Empty -> no_children node
| Content s -> texts node |> String.concat "" |> has_substring s
| Has selector ->
descendants node
|> filter (fun descendant -> matches_simple_selector descendant selector)
|> count
|> fun count -> count > 0
| Not selector -> not (matches_simple_selector node selector)

and matches_simple_selector node = function
Expand Down Expand Up @@ -921,6 +927,9 @@ struct
let s = parse_parenthesized_value parse_quoted_string stream in
Content s
| "empty" -> Empty
| "has" ->
let selector = parse_parenthesized_value parse_simple_selector stream in
Has selector
| "not" ->
let selector = parse_parenthesized_value parse_simple_selector stream in
Not selector
Expand Down
20 changes: 18 additions & 2 deletions test/performance/performance.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,24 @@ let () =

let selector = "form[action*=search]" in
assert (soup $ selector |> name = "form");
measure 1000 "select" (fun () -> soup $ selector |> ignore);
measure 1000 ("select " ^ selector) (fun () -> soup $ selector |> ignore);

let selector = ":has([id=mngb])" in
assert (soup $$ selector |> count = 2);
measure 1000 ("select_all " ^ selector)
(fun () -> soup $$ selector |> count |> ignore);

let selector = ":has([action*=search])" in
assert (soup $$ selector |> count = 3);
measure 1000 ("select_all " ^ selector)
(fun () -> soup $$ selector |> count |> ignore);

let selector = ":has([name=gbv])" in
assert (soup $$ selector |> count = 4);
measure 1000 ("select_all " ^ selector)
(fun () -> soup $$ selector |> count |> ignore);

let selector = "*" in
assert (soup $$ selector |> count > 10);
measure 1000 "select_all" (fun () -> soup $$ selector |> count |> ignore)
measure 1000 ("select_all " ^ selector)
(fun () -> soup $$ selector |> count |> ignore)
9 changes: 8 additions & 1 deletion test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ let suites = [
test "p:empty" 1;
test "ul li:not(:nth-child(1))" 2;
test ":not(ul) > li" 2;
test ":has([id=one])" 3;
test "ul:has([id=one])" 1;
test "ol:has([id=one])" 0;
test "li:has([id=one])" 0;
test ":has(.odd)" 4;
test
("html:root > body.lists[class~=lists] > ul > li#one:nth-child(1) " ^
"+ li#two")
Expand Down Expand Up @@ -155,7 +160,9 @@ let suites = [
test "[id=\"\\\"dquotes\\\"\"]" 1;
test "[id=\"simple'quote\"]" 1;
test "[id='simple\\'quote']" 1;
test "[id='back\\slash']" 1);
test "[id='back\\slash']" 1;
test "[id=\"bracket]\"]" 1;
test ":has([id=\"bracket]\"])" 2);

("parse-fail-quoted" >:: fun _ ->
let soup = page "quoted" |> parse in
Expand Down

0 comments on commit 24f31be

Please sign in to comment.