File Coverage

blib/lib/Mojo/DOM/CSS.pm
Criterion Covered Total %
statement 182 183 99.4
branch 180 180 100.0
condition 94 99 94.9
subroutine 25 25 100.0
pod 3 3 100.0
total 484 490 98.7


line stmt bran cond sub pod time code
1             package Mojo::DOM::CSS;
2 62     62   495 use Mojo::Base -base;
  62         150  
  62         465  
3              
4 62     62   468 use Carp qw(croak);
  62         150  
  62         3626  
5 62     62   463 use Mojo::Util qw(dumper trim);
  62         174  
  62         5238  
6              
7 62   50 62   463 use constant DEBUG => $ENV{MOJO_DOM_CSS_DEBUG} || 0;
  62         253  
  62         274649  
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 44     44 1 110 my $tree = shift->tree;
25 44 100       160 return $tree->[0] ne 'tag' ? undef : _match(_compile(@_), $tree, $tree, _root($tree));
26             }
27              
28 444     444 1 1266 sub select { _select(0, shift->tree, _compile(@_)) }
29 764     764 1 2112 sub select_one { _select(1, shift->tree, _compile(@_)) }
30              
31 47 100   47   74 sub _absolutize { [map { _is_scoped($_) ? $_ : [[['pc', 'scope']], ' ', @$_] } @{shift()}] }
  50         90  
  47         89  
32              
33             sub _ancestor {
34 1529     1529   2744 my ($selectors, $current, $tree, $scope, $one, $pos) = @_;
35              
36 1529   100     7405 while ($current ne $scope && $current->[0] ne 'root' && ($current = $current->[3])) {
      66        
37 1625 100       3160 return 1 if _combinator($selectors, $current, $tree, $scope, $pos);
38 393 100       1265 return undef if $current eq $scope;
39 269 100       897 last if $one;
40             }
41              
42 173         483 return undef;
43             }
44              
45             sub _attr {
46 1464     1464   2301 my ($name_re, $value_re, $current) = @_;
47              
48 1464         2128 my $attrs = $current->[2];
49 1464         3415 for my $name (keys %$attrs) {
50 1453         2671 my $value = $attrs->{$name};
51 1453 100 100     7970 next if $name !~ $name_re || (!defined $value && defined $value_re);
      100        
52 766 100 100     5926 return 1 if !(defined $value && defined $value_re) || $value =~ $value_re;
      100        
53             }
54              
55 988         4322 return undef;
56             }
57              
58             sub _combinator {
59 9145     9145   15468 my ($selectors, $current, $tree, $scope, $pos) = @_;
60              
61             # Selector
62 9145 100       17816 return undef unless my $c = $selectors->[$pos];
63 9140 100       16768 if (ref $c) {
64 9137 100       14158 return undef unless _selector($c, $current, $tree, $scope);
65 3501 100       13400 return 1 unless $c = $selectors->[++$pos];
66             }
67              
68             # ">" (parent only)
69 1661 100       4280 return _ancestor($selectors, $current, $tree, $scope, 1, ++$pos) if $c eq '>';
70              
71             # "~" (preceding siblings)
72 637 100       1266 return _sibling($selectors, $current, $tree, $scope, 0, ++$pos) if $c eq '~';
73              
74             # "+" (immediately preceding siblings)
75 572 100       1088 return _sibling($selectors, $current, $tree, $scope, 1, ++$pos) if $c eq '+';
76              
77             # " " (ancestor)
78 505         984 return _ancestor($selectors, $current, $tree, $scope, 0, ++$pos);
79             }
80              
81             sub _compile {
82 1306     1306   5709 my ($css, %ns) = (trim('' . shift), @_);
83              
84 1306         3235 my $group = [[]];
85 1306         3241 while (my $selectors = $group->[-1]) {
86 4510 100 100     16855 push @$selectors, [] unless @$selectors && ref $selectors->[-1];
87 4510         6718 my $last = $selectors->[-1];
88              
89             # Separator
90 4510 100       32054 if ($css =~ /\G\s*,\s*/gc) { push @$group, [] }
  14 100       56  
    100          
    100          
    100          
    100          
91              
92             # Combinator
93             elsif ($css =~ /\G\s*([ >+~])\s*/gc) {
94 742 100       1879 push @$last, ['pc', 'scope'] unless @$last;
95 742         2407 push @$selectors, $1;
96             }
97              
98             # Class or ID
99             elsif ($css =~ /\G([.#])((?:$ESCAPE_RE\s|\\.|[^,.#:[ >~+])+)/gco) {
100 188 100       754 my ($name, $op) = $1 eq '.' ? ('class', '~') : ('id', '');
101 188         445 push @$last, ['attr', _name($name), _value($op, $2)];
102             }
103              
104             # Attributes
105 285   100     740 elsif ($css =~ /\G$ATTR_RE/gco) { push @$last, ['attr', _name($1), _value($2 // '', $3 // $4 // $5, $6)] }
      100        
      100        
106              
107             # Pseudo-class
108             elsif ($css =~ /\G:([\w\-]+)(?:\(((?:\([^)]+\)|[^)])+)\))?/gcs) {
109 302         1153 my ($name, $args) = (lc $1, $2);
110              
111             # ":text" (raw text)
112 302 100       981 $args = [$args =~ m!^/(.+)/$! ? qr/$1/ : qr/\Q$args\E/i] if $name eq 'text';
    100          
113              
114             # ":is" and ":not" (contains more selectors)
115 302 100 100     1647 $args = _compile($args, %ns) if $name eq 'has' || $name eq 'is' || $name eq 'not';
      100        
116              
117             # ":nth-*" (with An+B notation)
118 302 100       894 $args = _equation($args) if $name =~ /^nth-/;
119              
120             # ":first-*", ":last-*" (rewrite to ":nth-(last-)*")
121 302 100       833 ($name, $args) = ("nth-$+", [0, 1]) if $name =~ /^(?:first-(.+)|(last-.+))$/;
122              
123 302         1099 push @$last, ['pc', $name, $args];
124             }
125              
126             # Tag
127             elsif ($css =~ /\G((?:$ESCAPE_RE\s|\\.|[^,.#:[ >~+])+)/gco) {
128 1674 100 100     6538 my $alias = (my $name = $1) =~ s/^([^|]*)\|// && $1 ne '*' ? $1 : undef;
129 1674 100 100     3291 my $ns = length $alias ? $ns{$alias} // return [['invalid']] : $alias;
130 1673 100       4311 push @$last, ['tag', $name eq '*' ? undef : _name($name), _unescape($ns)];
131             }
132              
133 1305 100       3833 else { pos $css < length $css ? croak "Unknown CSS selector: $css" : last }
134             }
135              
136 1303         1633 warn qq{-- CSS Selector ($css)\n@{[dumper $group]}} if DEBUG;
137 1303         3944 return $group;
138             }
139              
140             sub _equation {
141 117 100   117   318 return [0, 0] unless my $equation = shift;
142              
143             # "even"
144 115 100       300 return [2, 0] if $equation =~ /^\s*even\s*$/i;
145              
146             # "odd"
147 106 100       269 return [2, 1] if $equation =~ /^\s*odd\s*$/i;
148              
149             # "4", "+4" or "-4"
150 94 100       443 return [0, $1] if $equation =~ /^\s*((?:\+|-)?\d+)\s*$/;
151              
152             # "n", "4n", "+4n", "-4n", "n+1", "4n-1", "+4n-1" (and other variations)
153 52 100       266 return [0, 0] unless $equation =~ /^\s*((?:\+|-)?(?:\d+)?)?n\s*((?:\+|-)\s*\d+)?\s*$/i;
154 51 100 100     403 return [$1 eq '-' ? -1 : !length $1 ? 1 : $1, join('', split(' ', $2 // 0))];
    100          
155             }
156              
157             sub _is_scoped {
158 1364     1364   1920 my $selector = shift;
159              
160 1364 100       2893 for my $pc (grep { $_->[0] eq 'pc' } map { ref $_ ? @$_ : () } @$selector) {
  2556         6644  
  2972         6750  
161              
162             # Selector with ":scope"
163 371 100       1115 return 1 if $pc->[1] eq 'scope';
164              
165             # Argument of functional pseudo-class with ":scope"
166 277 100 100     1468 return 1 if ($pc->[1] eq 'has' || $pc->[1] eq 'is' || $pc->[1] eq 'not') && grep { _is_scoped($_) } @{$pc->[2]};
  69   100     121  
  65         162  
167             }
168              
169 1260         3469 return undef;
170             }
171              
172             sub _match {
173 7252     7252   12196 my ($group, $current, $tree, $scope) = @_;
174 7252   100     18724 _combinator([reverse @$_], $current, $tree, $scope, 0) and return 1 for @$group;
175 5414         16700 return undef;
176             }
177              
178 2123     2123   3104 sub _name {qr/(?:^|:)\Q@{[_unescape(shift)]}\E$/}
  2123         3878  
179              
180             sub _namespace {
181 77     77   149 my ($ns, $current) = @_;
182              
183 77 100       194 my $attr = $current->[1] =~ /^([^:]+):/ ? "xmlns:$1" : 'xmlns';
184 77         150 while ($current) {
185 121 100       230 last if $current->[0] eq 'root';
186 117 100       484 return $current->[2]{$attr} eq $ns if exists $current->[2]{$attr};
187              
188 44         82 $current = $current->[3];
189             }
190              
191             # Failing to match yields true if searching for no namespace, false otherwise
192 4         25 return !length $ns;
193             }
194              
195             sub _pc {
196 1793     1793   3164 my ($class, $args, $current, $tree, $scope) = @_;
197              
198             # ":scope" (root can only be a :scope)
199 1793 100       3716 return $current eq $scope if $class eq 'scope';
200 1671 100       3088 return undef if $current->[0] eq 'root';
201              
202             # ":checked"
203 1666 100 100     3709 return exists $current->[2]{checked} || exists $current->[2]{selected} if $class eq 'checked';
204              
205             # ":not"
206 1462 100       2547 return !_match($args, $current, $current, $scope) if $class eq 'not';
207              
208             # ":is"
209 1283 100       2206 return !!_match($args, $current, $current, $scope) if $class eq 'is';
210              
211             # ":has"
212 1270 100       2332 return !!_select(1, $current, $args) if $class eq 'has';
213              
214             # ":empty"
215 1241 100 100     2238 return !grep { !($_->[0] eq 'comment' || $_->[0] eq 'pi') } @$current[4 .. $#$current] if $class eq 'empty';
  58         211  
216              
217             # ":root"
218 1213 100 66     2553 return $current->[3] && $current->[3][0] eq 'root' if $class eq 'root';
219              
220             # ":text"
221 1159 100 66     2109 return grep { ($_->[0] eq 'text' || $_->[0] eq 'raw') && $_->[1] =~ $args->[0] } @$current[4 .. $#$current]
  232 100       1277  
222             if $class eq 'text';
223              
224             # ":any-link", ":link" and ":visited"
225 1079 100 100     4043 if ($class eq 'any-link' || $class eq 'link' || $class eq 'visited') {
      100        
226 39 100 66     189 return undef unless $current->[0] eq 'tag' && exists $current->[2]{href};
227 21         41 return !!grep { $current->[1] eq $_ } qw(a area link);
  63         162  
228             }
229              
230             # ":only-child" or ":only-of-type"
231 1040 100 100     2978 if ($class eq 'only-child' || $class eq 'only-of-type') {
232 40 100       72 my $type = $class eq 'only-of-type' ? $current->[1] : undef;
233 40   100     53 $_ ne $current and return undef for @{_siblings($current, $type)};
  40         60  
234 7         23 return 1;
235             }
236              
237             # ":nth-child", ":nth-last-child", ":nth-of-type" or ":nth-last-of-type"
238 1000 100       1934 if (ref $args) {
239 992 100 100     2753 my $type = $class eq 'nth-of-type' || $class eq 'nth-last-of-type' ? $current->[1] : undef;
240 992         1281 my @siblings = @{_siblings($current, $type)};
  992         1519  
241 992         1541 my $index;
242 992         1861 for my $i (0 .. $#siblings) {
243 3648 100       8154 $index = $i, last if $siblings[$i] eq $current;
244             }
245 992 100 100     2856 $index = $#siblings - $index if $class eq 'nth-last-child' || $class eq 'nth-last-of-type';
246 992         1317 $index++;
247              
248 992         1460 my $delta = $index - $args->[1];
249 992 100       1980 return 1 if $delta == 0;
250 800   100     5218 return $args->[0] != 0 && ($delta < 0) == ($args->[0] < 0) && $delta % $args->[0] == 0;
251             }
252              
253             # Everything else
254 8         33 return undef;
255             }
256              
257             sub _root {
258 90     90   156 my $tree = shift;
259 90         399 $tree = $tree->[3] while $tree->[0] ne 'root';
260 90         196 return $tree;
261             }
262              
263             sub _select {
264 1235     1235   2489 my ($one, $scope, $group) = @_;
265              
266             # Scoped selectors require the whole tree to be searched
267 1235         2031 my $tree = $scope;
268 1235 100       2254 ($group, $tree) = (_absolutize($group), _root($scope)) if grep { _is_scoped($_) } @$group;
  1245         2282  
269              
270 1235         1854 my @results;
271 1235 100       4840 my @queue = @$tree[($tree->[0] eq 'root' ? 1 : 4) .. $#$tree];
272 1235         3595 while (my $current = shift @queue) {
273 17414 100       40332 next unless $current->[0] eq 'tag';
274              
275 7017         15639 unshift @queue, @$current[4 .. $#$current];
276 7017 100       12551 next unless _match($group, $current, $tree, $scope);
277 1759 100       7097 $one ? return $current : push @results, $current;
278             }
279              
280 530 100       3491 return $one ? undef : \@results;
281             }
282              
283             sub _selector {
284 9137     9137   13899 my ($selector, $current, $tree, $scope) = @_;
285              
286             # The root might be the scope
287 9137         14589 my $is_tag = $current->[0] eq 'tag';
288 9137         14220 for my $s (@$selector) {
289 10381         14865 my $type = $s->[0];
290              
291             # Tag
292 10381 100 100     32534 if ($is_tag && $type eq 'tag') {
    100 100        
    100          
293 7009 100 100     46206 return undef if defined $s->[1] && $current->[1] !~ $s->[1];
294 3551 100 100     9748 return undef if defined $s->[2] && !_namespace($s->[2], $current);
295             }
296              
297             # Attribute
298 1464 100       2669 elsif ($is_tag && $type eq 'attr') { return undef unless _attr(@$s[1, 2], $current) }
299              
300             # Pseudo-class
301 1793 100       3505 elsif ($type eq 'pc') { return undef unless _pc(@$s[1, 2], $current, $tree, $scope) }
302              
303             # No match
304 115         403 else { return undef }
305             }
306              
307 3501         7161 return 1;
308             }
309              
310             sub _sibling {
311 132     132   259 my ($selectors, $current, $tree, $scope, $immediate, $pos) = @_;
312              
313 132         186 my $found;
314 132         182 for my $sibling (@{_siblings($current)}) {
  132         265  
315 326 100       1020 return $found if $sibling eq $current;
316              
317             # "+" (immediately preceding sibling)
318 224 100       380 if ($immediate) { $found = _combinator($selectors, $sibling, $tree, $scope, $pos) }
  125         245  
319              
320             # "~" (preceding sibling)
321 99 100       181 else { return 1 if _combinator($selectors, $sibling, $tree, $scope, $pos) }
322             }
323              
324 0         0 return undef;
325             }
326              
327             sub _siblings {
328 1164     1164   1906 my ($current, $type) = @_;
329              
330 1164         1626 my $parent = $current->[3];
331 1164 100       3471 my @siblings = grep { $_->[0] eq 'tag' } @$parent[($parent->[0] eq 'root' ? 1 : 4) .. $#$parent];
  15442         27276  
332 1164 100       2721 @siblings = grep { $type eq $_->[1] } @siblings if defined $type;
  643         1126  
333              
334 1164         2636 return \@siblings;
335             }
336              
337             sub _unescape {
338 4221 100   4221   14027 return undef unless defined(my $value = shift);
339              
340             # Remove escaped newlines
341 2616         4291 $value =~ s/\\\n//g;
342              
343             # Unescape Unicode characters
344 2616         3582 $value =~ s/\\([0-9a-fA-F]{1,6})\s?/pack 'U', hex $1/ge;
  35         210  
345              
346             # Remove backslash
347 2616         3650 $value =~ s/\\//g;
348              
349 2616         39801 return $value;
350             }
351              
352             sub _value {
353 473     473   1702 my ($op, $value, $insensitive) = @_;
354 473 100       1212 return undef unless defined $value;
355 425 100       884 $value = ($insensitive ? '(?i)' : '') . quotemeta _unescape($value);
356              
357             # "~=" (word)
358 425 100       2352 return qr/(?:^|\s+)$value(?:\s+|$)/ if $op eq '~';
359              
360             # "|=" (hyphen-separated)
361 326 100       769 return qr/^$value(?:-|$)/ if $op eq '|';
362              
363             # "*=" (contains)
364 316 100       834 return qr/$value/ if $op eq '*';
365              
366             # "^=" (begins with)
367 304 100       862 return qr/^$value/ if $op eq '^';
368              
369             # "$=" (ends with)
370 272 100       770 return qr/$value$/ if $op eq '$';
371              
372             # Everything else
373 241         2697 return qr/^$value$/;
374             }
375              
376             1;
377              
378             =encoding utf8
379              
380             =head1 NAME
381              
382             Mojo::DOM::CSS - CSS selector engine
383              
384             =head1 SYNOPSIS
385              
386             use Mojo::DOM::CSS;
387              
388             # Select elements from DOM tree
389             my $css = Mojo::DOM::CSS->new(tree => $tree);
390             my $elements = $css->select('h1, h2, h3');
391              
392             =head1 DESCRIPTION
393              
394             L is the CSS selector engine used by L, based on the L
395             Standard|https://html.spec.whatwg.org> and L.
396              
397             =head1 SELECTORS
398              
399             All CSS selectors that make sense for a standalone parser are supported.
400              
401             =head2 *
402              
403             Any element.
404              
405             my $all = $css->select('*');
406              
407             =head2 E
408              
409             An element of type C.
410              
411             my $title = $css->select('title');
412              
413             =head2 E[foo]
414              
415             An C element with a C attribute.
416              
417             my $links = $css->select('a[href]');
418              
419             =head2 E[foo="bar"]
420              
421             An C element whose C attribute value is exactly equal to C.
422              
423             my $case_sensitive = $css->select('input[type="hidden"]');
424             my $case_sensitive = $css->select('input[type=hidden]');
425              
426             =head2 E[foo="bar" i]
427              
428             An C element whose C attribute value is exactly equal to any (ASCII-range) case-permutation of C. Note
429             that this selector is B and might change without warning!
430              
431             my $case_insensitive = $css->select('input[type="hidden" i]');
432             my $case_insensitive = $css->select('input[type=hidden i]');
433             my $case_insensitive = $css->select('input[class~="foo" i]');
434              
435             This selector is part of L, which is still a work in progress.
436              
437             =head2 E[foo="bar" s]
438              
439             An C element whose C attribute value is exactly and case-sensitively equal to C. Note that this selector
440             is B and might change without warning!
441              
442             my $case_sensitive = $css->select('input[type="hidden" s]');
443              
444             This selector is part of L, which is still a work in progress.
445              
446             =head2 E[foo~="bar"]
447              
448             An C element whose C attribute value is a list of whitespace-separated values, one of which is exactly equal to
449             C.
450              
451             my $foo = $css->select('input[class~="foo"]');
452             my $foo = $css->select('input[class~=foo]');
453              
454             =head2 E[foo^="bar"]
455              
456             An C element whose C attribute value begins exactly with the string C.
457              
458             my $begins_with = $css->select('input[name^="f"]');
459             my $begins_with = $css->select('input[name^=f]');
460              
461             =head2 E[foo$="bar"]
462              
463             An C element whose C attribute value ends exactly with the string C.
464              
465             my $ends_with = $css->select('input[name$="o"]');
466             my $ends_with = $css->select('input[name$=o]');
467              
468             =head2 E[foo*="bar"]
469              
470             An C element whose C attribute value contains the substring C.
471              
472             my $contains = $css->select('input[name*="fo"]');
473             my $contains = $css->select('input[name*=fo]');
474              
475             =head2 E[foo|="en"]
476              
477             An C element whose C attribute has a hyphen-separated list of values beginning (from the left) with C.
478              
479             my $english = $css->select('link[hreflang|=en]');
480              
481             =head2 E:root
482              
483             An C element, root of the document.
484              
485             my $root = $css->select(':root');
486              
487             =head2 E:nth-child(n)
488              
489             An C element, the C child of its parent.
490              
491             my $third = $css->select('div:nth-child(3)');
492             my $odd = $css->select('div:nth-child(odd)');
493             my $even = $css->select('div:nth-child(even)');
494             my $top3 = $css->select('div:nth-child(-n+3)');
495              
496             =head2 E:nth-last-child(n)
497              
498             An C element, the C child of its parent, counting from the last one.
499              
500             my $third = $css->select('div:nth-last-child(3)');
501             my $odd = $css->select('div:nth-last-child(odd)');
502             my $even = $css->select('div:nth-last-child(even)');
503             my $bottom3 = $css->select('div:nth-last-child(-n+3)');
504              
505             =head2 E:nth-of-type(n)
506              
507             An C element, the C sibling of its type.
508              
509             my $third = $css->select('div:nth-of-type(3)');
510             my $odd = $css->select('div:nth-of-type(odd)');
511             my $even = $css->select('div:nth-of-type(even)');
512             my $top3 = $css->select('div:nth-of-type(-n+3)');
513              
514             =head2 E:nth-last-of-type(n)
515              
516             An C element, the C sibling of its type, counting from the last one.
517              
518             my $third = $css->select('div:nth-last-of-type(3)');
519             my $odd = $css->select('div:nth-last-of-type(odd)');
520             my $even = $css->select('div:nth-last-of-type(even)');
521             my $bottom3 = $css->select('div:nth-last-of-type(-n+3)');
522              
523             =head2 E:first-child
524              
525             An C element, first child of its parent.
526              
527             my $first = $css->select('div p:first-child');
528              
529             =head2 E:last-child
530              
531             An C element, last child of its parent.
532              
533             my $last = $css->select('div p:last-child');
534              
535             =head2 E:first-of-type
536              
537             An C element, first sibling of its type.
538              
539             my $first = $css->select('div p:first-of-type');
540              
541             =head2 E:last-of-type
542              
543             An C element, last sibling of its type.
544              
545             my $last = $css->select('div p:last-of-type');
546              
547             =head2 E:only-child
548              
549             An C element, only child of its parent.
550              
551             my $lonely = $css->select('div p:only-child');
552              
553             =head2 E:only-of-type
554              
555             An C element, only sibling of its type.
556              
557             my $lonely = $css->select('div p:only-of-type');
558              
559             =head2 E:empty
560              
561             An C element that has no children (including text nodes).
562              
563             my $empty = $css->select(':empty');
564              
565             =head2 E:any-link
566              
567             Alias for L. Note that this selector is B and might change without warning! This selector is
568             part of L, which is still a work in progress.
569              
570             =head2 E:link
571              
572             An C element being the source anchor of a hyperlink of which the target is not yet visited (C<:link>) or already
573             visited (C<:visited>). Note that L is not stateful, therefore C<:any-link>, C<:link> and C<:visited>
574             yield exactly the same results.
575              
576             my $links = $css->select(':any-link');
577             my $links = $css->select(':link');
578             my $links = $css->select(':visited');
579              
580             =head2 E:visited
581              
582             Alias for L.
583              
584             =head2 E:scope
585              
586             An C element being a designated reference element. Note that this selector is B and might change
587             without warning!
588              
589             my $scoped = $css->select('a:not(:scope > a)');
590             my $scoped = $css->select('div :scope p');
591             my $scoped = $css->select('~ p');
592              
593             This selector is part of L, which is still a work in progress.
594              
595             =head2 E:checked
596              
597             A user interface element C which is checked (for instance a radio-button or checkbox).
598              
599             my $input = $css->select(':checked');
600              
601             =head2 E.warning
602              
603             An C element whose class is "warning".
604              
605             my $warning = $css->select('div.warning');
606              
607             =head2 E#myid
608              
609             An C element with C equal to "myid".
610              
611             my $foo = $css->select('div#foo');
612              
613             =head2 E:not(s1, s2)
614              
615             An C element that does not match either compound selector C or compound selector C. Note that support for
616             compound selectors is B and might change without warning!
617              
618             my $others = $css->select('div p:not(:first-child, :last-child)');
619              
620             Support for compound selectors was added as part of L, which is
621             still a work in progress.
622              
623             =head2 E:is(s1, s2)
624              
625             An C element that matches compound selector C and/or compound selector C. Note that this selector is
626             B and might change without warning!
627              
628             my $headers = $css->select(':is(section, article, aside, nav) h1');
629              
630             This selector is part of L, which is still a work in progress.
631              
632             =head2 E:has(rs1, rs2)
633              
634             An C element, if either of the relative selectors C or C, when evaluated with C as the :scope elements,
635             match an element. Note that this selector is B and might change without warning!
636              
637             my $link = $css->select('a:has(> img)');
638              
639             This selector is part of L, which is still a work in progress.
640             Also be aware that this feature is currently marked C, so there is a high chance that it will get removed
641             completely.
642              
643             =head2 E:text(string_or_regex)
644              
645             An C element containing text content that substring matches C case-insensitively or that regex
646             matches C. For regular expressions use the format C<:text(/.../)>. Note that this selector is
647             B and might change without warning!
648              
649             # Substring match
650             my $login = $css->select(':text(Log in)');
651              
652             # Regex match
653             my $login = $css->select(':text(/Log ?in/)');
654              
655             # Regex match (case-insensitive)
656             my $login = $css->select(':text(/(?i:Log ?in)/)');
657              
658             This is a custom selector for L and not part of any spec.
659              
660             =head2 A|E
661              
662             An C element that belongs to the namespace alias C from L
663             3|https://www.w3.org/TR/css-namespaces-3/>. Key/value pairs passed to selector methods are used to declare namespace
664             aliases.
665              
666             my $elem = $css->select('lq|elem', lq => 'http://example.com/q-markup');
667              
668             Using an empty alias searches for an element that belongs to no namespace.
669              
670             my $div = $c->select('|div');
671              
672             =head2 E F
673              
674             An C element descendant of an C element.
675              
676             my $headlines = $css->select('div h1');
677              
678             =head2 E E F
679              
680             An C element child of an C element.
681              
682             my $headlines = $css->select('html > body > div > h1');
683              
684             =head2 E + F
685              
686             An C element immediately preceded by an C element.
687              
688             my $second = $css->select('h1 + h2');
689              
690             =head2 E ~ F
691              
692             An C element preceded by an C element.
693              
694             my $second = $css->select('h1 ~ h2');
695              
696             =head2 E, F, G
697              
698             Elements of type C, C and C.
699              
700             my $headlines = $css->select('h1, h2, h3');
701              
702             =head2 E[foo=bar][bar=baz]
703              
704             An C element whose attributes match all following attribute selectors.
705              
706             my $links = $css->select('a[foo^=b][foo$=ar]');
707              
708             =head1 ATTRIBUTES
709              
710             L implements the following attributes.
711              
712             =head2 tree
713              
714             my $tree = $css->tree;
715             $css = $css->tree(['root']);
716              
717             Document Object Model. Note that this structure should only be used very carefully since it is very dynamic.
718              
719             =head1 METHODS
720              
721             L inherits all methods from L and implements the following new ones.
722              
723             =head2 matches
724              
725             my $bool = $css->matches('head > title');
726             my $bool = $css->matches('svg|line', svg => 'http://www.w3.org/2000/svg');
727              
728             Check if first node in L matches the CSS selector. Trailing key/value pairs can be used to declare xml
729             namespace aliases.
730              
731             =head2 select
732              
733             my $results = $css->select('head > title');
734             my $results = $css->select('svg|line', svg => 'http://www.w3.org/2000/svg');
735              
736             Run CSS selector against L. Trailing key/value pairs can be used to declare xml namespace aliases.
737              
738             =head2 select_one
739              
740             my $result = $css->select_one('head > title');
741             my $result =
742             $css->select_one('svg|line', svg => 'http://www.w3.org/2000/svg');
743              
744             Run CSS selector against L and stop as soon as the first node matched. Trailing key/value pairs can be used to
745             declare xml namespace aliases.
746              
747             =head1 DEBUGGING
748              
749             You can set the C environment variable to get some advanced diagnostics information printed to
750             C.
751              
752             MOJO_DOM_CSS_DEBUG=1
753              
754             =head1 SEE ALSO
755              
756             L, L, L.
757              
758             =cut