use XML::SAX::Expat;
use XML::SAX::Writer;
+use Data::Dumper;
package XML::TemplateSAX::Handler;
use base qw(XML::SAX::Base);
my $self = {
obj => $options{'Content'},
+ stack => [],
Handler => $options{'Handler'}
};
bless($self, $class);
sub start_element {
my ($self, $data) = @_;
+ my $obj = $self->{'obj'};
+ # within a replacement; just ignore everything
+ return if (!defined($obj));
+
+ # substitution: see if this element matches anything. if so,
+ # descend down into the tree.
+ if (ref($obj) eq 'HASH') {
+ my $match = undef;
+ for my $key (keys %$obj) {
+ if ($key =~ /^#(.*)$/) {
+ if ($data->{'NamespaceURI'} eq 'http://template.sesse.net/' && $data->{'LocalName'} eq $1) {
+ $match = $obj->{$key};
+ last;
+ }
+ } else {
+ if ($data->{'LocalName'} eq $key) {
+ $match = $obj->{$key};
+ last;
+ }
+ }
+ }
+
+ if (defined($match)) {
+ $self->SUPER::start_element($data);
+
+ push @{$self->{'stack'}}, [ $data->{'Name'}, $obj ];
+
+ #
+ # This is sort of ugly. We special-case replacement by outputting
+ # the string immediately, and then just ignoring the rest of the
+ # events until we get to the right end tag. It's not 100% technically
+ # correct for the case where you replace an entire document by a
+ # string, but that's nonsensical anyway.
+ #
+ if (!ref($match)) {
+ $self->SUPER::characters({ Data => $match });
+ $match = undef;
+ }
+
+ $self->{'obj'} = $match;
+ return;
+ }
+ }
+
$self->SUPER::start_element($data);
}
+sub characters {
+ my ($self, $data) = @_;
+ return if (!defined($self->{'obj'}));
+ $self->SUPER::characters($data);
+}
+
+sub end_element {
+ my ($self, $data) = @_;
+
+ my $stack = $self->{'stack'};
+ if (scalar @$stack > 0) {
+ my $top = $stack->[$#stack];
+
+ if ($data->{'Name'} eq $top->[0]) {
+ $self->SUPER::end_element($data);
+ $self->{'obj'} = $top->[1];
+ pop @$stack;
+ return;
+ }
+ }
+
+ return if (!defined($self->{'obj'}));
+
+ $self->SUPER::end_element($data);
+}
+
package XML::TemplateSAX;
sub process_file {