I really like my XPath for object trees idea. I like it so much that I want other people to use it too. The question is, what is the most effective way to make that happen?
I've been thinking I could make it into a module. It could be used like:
package Some::Node; use Class::XPath get_parent => 'parent', get_root => sub { local $_ = shift; while($_->parent) { $_ = $_->parent } return $_; }, get_name => 'name', get_kids => 'children', get_attr => 'attr';
Then clients of Some::Node can do:
@nodes = Some::Node->match('/foo/bar[1]/*');
The idea being that you give Class::XPath some instructions on how to perform various operations - either in the form of method names or as subroutines. Then Class::XPath creates customized versions of xpath() and match() that work with your class.
The value-add here is the XPath parser and executor. At start it would be a straight port of the simple parser I've written already. Later it could grow to include support for more of XPath and learn to optimize match() requests using caches and such. Then others can enjoy the benefits of having full XPath support for their trees without much work at all.
Feedback would be appreciated. Would you use such a module?
-sam
I just wrote B::SAX yesterday (yes, it fires SAX events based on traversing a compiled Perl optree). Is it possible to run XPath over SAX events?
Otherwise, I'll have to write a little state machine to find the subtree I'm seeking. That doesn't sound too awful, but the less work, the better.
Re:Tree Matching?
Matts on 2003-02-27T07:26:07
Yes, see Barrie Slaymaker's XML::Filter::Dispatcher.
Either that or build a DOM (using something like XML::LibXML::SAX::Builder) and go from there.
or maybe#!/usr/bin/perl
use HTML::TreeBuilder;
use HTML::Element;
use Class::XPath (
install_in => 'HTML::Element',
%the_get_foo_mappings,
);
If get_attr is supposed to return a list of attributes, then you'll probably need a get_attr_value or something too.#!/usr/bin/perl
use HTML::TreeBuilder;
use Class::XPath;
my $tree = HTML::TreeBuilder->new();
my $xp_tree = Class::XPath (
use_object => $tree,
%the_get_foo_mappings,
);
Re:yup
dlc on 2003-03-21T19:45:47
How about maybe:
package Foo;
use base qw(Class::XPath);
Class::XPath
can be designed to be mixed-in to any arbitrary class, and simply provide amatch
method. Seems much simpler.Re:yup
samtregar on 2003-03-21T19:53:23
How does Class::XPath magically know how to operate on the nodes of your tree unless you tell it? Sure, inheritence is an option but I doubt the end result would require any less configuration.-sam
Re:yup
dlc on 2003-03-21T20:04:46
I wasn't disgreeing with the need for configuration, just the need usage examples. I was suggesting something more like:
use base qw(Class::XPath);
sub new {
my $class = shift;
my $self = bless { } => $class;
$self->create_matcher(%xpath_stuff);
return $self;
}Though I would suggest that a good default
match
method would be one that could automatically walk a data structure (i.e., didn't use methods, but did stuff based on the underlying data). This default matcher would probably be limited to non-attribute XPath operations, e.g.:/root/foo[2] which would find:
$var->{'root'}->{'foo'}->[1](XPath is 1-based, right?)