1 package HTML::Zoom::SelectorParser;
4 use warnings FATAL => 'all';
5 use base qw(HTML::Zoom::SubObject);
9 my $sel_re = qr/([$sel_char]+)/;
11 sub new { bless({}, shift) }
13 sub _raw_parse_simple_selector {
14 for ($_[1]) { # same pos() as outside
16 # '*' - match anything
23 /\G$sel_re\[$sel_re~="$sel_re"\]/gc and
30 $_[0]->{name} && $_[0]->{name} eq $name and
33 my %vals = map { $_ => 1 } split /\s+/, $_[0]->{attrs}{$attr};
42 /\G$sel_re\[$sel_re="$sel_re"\]/gc and
48 $_[0]->{name} && $_[0]->{name} eq $name and
49 $_[0]->{attrs}{$attr} && $_[0]->{attrs}{$attr} eq $val
53 # 'element' - match on tag name
58 sub { $_[0]->{name} && $_[0]->{name} eq $name }
61 # '#id' - match on id attribute
66 sub { $_[0]->{attrs}{id} && $_[0]->{attrs}{id} eq $id }
69 # '.class1.class2' - match on intersection of classes
71 /\G((?:\.$sel_re)+)/gc and
73 my $cls = $1; $cls =~ s/^\.//;
74 my @cl = split(/\./, $cls);
77 && !grep $_[0]->{attrs}{class} !~ /(^|\s+)$_($|\s+)/, @cl
81 # 'el.class1' - element + class
83 /\G$sel_re\.$sel_re/gc and
88 $_[0]->{name} && $_[0]->{name} eq $name and
89 $_[0]->{attrs}{class} && $_[0]->{attrs}{class} eq $cls
93 # 'el#id' - element + id
95 /\G$sel_re#$sel_re/gc and
100 $_[0]->{name} && $_[0]->{name} eq $name and
101 $_[0]->{attrs}{id} && $_[0]->{attrs}{id} eq $id
105 confess "Couldn't parse $_ as starting with simple selector";
111 my $sel = $_[1]; # my pos() only please
112 die "No selector provided" unless $sel;
117 push(@sub, $self->_raw_parse_simple_selector($_));
118 last PARSE if (pos == length);
119 /\G\s*,\s*/gc or confess "Selectors not comma separated";
120 } until (pos == length) };
121 return $sub[0] if (@sub == 1);
123 foreach my $inner (@sub) {
124 if (my $r = $inner->(@_)) { return $r }