use strict;
use XML::Rules;
my $parser = XML::Rules->new( rules => [ _default => 'raw extended array']);
my %plugins;
%plugins = (
'_parser' => $parser,
set => sub {
die "The <set> plugin requires a name attribute!\n" unless exists($_[0]->{name});
my $content = $_[0]->{_content};
$plugins{$_[0]->{name}} = sub {$content};
return;
},
print => sub {
print $parser->ToXML( '', process($_[0]->{_content}));
return;
},
select => sub {
die "The <select> plugin requires a switch attribute!\n" unless exists($_[0]->{switch});
my $switch = $_[0]->{switch};
if (exists $_[0]->{':' . $switch}) { # exists a subtag with that name
return process($_[0]->{':' . $switch}[0]{_content})
} elsif (exists $_[0]->{':case'}) { # maybe there is a <case id="that name">
foreach my $case (@{$_[0]->{':case'}}) {
return process($case->{_content}) if $case->{id} eq $switch;
}
return;
} else {
return; # the case was not found
}
},
);
my $data = $parser->parse( \*DATA);
$data = $data->{_content};
use Data::Dumper;
#print Dumper($data);
#print Dumper(process($data));
my $result = $parser->ToXML(@{(process($data))->[0]});
print "\n-----------------------------\n\n$result";
sub process {
my ($what) = @_;
if (! ref $what) {
return $what
} elsif (ref($what) eq 'ARRAY') {
return [ map {
if (!ref $_) {
$_
} elsif (ref($_) eq 'ARRAY' and @$_ == 2) {
processAttr($_->[1]);
if (exists $plugins{$_->[0]}) {
$plugins{$_->[0]}->($_->[1])
} else {
$_->[1]{_content} = process($_->[1]{_content});
[ $_->[0] => $_->[1]]
}
}
} @$what]
} else {
die "process() only accepts strings and array refs.\n";
}
}
sub processAttr {
my ($attrs) = @_;
foreach my $attr (keys %$attrs) {
next if $attr =~ /^:/;
next unless $attrs->{$attr} =~ /\{/;
#print "$attrs->{$attr} -> ";
$attrs->{$attr} =~ tr/{}/<>/;
my $data = $parser->parse( '<root>' . $attrs->{$attr} . '</root>');
$data = $data->{_content}[0][1]{_content};
#print "(" . Dumper($data) . ")";
$attrs->{$attr} = $parser->ToXML('', process($data));
#print "$attrs->{$attr}\n";
}
}
__END__
<html>
<set name="foo">blah blah</set>
<set name="bar">two</set>
<set name="x">3</set>
<h1>I say <foo/>, you know.</h1>
<print>This is printed always!</print>
<p>
<select switch="{bar/}">
<one>This is one.</one>
<two>This is the other.</two>
<three>And this is yet another.</three>
<print>This is NOT printed!</print>
</select>
</p>
<p>
<select switch="{x/}0">
<case id="10">This is ten.</case>
<case id="20">This is twenty.</case>
<case id="30">This is thirty.</case>
<case id="41">This is fourty one.<print>This is not printed neither!</print></case>
</select>
</p>
</html>