File Coverage

blib/lib/Mojo/DOM/CSS.pm
Criterion Covered Total %
statement 237 237 100.0
branch 195 202 96.5
condition 92 108 85.1
subroutine 28 28 100.0
pod 3 3 100.0
total 555 578 96.0


line stmt bran cond sub pod time code
1             package Mojo::DOM::CSS;
2 65     65   356 use Mojo::Base -base;
  65         104  
  65         363  
3              
4 65     65   314 use Carp qw(croak);
  65         96  
  65         3256  
5 65     65   288 use Mojo::Util qw(dumper trim);
  65         117  
  65         3991  
6              
7 65   50 65   271 use constant DEBUG => $ENV{MOJO_DOM_CSS_DEBUG} || 0;
  65         96  
  65         297385  
8              
9             has 'tree';
10              
11             my $ESCAPE_RE = qr/\\[^0-9a-fA-F]|\\[0-9a-fA-F]{1,6}/;
12             my $ATTR_RE = qr/
13             \[
14             ((?:$ESCAPE_RE|[\w\-])+) # Key
15             (?:
16             (\W)?= # Operator
17             (?:"((?:\\"|[^"])*)"|'((?:\\'|[^'])*)'|([^\]]+?)) # Value
18             (?:\s+(?:(i|I)|s|S))? # Case-sensitivity
19             )?
20             \]
21             /x;
22              
23             sub matches {
24 51     51 1 103 my $tree = shift->tree;
25 51 100       113 return undef if $tree->[0] ne 'tag';
26 49         83 return _match(_compile(@_), $tree, $tree, _root($tree));
27             }
28              
29 449     449 1 1247 sub select { _select(0, shift->tree, _compile(@_)) }
30 787     787 1 1987 sub select_one { _select(1, shift->tree, _compile(@_)) }
31              
32 48 100   48   70 sub _absolutize { [map { _is_scoped($_) ? $_ : [[['pc', 'scope']], ' ', @$_] } @{shift()}] }
  51         75  
  48         66  
33              
34             sub _all_tags {
35 2339     2339   2716 my $tree = shift;
36              
37 2339         2629 my @tags;
38 2339 100       6249 my @queue = @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
39 2339         3845 while (my $current = shift @queue) {
40 146898 100       199613 next unless $current->[0] eq 'tag';
41 49848         45887 push @tags, $current;
42 49848         80841 unshift @queue, @$current[4 .. $#$current];
43             }
44              
45 2339         5280 return \@tags;
46             }
47              
48             sub _attr {
49 2346     2346   2706 my ($name, $value_re, $current) = @_;
50              
51 2346         2310 my $attrs = $current->[2];
52 2346 100       4841 return undef unless exists $attrs->{$name};
53              
54 837         1040 my $value = $attrs->{$name};
55 837 100 100     1309 return undef if !defined $value && defined $value_re;
56 836 100 100     4201 return 1 if !defined $value_re || $value =~ $value_re;
57              
58 348         804 return undef;
59             }
60              
61             sub _compile {
62 1340     1340   4985 my ($css, %ns) = (trim('' . shift), @_);
63              
64 1340         2901 my $group = [[]];
65 1340         3360 while (my $selectors = $group->[-1]) {
66 4644 100 100     11535 push @$selectors, [] unless @$selectors && ref $selectors->[-1];
67 4644         5141 my $last = $selectors->[-1];
68              
69             # Separator
70 4644 100       31516 if ($css =~ /\G\s*,\s*/gc) { push @$group, [] }
  15 100       35  
    100          
    100          
    100          
    100          
    100          
71              
72             # Combinator
73             elsif ($css =~ /\G\s*([>+~])\s*/gc) {
74 513 100       891 push @$last, ['pc', 'scope'] unless @$last;
75 513         1187 push @$selectors, $1;
76             }
77              
78             # Descendant combinator
79             elsif ($css =~ /\G\s+/gc) {
80 261 50       417 push @$last, ['pc', 'scope'] unless @$last;
81 261         509 push @$selectors, ' ';
82             }
83              
84             # Class or ID
85             elsif ($css =~ /\G([.#])((?:$ESCAPE_RE\s?|[^,.#:[\s>~+])+)/gco) {
86 196 100       635 my ($name, $op) = $1 eq '.' ? ('class', '~') : ('id', '');
87 196         459 push @$last, ['attr', $name, _value($op, $2)];
88             }
89              
90             # Attributes
91 281   100     551 elsif ($css =~ /\G$ATTR_RE/gco) { push @$last, ['attr', _unescape($1), _value($2 // '', $3 // $4 // $5, $6)] }
      100        
      100        
92              
93             # Pseudo-class
94             elsif ($css =~ /\G:([\w\-]+)(?:\(((?:\([^)]+\)|[^)])+)\))?/gcs) {
95 302         1027 my ($name, $args) = (lc $1, $2);
96              
97             # ":text" (raw text)
98 302 100       809 $args = [$args =~ m!^/(.+)/$! ? qr/$1/ : qr/\Q$args\E/i] if $name eq 'text';
    100          
99              
100             # ":is" and ":not" (contains more selectors)
101 302 100 100     1227 $args = _compile($args, %ns) if $name eq 'has' || $name eq 'is' || $name eq 'not';
      100        
102              
103             # ":nth-*" (with An+B notation)
104 302 100       732 $args = _equation($args) if $name =~ /^nth-/;
105              
106             # ":first-*", ":last-*" (rewrite to ":nth-(last-)*")
107 302 100       717 ($name, $args) = ("nth-$+", [0, 1]) if $name =~ /^(?:first-(.+)|(last-.+))$/;
108              
109 302         885 push @$last, ['pc', $name, $args];
110             }
111              
112             # Tag
113             elsif ($css =~ /\G((?:$ESCAPE_RE\s|\\[\s\S]|[^,.#:[\s>~+])+)/gco) {
114 1737 100 100     6028 my $alias = (my $name = $1) =~ s/^([^|]*)\|// && $1 ne '*' ? $1 : undef;
115 1737 100 100     2628 my $ns = length $alias ? $ns{$alias} // return [['invalid']] : $alias;
116 1736 100       3705 push @$last, ['tag', $name eq '*' ? undef : _name($name), _unescape($ns)];
117             }
118              
119 1339 100       3638 else { pos $css < length $css ? croak "Unknown CSS selector: $css" : last }
120             }
121              
122 1337         1471 warn qq{-- CSS Selector ($css)\n@{[dumper $group]}} if DEBUG;
123 1337         3655 return $group;
124             }
125              
126             sub _equation {
127 117 100   117   265 return [0, 0] unless my $equation = shift;
128              
129             # "even"
130 115 100       265 return [2, 0] if $equation =~ /^\s*even\s*$/i;
131              
132             # "odd"
133 106 100       266 return [2, 1] if $equation =~ /^\s*odd\s*$/i;
134              
135             # "4", "+4" or "-4"
136 94 100       478 return [0, $1] if $equation =~ /^\s*((?:\+|-)?\d+)\s*$/;
137              
138             # "n", "4n", "+4n", "-4n", "n+1", "4n-1", "+4n-1" (and other variations)
139 52 100       294 return [0, 0] unless $equation =~ /^\s*((?:\+|-)?(?:\d+)?)?n\s*((?:\+|-)\s*\d+)?\s*$/i;
140 51 100 50     362 return [$1 eq '-' ? -1 : !length $1 ? 1 : $1, join('', split(' ', $2 // 0))];
    100          
141             }
142              
143             sub _evaluate {
144 1256     1256   1959 my ($group, $tree, $scope, $pool) = @_;
145              
146 1256         1515 my (@results, %seen);
147 1256         2695 push @results, grep { !$seen{$_}++ } _evaluate_one($_, $tree, $scope, $pool) for @$group;
  1922         5528  
148              
149 1256         3245 return \@results;
150             }
151              
152             sub _evaluate_one {
153 1267     1267   1790 my ($selector, $tree, $scope, $pool) = @_;
154              
155             # Match the leftmost compound, then propagate forward through combinators
156 1267         1853 my @parts = @$selector;
157 1267         1330 my $compound = shift @parts;
158 1267 100       1957 return () unless ref $compound;
159 1266         1625 my @candidates = grep { _selector($compound, $_, $tree, $scope) } @$pool;
  11449         12533  
160              
161 1266         1957 while (@parts) {
162 780         1050 my $combinator = shift @parts;
163 780         913 my $next = shift @parts;
164 780 50       1197 return () unless ref $next;
165              
166 780         935 my (%seen, @new);
167 780         855 for my $node (@candidates) {
168 1761         2361 for my $cand (_step_forward($combinator, $node)) {
169 41036 100       55395 next if $seen{$cand}++;
170 3387 100       3878 push @new, $cand if _selector($next, $cand, $tree, $scope);
171             }
172             }
173 780         2421 @candidates = @new;
174             }
175              
176 1266         2352 return @candidates;
177             }
178              
179             sub _is_scoped {
180 1384     1384   1478 my $selector = shift;
181              
182 1384 100       1796 for my $pc (grep { $_->[0] eq 'pc' } map { ref $_ ? @$_ : () } @$selector) {
  2604         5007  
  3048         4814  
183              
184             # Selector with ":scope"
185 370 100       832 return 1 if $pc->[1] eq 'scope';
186              
187             # Argument of functional pseudo-class with ":scope"
188 274 100 100     1234 return 1 if ($pc->[1] eq 'has' || $pc->[1] eq 'is' || $pc->[1] eq 'not') && grep { _is_scoped($_) } @{$pc->[2]};
  66   100     108  
  62         97  
189             }
190              
191 1278         2834 return undef;
192             }
193              
194             sub _match {
195 171     171   240 my ($group, $current, $tree, $scope) = @_;
196 171   100     283 _match_one($_, $current, $tree, $scope) and return 1 for @$group;
197 104         342 return undef;
198             }
199              
200             sub _match_one {
201 181     181   199 my ($selector, $current, $tree, $scope) = @_;
202              
203             # Match the rightmost compound, then propagate backward through combinators
204 181         229 my @parts = reverse @$selector;
205 181         203 my $compound = shift @parts;
206 181 100 66     305 return undef unless ref $compound && _selector($compound, $current, $tree, $scope);
207              
208 72         108 my @candidates = ($current);
209 72         119 while (@parts) {
210 12         17 my $combinator = shift @parts;
211 12         15 my $next = shift @parts;
212 12 50       22 return undef unless ref $next;
213              
214 12         13 my (%seen, @new);
215 12         21 for my $node (@candidates) {
216 12         24 for my $cand (_step_back($combinator, $node, $scope)) {
217 15 50       96 next if $seen{$cand}++;
218 15 100       37 push @new, $cand if _selector($next, $cand, $tree, $scope);
219             }
220             }
221 12 100       30 return undef unless @new;
222 7         22 @candidates = @new;
223             }
224              
225 67         334 return 1;
226             }
227              
228 1691     1691   1917 sub _name {qr/(?:^|:)\Q@{[_unescape(shift)]}\E$/}
  1691         3280  
229              
230             sub _namespace {
231 81     81   126 my ($ns, $current) = @_;
232              
233 81 100       166 my $attr = $current->[1] =~ /^([^:]+):/ ? "xmlns:$1" : 'xmlns';
234 81         162 while ($current) {
235 127 100       176 last if $current->[0] eq 'root';
236 123 100       439 return $current->[2]{$attr} eq $ns if exists $current->[2]{$attr};
237              
238 46         67 $current = $current->[3];
239             }
240              
241             # Failing to match yields true if searching for no namespace, false otherwise
242 4         14 return !length $ns;
243             }
244              
245             sub _pc {
246 1976     1976   2539 my ($class, $args, $current, $tree, $scope) = @_;
247              
248             # ":scope" (root can only be a :scope)
249 1976 100       3391 return $current eq $scope if $class eq 'scope';
250 1422 100       1957 return undef if $current->[0] eq 'root';
251              
252             # ":checked"
253 1376 100 100     2119 return exists $current->[2]{checked} || exists $current->[2]{selected} if $class eq 'checked';
254              
255             # ":not"
256 1171 100       1400 return !_match($args, $current, $current, $scope) if $class eq 'not';
257              
258             # ":is"
259 1069 100       1368 return !!_match($args, $current, $current, $scope) if $class eq 'is';
260              
261             # ":has"
262 1049 100       1363 return !!_select(1, $current, $args) if $class eq 'has';
263              
264             # ":empty"
265 1027 100 100     1155 return !grep { !($_->[0] eq 'comment' || $_->[0] eq 'pi') } @$current[4 .. $#$current] if $class eq 'empty';
  83         168  
266              
267             # ":root"
268 987 100 66     1378 return $current->[3] && $current->[3][0] eq 'root' if $class eq 'root';
269              
270             # ":text"
271 933 100 66     1169 return grep { ($_->[0] eq 'text' || $_->[0] eq 'raw') && $_->[1] =~ $args->[0] } @$current[4 .. $#$current]
  257 100       933  
272             if $class eq 'text';
273              
274             # ":any-link", ":link" and ":visited"
275 836 100 100     2090 if ($class eq 'any-link' || $class eq 'link' || $class eq 'visited') {
      100        
276 39 100 66     122 return undef unless $current->[0] eq 'tag' && exists $current->[2]{href};
277 21         23 return !!grep { $current->[1] eq $_ } qw(a area link);
  63         103  
278             }
279              
280             # ":only-child" or ":only-of-type"
281 797 100 100     1618 if ($class eq 'only-child' || $class eq 'only-of-type') {
282 26 100       34 my $type = $class eq 'only-of-type' ? $current->[1] : undef;
283 26   100     26 $_ ne $current and return undef for @{_siblings($current, $type)};
  26         28  
284 6         17 return 1;
285             }
286              
287             # ":nth-child", ":nth-last-child", ":nth-of-type" or ":nth-last-of-type"
288 771 100       977 if (ref $args) {
289 763 100 100     1530 my $type = $class eq 'nth-of-type' || $class eq 'nth-last-of-type' ? $current->[1] : undef;
290 763         681 my @siblings = @{_siblings($current, $type)};
  763         861  
291 763         908 my $index;
292 763         1109 for my $i (0 .. $#siblings) {
293 3204 100       4880 $index = $i, last if $siblings[$i] eq $current;
294             }
295 763 100 100     1467 $index = $#siblings - $index if $class eq 'nth-last-child' || $class eq 'nth-last-of-type';
296 763         667 $index++;
297              
298 763         854 my $delta = $index - $args->[1];
299 763 100       1081 return 1 if $delta == 0;
300 646   100     2497 return $args->[0] != 0 && ($delta < 0) == ($args->[0] < 0) && $delta % $args->[0] == 0;
301             }
302              
303             # Everything else
304 8         16 return undef;
305             }
306              
307             sub _root {
308 97     97   151 my $tree = shift;
309 97         338 $tree = $tree->[3] while $tree->[0] ne 'root';
310 97         153 return $tree;
311             }
312              
313             sub _select {
314 1256     1256   2191 my ($one, $scope, $group) = @_;
315              
316             # Scoped selectors require the whole tree to be searched
317 1256         1410 my $tree = $scope;
318 1256 100       2204 ($group, $tree) = (_absolutize($group), _root($scope)) if grep { _is_scoped($_) } @$group;
  1267         1894  
319              
320             # Pool includes $tree so ":scope" can match it, but results exclude it
321 1256         2061 my $tags = _all_tags($tree);
322 1256         1489 my %match = map { $_ => 1 } @{_evaluate($group, $tree, $scope, [$tree, @$tags])};
  1921         3960  
  1256         2774  
323              
324 1256         2364 my @results;
325 1256         1416 for my $node (@$tags) {
326 7446 100       10533 next unless $match{$node};
327 1776 100       4449 return $node if $one;
328 1054         1418 push @results, $node;
329             }
330              
331 534 100       3254 return $one ? undef : \@results;
332             }
333              
334             sub _selector {
335 15032     15032   16974 my ($selector, $current, $tree, $scope) = @_;
336              
337             # The root might be the scope
338 15032         15267 my $is_tag = $current->[0] eq 'tag';
339 15032         15602 for my $s (@$selector) {
340 16224         14846 my $type = $s->[0];
341              
342             # Tag
343 16224 100 100     34924 if ($is_tag && $type eq 'tag') {
    100 100        
    100          
344 10764 100 100     38273 return undef if defined $s->[1] && $current->[1] !~ $s->[1];
345 3926 100 100     6917 return undef if defined $s->[2] && !_namespace($s->[2], $current);
346             }
347              
348             # Attribute
349 2346 100       2747 elsif ($is_tag && $type eq 'attr') { return undef unless _attr(@$s[1, 2], $current) }
350              
351             # Pseudo-class
352 1976 100       2793 elsif ($type eq 'pc') { return undef unless _pc(@$s[1, 2], $current, $tree, $scope) }
353              
354             # No match
355 1138         2292 else { return undef }
356             }
357              
358 3762         6509 return 1;
359             }
360              
361             sub _siblings {
362 897     897   1056 my ($current, $type) = @_;
363 897         985 my $parent = $current->[3];
364 897 100       1930 my @siblings = grep { $_->[0] eq 'tag' } @$parent[($parent->[0] eq 'root' ? 1 : 4) .. $#$parent];
  13526         15153  
365 897 100       1393 @siblings = grep { $type eq $_->[1] } @siblings if defined $type;
  542         608  
366 897         1364 return \@siblings;
367             }
368              
369             sub _step_back {
370 12     12   19 my ($combinator, $node, $scope) = @_;
371              
372             # " " (ancestors) and ">" (parent only)
373 12 100 66     38 if ($combinator eq ' ' || $combinator eq '>') {
374 8         10 my @ancestors;
375 8   33     33 while ($node ne $scope && $node->[0] ne 'root' && ($node = $node->[3])) {
      33        
376 8         12 push @ancestors, $node;
377 8 50 33     14 last if $combinator eq '>' || $node eq $scope;
378             }
379 8         14 return @ancestors;
380             }
381              
382             # "~" (preceding siblings) and "+" (immediately preceding)
383 4 50       10 return () if $node->[0] eq 'root';
384 4         6 my @prev;
385 4         5 for my $sib (@{_siblings($node)}) {
  4         7  
386 14 100       28 last if $sib eq $node;
387 10         16 push @prev, $sib;
388             }
389 4 100 33     16 return $combinator eq '+' ? ($prev[-1] || ()) : @prev;
390             }
391              
392             sub _step_forward {
393 1761     1761   2403 my ($combinator, $node) = @_;
394              
395             # " " (descendants)
396 1761 100       2445 return @{_all_tags($node)} if $combinator eq ' ';
  1083         1188  
397              
398             # ">" (children only)
399 678 100       1587 return grep { $_->[0] eq 'tag' } @$node[($node->[0] eq 'root' ? 1 : 4) .. $#$node] if $combinator eq '>';
  2263 100       3087  
400              
401             # "~" (following siblings) and "+" (immediately following)
402 104 50       182 return () if $node->[0] eq 'root';
403 104         111 my (@next, $found);
404 104         100 for my $sib (@{_siblings($node)}) {
  104         140  
405 420 100       520 push @next, $sib if $found;
406 420 100       733 $found = 1 if $sib eq $node;
407             }
408 104 100 66     311 return $combinator eq '+' ? ($next[0] || ()) : @next;
409             }
410              
411             sub _unescape {
412 4141 100   4141   10563 return undef unless defined(my $value = shift);
413              
414             # Remove escaped newlines
415 2473         3202 $value =~ s/\\\n//g;
416              
417             # Unescape Unicode characters
418 2473         2736 $value =~ s/\\([0-9a-fA-F]{1,6})\s?/pack 'U', hex $1/ge;
  35         180  
419              
420             # Remove backslash
421 2473         2690 $value =~ s/\\//g;
422              
423 2473         31893 return $value;
424             }
425              
426             sub _value {
427 477     477   1217 my ($op, $value, $insensitive) = @_;
428 477 100       905 return undef unless defined $value;
429 433 100       799 $value = ($insensitive ? '(?i)' : '') . quotemeta _unescape($value);
430              
431             # "~=" (word)
432 433 100       2440 return qr/(?:^|\s+)$value(?:\s+|$)/ if $op eq '~';
433              
434             # "|=" (hyphen-separated)
435 334 100       690 return qr/^$value(?:-|$)/ if $op eq '|';
436              
437             # "*=" (contains)
438 324 100       650 return qr/$value/ if $op eq '*';
439              
440             # "^=" (begins with)
441 312 100       704 return qr/^$value/ if $op eq '^';
442              
443             # "$=" (ends with)
444 280 100       751 return qr/$value$/ if $op eq '$';
445              
446             # Everything else
447 249         3164 return qr/^$value$/;
448             }
449              
450             1;
451              
452             =encoding utf8
453              
454             =head1 NAME
455              
456             Mojo::DOM::CSS - CSS selector engine
457              
458             =head1 SYNOPSIS
459              
460             use Mojo::DOM::CSS;
461              
462             # Select elements from DOM tree
463             my $css = Mojo::DOM::CSS->new(tree => $tree);
464             my $elements = $css->select('h1, h2, h3');
465              
466             =head1 DESCRIPTION
467              
468             L is the CSS selector engine used by L, based on the L
469             Standard|https://html.spec.whatwg.org> and L.
470              
471             =head1 SELECTORS
472              
473             All CSS selectors that make sense for a standalone parser are supported.
474              
475             =head2 *
476              
477             Any element.
478              
479             my $all = $css->select('*');
480              
481             =head2 E
482              
483             An element of type C.
484              
485             my $title = $css->select('title');
486              
487             =head2 E[foo]
488              
489             An C element with a C attribute.
490              
491             my $links = $css->select('a[href]');
492              
493             =head2 E[foo="bar"]
494              
495             An C element whose C attribute value is exactly equal to C.
496              
497             my $case_sensitive = $css->select('input[type="hidden"]');
498             my $case_sensitive = $css->select('input[type=hidden]');
499              
500             =head2 E[foo="bar" i]
501              
502             An C element whose C attribute value is exactly equal to any (ASCII-range) case-permutation of C. Note
503             that this selector is B and might change without warning!
504              
505             my $case_insensitive = $css->select('input[type="hidden" i]');
506             my $case_insensitive = $css->select('input[type=hidden i]');
507             my $case_insensitive = $css->select('input[class~="foo" i]');
508              
509             This selector is part of L, which is still a work in progress.
510              
511             =head2 E[foo="bar" s]
512              
513             An C element whose C attribute value is exactly and case-sensitively equal to C. Note that this selector
514             is B and might change without warning!
515              
516             my $case_sensitive = $css->select('input[type="hidden" s]');
517              
518             This selector is part of L, which is still a work in progress.
519              
520             =head2 E[foo~="bar"]
521              
522             An C element whose C attribute value is a list of whitespace-separated values, one of which is exactly equal to
523             C.
524              
525             my $foo = $css->select('input[class~="foo"]');
526             my $foo = $css->select('input[class~=foo]');
527              
528             =head2 E[foo^="bar"]
529              
530             An C element whose C attribute value begins exactly with the string C.
531              
532             my $begins_with = $css->select('input[name^="f"]');
533             my $begins_with = $css->select('input[name^=f]');
534              
535             =head2 E[foo$="bar"]
536              
537             An C element whose C attribute value ends exactly with the string C.
538              
539             my $ends_with = $css->select('input[name$="o"]');
540             my $ends_with = $css->select('input[name$=o]');
541              
542             =head2 E[foo*="bar"]
543              
544             An C element whose C attribute value contains the substring C.
545              
546             my $contains = $css->select('input[name*="fo"]');
547             my $contains = $css->select('input[name*=fo]');
548              
549             =head2 E[foo|="en"]
550              
551             An C element whose C attribute has a hyphen-separated list of values beginning (from the left) with C.
552              
553             my $english = $css->select('link[hreflang|=en]');
554              
555             =head2 E:root
556              
557             An C element, root of the document.
558              
559             my $root = $css->select(':root');
560              
561             =head2 E:nth-child(n)
562              
563             An C element, the C child of its parent.
564              
565             my $third = $css->select('div:nth-child(3)');
566             my $odd = $css->select('div:nth-child(odd)');
567             my $even = $css->select('div:nth-child(even)');
568             my $top3 = $css->select('div:nth-child(-n+3)');
569              
570             =head2 E:nth-last-child(n)
571              
572             An C element, the C child of its parent, counting from the last one.
573              
574             my $third = $css->select('div:nth-last-child(3)');
575             my $odd = $css->select('div:nth-last-child(odd)');
576             my $even = $css->select('div:nth-last-child(even)');
577             my $bottom3 = $css->select('div:nth-last-child(-n+3)');
578              
579             =head2 E:nth-of-type(n)
580              
581             An C element, the C sibling of its type.
582              
583             my $third = $css->select('div:nth-of-type(3)');
584             my $odd = $css->select('div:nth-of-type(odd)');
585             my $even = $css->select('div:nth-of-type(even)');
586             my $top3 = $css->select('div:nth-of-type(-n+3)');
587              
588             =head2 E:nth-last-of-type(n)
589              
590             An C element, the C sibling of its type, counting from the last one.
591              
592             my $third = $css->select('div:nth-last-of-type(3)');
593             my $odd = $css->select('div:nth-last-of-type(odd)');
594             my $even = $css->select('div:nth-last-of-type(even)');
595             my $bottom3 = $css->select('div:nth-last-of-type(-n+3)');
596              
597             =head2 E:first-child
598              
599             An C element, first child of its parent.
600              
601             my $first = $css->select('div p:first-child');
602              
603             =head2 E:last-child
604              
605             An C element, last child of its parent.
606              
607             my $last = $css->select('div p:last-child');
608              
609             =head2 E:first-of-type
610              
611             An C element, first sibling of its type.
612              
613             my $first = $css->select('div p:first-of-type');
614              
615             =head2 E:last-of-type
616              
617             An C element, last sibling of its type.
618              
619             my $last = $css->select('div p:last-of-type');
620              
621             =head2 E:only-child
622              
623             An C element, only child of its parent.
624              
625             my $lonely = $css->select('div p:only-child');
626              
627             =head2 E:only-of-type
628              
629             An C element, only sibling of its type.
630              
631             my $lonely = $css->select('div p:only-of-type');
632              
633             =head2 E:empty
634              
635             An C element that has no children (including text nodes).
636              
637             my $empty = $css->select(':empty');
638              
639             =head2 E:any-link
640              
641             Alias for L. Note that this selector is B and might change without warning! This selector is
642             part of L, which is still a work in progress.
643              
644             =head2 E:link
645              
646             An C element being the source anchor of a hyperlink of which the target is not yet visited (C<:link>) or already
647             visited (C<:visited>). Note that L is not stateful, therefore C<:any-link>, C<:link> and C<:visited>
648             yield exactly the same results.
649              
650             my $links = $css->select(':any-link');
651             my $links = $css->select(':link');
652             my $links = $css->select(':visited');
653              
654             =head2 E:visited
655              
656             Alias for L.
657              
658             =head2 E:scope
659              
660             An C element being a designated reference element. Note that this selector is B and might change
661             without warning!
662              
663             my $scoped = $css->select('a:not(:scope > a)');
664             my $scoped = $css->select('div :scope p');
665             my $scoped = $css->select('~ p');
666              
667             This selector is part of L, which is still a work in progress.
668              
669             =head2 E:checked
670              
671             A user interface element C which is checked (for instance a radio-button or checkbox).
672              
673             my $input = $css->select(':checked');
674              
675             =head2 E.warning
676              
677             An C element whose class is "warning".
678              
679             my $warning = $css->select('div.warning');
680              
681             =head2 E#myid
682              
683             An C element with C equal to "myid".
684              
685             my $foo = $css->select('div#foo');
686              
687             =head2 E:not(s1, s2)
688              
689             An C element that does not match either compound selector C or compound selector C. Note that support for
690             compound selectors is B and might change without warning!
691              
692             my $others = $css->select('div p:not(:first-child, :last-child)');
693              
694             Support for compound selectors was added as part of L, which is
695             still a work in progress.
696              
697             =head2 E:is(s1, s2)
698              
699             An C element that matches compound selector C and/or compound selector C. Note that this selector is
700             B and might change without warning!
701              
702             my $headers = $css->select(':is(section, article, aside, nav) h1');
703              
704             This selector is part of L, which is still a work in progress.
705              
706             =head2 E:has(rs1, rs2)
707              
708             An C element, if either of the relative selectors C or C, when evaluated with C as the :scope elements,
709             match an element. Note that this selector is B and might change without warning!
710              
711             my $link = $css->select('a:has(> img)');
712              
713             This selector is part of L, which is still a work in progress.
714             Also be aware that this feature is currently marked C, so there is a high chance that it will get removed
715             completely.
716              
717             =head2 E:text(string_or_regex)
718              
719             An C element containing text content that substring matches C case-insensitively or that regex
720             matches C. For regular expressions use the format C<:text(/.../)>. Note that this selector is
721             B and might change without warning!
722              
723             # Substring match
724             my $login = $css->select(':text(Log in)');
725              
726             # Regex match
727             my $login = $css->select(':text(/Log ?in/)');
728              
729             # Regex match (case-insensitive)
730             my $login = $css->select(':text(/(?i:Log ?in)/)');
731              
732             This is a custom selector for L and not part of any spec.
733              
734             =head2 A|E
735              
736             An C element that belongs to the namespace alias C from L
737             3|https://www.w3.org/TR/css-namespaces-3/>. Key/value pairs passed to selector methods are used to declare namespace
738             aliases.
739              
740             my $elem = $css->select('lq|elem', lq => 'http://example.com/q-markup');
741              
742             Using an empty alias searches for an element that belongs to no namespace.
743              
744             my $div = $c->select('|div');
745              
746             =head2 E F
747              
748             An C element descendant of an C element.
749              
750             my $headlines = $css->select('div h1');
751              
752             =head2 E E F
753              
754             An C element child of an C element.
755              
756             my $headlines = $css->select('html > body > div > h1');
757              
758             =head2 E + F
759              
760             An C element immediately preceded by an C element.
761              
762             my $second = $css->select('h1 + h2');
763              
764             =head2 E ~ F
765              
766             An C element preceded by an C element.
767              
768             my $second = $css->select('h1 ~ h2');
769              
770             =head2 E, F, G
771              
772             Elements of type C, C and C.
773              
774             my $headlines = $css->select('h1, h2, h3');
775              
776             =head2 E[foo=bar][bar=baz]
777              
778             An C element whose attributes match all following attribute selectors.
779              
780             my $links = $css->select('a[foo^=b][foo$=ar]');
781              
782             =head1 ATTRIBUTES
783              
784             L implements the following attributes.
785              
786             =head2 tree
787              
788             my $tree = $css->tree;
789             $css = $css->tree(['root']);
790              
791             Document Object Model. Note that this structure should only be used very carefully since it is very dynamic.
792              
793             =head1 METHODS
794              
795             L inherits all methods from L and implements the following new ones.
796              
797             =head2 matches
798              
799             my $bool = $css->matches('head > title');
800             my $bool = $css->matches('svg|line', svg => 'http://www.w3.org/2000/svg');
801              
802             Check if first node in L matches the CSS selector. Trailing key/value pairs can be used to declare xml
803             namespace aliases.
804              
805             =head2 select
806              
807             my $results = $css->select('head > title');
808             my $results = $css->select('svg|line', svg => 'http://www.w3.org/2000/svg');
809              
810             Run CSS selector against L. Trailing key/value pairs can be used to declare xml namespace aliases.
811              
812             =head2 select_one
813              
814             my $result = $css->select_one('head > title');
815             my $result =
816             $css->select_one('svg|line', svg => 'http://www.w3.org/2000/svg');
817              
818             Run CSS selector against L and stop as soon as the first node matched. Trailing key/value pairs can be used to
819             declare xml namespace aliases.
820              
821             =head1 DEBUGGING
822              
823             You can set the C environment variable to get some advanced diagnostics information printed to
824             C.
825              
826             MOJO_DOM_CSS_DEBUG=1
827              
828             =head1 SEE ALSO
829              
830             L, L, L.
831              
832             =cut