PROXY  WHOIS  RQUOTE  TEXTS  SOFT  FOREX  BBOARD
 Music  Philosophy  Code  Literature  Russian

= ROOT|Technical|Code_Examples|Perl|site_perl|Class|XPath.pm =

page 3 of 7



        # do attribute matching
        foreach my $kid (@kids) {
            my $value = $get_attr_value->($kid, $pat->{attr});
            push(@results, $kid)
              if ($op eq 'eq' and $value eq $pat->{value}) or 
                 ($op eq '='  and $value == $pat->{value}) or 
                 ($op eq '!=' and $value != $pat->{value}) or 
                 ($op eq '>'  and $value >  $pat->{value}) or 
                 ($op eq '<'  and $value <  $pat->{value}) or 
                 ($op eq '>=' and $value >= $pat->{value}) or 
                 ($op eq '<=' and $value <= $pat->{value});                 
        }
        }
        else {
            my $attr = $pat->{attr};
            push(@results, $get_attr_value->($self, $attr))
            if grep { $_ eq $attr } $get_attr_names->($self);
        }
    } elsif (defined $pat->{child}) {
        croak("Can't process child pattern without name")
        unless defined $pat->{name};
        # default op is 'eq' for string matching
        my $op = $pat->{op} || 'eq';
        # do attribute matching
        foreach my $kid (@kids) {
            foreach ( 
                $pat->{child} eq "." ? $kid
                : grep {$get_name->($_) eq $pat->{child}} $get_children->($kid)
            ) {
                my $value;
                foreach_node { 
                    my $txt = $get_content->($_);
                    $value .= $txt if defined $txt;
                } $_, $get_children;
                next unless defined $value;
                push(@results, $kid)
                  if ($op eq 'eq' and $value eq $pat->{value}) or 
                     ($op eq '='  and $value == $pat->{value}) or 
                     ($op eq '!=' and $value != $pat->{value}) or 
                     ($op eq '>'  and $value >  $pat->{value}) or 
                     ($op eq '<'  and $value <  $pat->{value}) or 
                     ($op eq '>=' and $value >= $pat->{value}) or 
                     ($op eq '<=' and $value <= $pat->{value});
            }
        }
    } else {
        push @results, @kids;
    }

    # all done?
    return @results unless @patterns;

    # apply remaining patterns on matching kids
    return map { $pkg->_do_match($_, $args, @patterns) } @results;
}


sub xpath {
    my ($pkg, $self, $args) = @_;
    my ($get_parent, $get_children, $get_name) = 
      @{$args}{qw(get_parent get_children get_name)};

    my $parent = $get_parent->($self);
    return '/' unless defined $parent; # root's xpath is /
    
    # get order within same-named nodes in the parent
    my $name = $get_name->($self);
    my $count = 0;
    for my $kid ($get_children->($parent)) {
        last if $kid == $self;
        $count++ if $get_name->($kid) eq $name;
    }

    # construct xpath using parent's xpath and our name and count
    return $pkg->xpath($parent, $args) . 
      ($get_parent->($parent) ? '/' : '') .
        $name . '[' . $count . ']';
}


# does a depth first traversal in a stack
sub foreach_node (&@) {
    my ($code, $node, $get_children) = @_;
    my @stack = ($node);
    while (@stack) {
        local $_ = shift(@stack);
        $code->();
        push(@stack, $get_children->($_));
    }
}

1;
__END__

=head1 NAME

Class::XPath - adds xpath matching to object trees

=head1 SYNOPSIS

=3=

1|2| < PREV = PAGE 3 = NEXT > |4|5|6|7

UP TO ROOT | UP TO DIR | TO FIRST PAGE

Google
 


E-mail Facebook Google Digg del.icio.us BlinkList Fark Furl Ma.gnolia Netscape NewsVine Reddit Slashdot Spurl StumbleUpon Technorati YahooMyWeb LiveJournal Blogmarks TwitThis Live News2.ru BobrDobr.ru Memori.ru MoeMesto.ru

0.00578499 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU)