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);