/usr/local/CPAN/XML-Parser-Lite-Tree-XPath/XML/Parser/Lite/Tree/XPath/Eval.pm


package XML::Parser::Lite::Tree::XPath::Eval;

use XML::Parser::Lite::Tree::XPath::Token;
use Data::Dumper;
use strict;

sub new {
	my ($class) = @_;
	my $self = bless {}, $class;
	$self->{error} = 0;
	return $self;
}

sub query {
	my ($self, $xpath, $tree) = @_;
	$self->{error} = 0;
	$self->{tree} = $tree;

	$self->{root} = XML::Parser::Lite::Tree::XPath::Result->new('nodeset', [$self->{tree}]);
	$self->{max_order} = $self->mark_orders($self->{tree}, 1, undef);

	$self->{uids} = {};
	$self->mark_uids($self->{tree});

	my $token = $xpath->{tokens}->[0];
	unless (defined $token){
		$self->{error} = "couldn't get root token to eval.";
		return 0;
	}

	$self->mark_token($token);

	my $out = $token->eval($self->{root});

	if ($out->is_error){
		$self->{error} = $out->{value};
		return 0;
	}

	return $out;

	if ($out->{type} ne 'nodeset'){
		$self->{error} = "Result was not a nodeset (was a $out->{type})";
		return 0;
	}

	return $out->{value};
}

sub mark_orders {
	my ($self, $tag, $i, $parent) = @_;

	$tag->{order} = $i++;
	$tag->{parent} = $parent;

	for my $child(@{$tag->{children}}){
		$i = $self->mark_orders($child, $i, $tag);
	}

	return $i;
}

sub mark_token {
	my ($self, $token) = @_;

	$token->{root} = $self->{root};
	$token->{max_order} = $self->{max_order};

	for my $child(@{$token->{tokens}}){
		$self->mark_token($child);
	}
}

sub mark_uids {
	my ($self, $tag) = @_;

	#
	# mark
	#

	if ($tag->{type} eq 'element'){

		$tag->{uid} = '';

		my $id = $tag->{attributes}->{id};

		if (defined $id && length $id){
			unless (defined $self->{uids}->{$id}){

				$tag->{uid} = $id;
				$self->{uids}->{$id} = 1;
			}
		}
	}


	#
	# descend
	#

	if ($tag->{type} eq 'root' || $tag->{type} eq 'element'){

		for my $child (@{$tag->{children}}){

			$self->mark_uids($child);
		}
	}
}

1;