Subject: | XML::XPath bugs in comparison operators |
Module: XML-XPath-1.12
Perl version:
perl, v5.6.1 built for MSWin32-x86-multi-thread
Binary build 631 provided by ActiveState Tool Corp.
O.S.: Windows 2000
In XML::XPath (1.12, the latest, right?), there are bugs in the comparison
operators <, <=, >, >= operators, at least when used with attribute values.
For the following sample code:
...
my @nodes = $xp->findnodes('//BBB[@xx <= "51"]');
...
The following error message appears
No such method to_number in XML::XPath::Node::AttributeImpl at
c:/Perl/site/lib/XML/XPath/Expr.pm line 452
The offending line 452 in Expr.pm:
if ($node->to_number->value > $other->to_number->value) {
where $node is of type AttributeImpl.
One possible fix (and I don't know the XML::XPath well enough to know if
this is the best fix approach):
Add the following line to Node/Attribute.pm:
sub to_number { return XML::XPath::Number->new($_[0]->string_value);
}
(similar to Literal.pm -- should a to_number sub be added elsewhere, also?
I haven't thoroughly checked...).
Also, in Expr.pm, the "op_lt" and "op_le" subroutines have minor bugs (they
"flip" args to calls to op_ge() and op_gt() incorrectly).
These should be changed to:
sub op_le {
my ($node, $lhs, $rhs) = @_;
op_gt($node, $rhs, $lhs);
}
...
sub op_lt {
my ($node, $lhs, $rhs) = @_;
op_ge($node, $rhs, $lhs);
}
(These previously had op_ge() and op_gt() calls, respectively.)
Thanks,
Jim Wiltshire
# $Id: Attribute.pm,v 1.9 2001/11/05 19:57:47 matt Exp $
package XML::XPath::Node::Attribute;
use strict;
use vars qw/@ISA/;
@ISA = ('XML::XPath::Node');
package XML::XPath::Node::AttributeImpl;
use vars qw/@ISA/;
@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Attribute');
use XML::XPath::Node ':node_keys';
sub new {
my $class = shift;
my ($key, $val, $prefix) = @_;
my $pos = XML::XPath::Node->nextPos;
my @vals;
@vals[node_global_pos, node_prefix, node_key, node_value] =
($pos, $prefix, $key, $val);
my $self = \@vals;
bless $self, $class;
}
sub getNodeType { ATTRIBUTE_NODE }
sub isAttributeNode { 1; }
sub getName {
my $self = shift;
$self->[node_key];
}
sub getLocalName {
my $self = shift;
my $local = $self->[node_key];
$local =~ s/.*://;
return $local;
}
sub getNodeValue {
my $self = shift;
$self->[node_value];
}
sub getData {
shift->getNodeValue(@_);
}
sub setNodeValue {
my $self = shift;
$self->[node_value] = shift;
}
sub getPrefix {
my $self = shift;
$self->[node_prefix];
}
sub string_value {
my $self = shift;
return $self->[node_value];
}
sub to_number { return XML::XPath::Number->new($_[0]->string_value); }
sub toString {
my $self = shift;
my $string = ' ';
# if ($self->[node_prefix]) {
# $string .= $self->[node_prefix] . ':';
# }
$string .= join('',
$self->[node_key],
'="',
XML::XPath::Node::XMLescape($self->[node_value], '"&><'),
'"');
return $string;
}
sub getNamespace {
my $self = shift;
my ($prefix) = @_;
$prefix ||= $self->getPrefix;
if (my $parent = $self->getParentNode) {
return $parent->getNamespace($prefix);
}
}
1;
__END__
=head1 NAME
Attribute - a single attribute
=head1 API
=head2 new ( key, value, prefix )
Create a new attribute node.
=head2 getName
Returns the key for the attribute
=head2 getLocalName
As getName above, but without namespace information
=head2 getNodeValue / getData
Returns the value
=head2 setNodeValue
Sets the value of the attribute node.
=head2 getPrefix
Returns the prefix
=head2 getNamespace
Return the namespace.
=head2 toString
Generates key="value", encoded correctly.
=cut