use strict;
use XML::Rules;

my $xml = <<'*END*';
<doc>
	<set name="x"><plus><times>5 3</times> 9</plus></set>
	<print>The result is: <plus>1 -<var>x</var></plus>
</print>
	<print x="129">The result is: <plus>1 -<var>x</var></plus>
</print>
	<print>The other result is: <plus>1 2 3 4 5</plus></print>
</doc>
*END*
	use List::Util qw(reduce);
	my $parser = new XML::Rules (
		rules => [
			'times' => sub {reduce {$a * $b} split ' ', $_[1]->{_content}},
			'plus' => sub {reduce {$a + $b} split ' ', $_[1]->{_content}},
			'set' => sub {
				my ($tag_name, $tag_hash, $context, $parent_data) = @_;
				$parent_data->[-1]{$tag_hash->{name}} = $tag_hash->{_content};
#print "Defined variable $tag_hash->{name}= $tag_hash->{_content} in <$context->[-1]>\n";
				return;
			},
			'var' => sub {
				my ($tag_name, $tag_hash, $context, $parent_data) = @_;
				my $var_name = $tag_hash->{_content};
				s/^\s+//,s/\s+$// for ($var_name);

				for (my $i = $#{$parent_data}; $i>=0; $i--) {
#print "Looking for $var_name in <$context->[$i]>\n";
#print "  Found: $parent_data->[$i]{$var_name}\n" if exists($parent_data->[$i]{$var_name});
					return $parent_data->[$i]{$var_name} if exists($parent_data->[$i]{$var_name});
				}
				die "Variable $var_name not defined in current scope!\n";
			},
			'print' => sub {print $_[1]->{_content}; return;},
			'doc' => sub {},
		]
	);

my $result = $parser->parsestring($xml);
