I
Ivan Shmakov
[Cross-posting to yet omitting it from
Followup-To:, for I'm primarily interested in Perl-based
solutions.]
Is there an easy way to invoke a particular code for each of XML
nodes that satisfies an XPath expression out of a certain list?
A simple-minded approach (based on XML::LibXML) could be like:
require XML::LibXML;
my %xpath_sub = {
q {//node ()[@foo = "bar"]} => \&foo_bar,
q {//node ()[@baz = "qux"]} => sub { baz ("qux", @_); }
};
foreach my $xpath (keys (%xpath_sub)) {
my $sub
= $xpath_sub{$xpath};
foreach my $node ($context->findnodes ($xpath)) {
$sub->($node);
}
}
However, AIUI, the code above implies that the XML tree is to be
traversed multiple times. Which could probably be avoided by
traversing the tree explicitly, as in:
sub traverse {
my ($node, $xsubs) = @_;
foreach my $xpath (keys (%$xsubs)) {
next
unless ($node->find ($xpath));
## FIXME: check if the result is a boolean?
$xsubs->{$xpath}->($node);
## FIXME: there, one may wish for a recursion; or not
}
## recurse over the children
foreach my $child ($node->childNodes ()) {
traverse ($child, $xsubs);
}
## .
}
Still, it may repeatedly traverse the children of $node while
computing ->find () for each of the XPath expressions. (Unlike
the way an "optimized," or "compiled," regular expression would
be handled, IIUC.)
The question is: does LibXML (or some other library) provide a
way to make such a task both simpler to code and more efficient
on execution?
... Or do I "optimize" all the XPath expressions themselves into
a single one somehow?
TIA.
Followup-To:, for I'm primarily interested in Perl-based
solutions.]
Is there an easy way to invoke a particular code for each of XML
nodes that satisfies an XPath expression out of a certain list?
A simple-minded approach (based on XML::LibXML) could be like:
require XML::LibXML;
my %xpath_sub = {
q {//node ()[@foo = "bar"]} => \&foo_bar,
q {//node ()[@baz = "qux"]} => sub { baz ("qux", @_); }
};
foreach my $xpath (keys (%xpath_sub)) {
my $sub
= $xpath_sub{$xpath};
foreach my $node ($context->findnodes ($xpath)) {
$sub->($node);
}
}
However, AIUI, the code above implies that the XML tree is to be
traversed multiple times. Which could probably be avoided by
traversing the tree explicitly, as in:
sub traverse {
my ($node, $xsubs) = @_;
foreach my $xpath (keys (%$xsubs)) {
next
unless ($node->find ($xpath));
## FIXME: check if the result is a boolean?
$xsubs->{$xpath}->($node);
## FIXME: there, one may wish for a recursion; or not
}
## recurse over the children
foreach my $child ($node->childNodes ()) {
traverse ($child, $xsubs);
}
## .
}
Still, it may repeatedly traverse the children of $node while
computing ->find () for each of the XPath expressions. (Unlike
the way an "optimized," or "compiled," regular expression would
be handled, IIUC.)
The question is: does LibXML (or some other library) provide a
way to make such a task both simpler to code and more efficient
on execution?
... Or do I "optimize" all the XPath expressions themselves into
a single one somehow?
TIA.