/usr/local/CPAN/XML-Parser-Lite-Tree-XPath/XML/Parser/Lite/Tree/XPath/Result.pm
package XML::Parser::Lite::Tree::XPath::Result;
use strict;
use Data::Dumper;
#
# types:
#
# Error - value is error message string
# number - value is numeric scalar
# boolean - value is boolean scalar
# string - value is string scalar
# nodeset - value is arrayref of nodes and/or attributes
# node - value is node
# attribute - value is attribute
#
sub new {
my $class = shift;
my $self = bless {}, $class;
$self->{type} = shift;
$self->{value} = shift;
return $self;
}
sub is_error {
my ($self) = @_;
return ($self->{type} eq 'Error') ? 1 : 0;
}
sub normalize {
my ($self) = @_;
if ($self->{type} eq 'nodeset'){
# uniquify and sort
my %seen = ();
my @tags = sort {
$a->{order} <=> $b->{order}
} grep {
! $seen{$_->{order}} ++
} @{$self->{value}};
$self->{value} = \@tags;
}
}
sub ret {
my ($self, $a, $b) = @_;
return XML::Parser::Lite::Tree::XPath::Result->new($a, $b);
}
sub get_type {
my ($self, $type) = @_;
return $self if $self->is_error;
return $self->get_number if $type eq 'number';
return $self->get_boolean if $type eq 'boolean';
return $self->get_string if $type eq 'string';
return $self->get_nodeset if $type eq 'nodeset';
return $self->get_node if $type eq 'node';
return $self->ret('Error', "Can't get type '$type'");
}
sub get_boolean {
my ($self) = @_;
return $self if $self->{type} eq 'boolean';
return $self if $self->is_error;
if ($self->{type} eq 'number'){
return $self->ret('boolean', 0) if $self->{value} eq 'NaN';
return $self->ret('boolean', $self->{value} != 0);
}
if ($self->{type} eq 'string'){
return $self->ret('boolean', length $self->{value} > 0);
}
if ($self->{type} eq 'nodeset'){
return $self->ret('boolean', scalar(@{$self->{value}}) > 0);
}
if ($self->{type} eq 'node'){
# todo
}
return $self->ret('Error', "can't convert type $self->{type} to boolean");
}
sub get_string {
my ($self) = @_;
return $self if $self->{type} eq 'string';
return $self if $self->is_error;
if ($self->{type} eq 'nodeset'){
return $self->ret('string', '') unless scalar @{$self->{value}};
my $node = $self->ret('node', $self->{value}->[0]);
return $node->get_string;
}
if ($self->{type} eq 'node'){
return $self->ret('string', $self->{value}->{value}) if $self->{value}->{type} eq 'attribute';
die "can't convert a node of type $self->{value}->{type} to a string";
}
if ($self->{type} eq 'number'){
return $self->ret('string', "$self->{value}");
}
if ($self->{type} eq 'boolean'){
return $self->ret('string', $self->{value} ? 'true' : 'false');
}
return $self->ret('Error', "can't convert type $self->{type} to string");
}
sub get_nodeset {
my ($self) = @_;
return $self if $self->{type} eq 'nodeset';
return $self if $self->is_error;
if ($self->{type} eq 'node'){
return $self->ret('nodeset', [$self->{value}]);
}
return $self->ret('Error', "can't convert type $self->{type} to nodeset");
}
sub get_node {
my ($self) = @_;
return $self if $self->{type} eq 'node';
return $self if $self->is_error;
return $self->ret('Error', "can't convert type $self->{type} to node");
}
sub get_number {
my ($self) = @_;
return $self if $self->{type} eq 'number';
return $self if $self->is_error;
if ($self->{type} eq 'string'){
if ($self->{value} =~ m!^[\x20\x09\x0D\x0A]*(-?([0-9]+(\.([0-9]+)?)?)|(\.[0-9]+))[\x20\x09\x0D\x0A]*$!){
return $self->ret('number', $1);
}else{
return $self->ret('number', 'NaN');
}
}
if ($self->{type} eq 'boolean'){
return $self->ret('number', $self->{value}?1:0);
}
return $self->ret('Error', "can't convert type $self->{type} to number");
}
1;