7 package XML::TemplateSAX::Handler;
8 use base qw(XML::SAX::Base);
15 obj => $options{'Content'},
18 Handler => $options{'Handler'}
25 my ($self, $data) = @_;
26 my $obj = $self->{'obj'};
31 my $id = $data->{'Attributes'}->{'{http://template.sesse.net/}id'};
32 $id = $id->{'Value'} if (defined($id));
34 # within a replacement; just ignore everything
35 return if (!defined($obj));
37 # within a cloning; slurp it up
38 if (ref($obj) eq 'XML::TemplateSAX::Buffer') {
39 $obj->start_element($data);
43 # substitution: see if this element matches anything. if so,
44 # descend down into the tree.
45 if (ref($obj) eq 'HASH') {
46 # first of all, see if we have an attribute match.
47 for my $key (keys %$obj) {
48 next unless ($key =~ /^(#?)(.*)\/(.*)$/);
49 my ($idmarker, $name, $attr) = ($1, $2, $3);
51 if (($idmarker eq '#' && $id eq $name) ||
52 ($idmarker ne '#' && $data->{'LocalName'} eq $name)) {
53 $data->{'Attributes'}->{$attr} = {
64 for my $key (keys %$obj) {
65 if ($key =~ /^#(.*)$/) {
66 if (defined($id) && $id eq $1) {
67 $match = $obj->{$key};
71 if ($data->{'LocalName'} eq $key) {
72 $match = $obj->{$key};
78 if (defined($match)) {
79 $self->SUPER::start_element($data);
81 push @{$self->{'stack'}}, [ $self->{'level'}, $obj ];
84 # This is sort of ugly. We special-case replacement by outputting
85 # the string immediately, and then just ignoring the rest of the
86 # events until we get to the right end tag. It's not 100% technically
87 # correct for the case where you replace an entire document by a
88 # string, but that's nonsensical anyway.
91 $self->SUPER::characters({ Data => $match });
92 $self->{'obj'} = undef;
97 # Sort of the same, for cloning. Cloning works by gobbling up all the all the
98 # input until the end element, and put it into a buffer. when we get to the end
99 # element, spew it all out again as many times as we need, onto ourselves so we
100 # get filtering etc. right.
102 # We let the buffer object keep the actual array, so we can fetch it out later.
104 if (ref($match) eq 'ARRAY') {
105 $self->{'obj'} = XML::TemplateSAX::Buffer->new($match);
110 # If someone tries to insert a full tree, do it, just like the character
113 if (ref($match) eq 'XML::TemplateSAX::Buffer') {
114 $match->replay($self);
115 $self->{'obj'} = undef;
116 } elsif (ref($match) eq 'XML::TemplateSAX::Deferred') {
117 $match->parse($self);
118 $self->{'obj'} = undef;
120 $self->{'obj'} = $match;
127 $self->SUPER::start_element($data);
131 my ($self, $data) = @_;
133 return if (!defined($self->{'obj'}));
135 if (ref($self->{'obj'}) eq 'XML::TemplateSAX::Buffer') {
136 $self->{'obj'}->characters($data);
140 $self->SUPER::characters($data);
144 my ($self, $data) = @_;
146 return if (!defined($self->{'obj'}));
148 if (ref($self->{'obj'}) eq 'XML::TemplateSAX::Buffer') {
149 $self->{'obj'}->comment($data);
153 $self->SUPER::comment($data);
156 sub processing_instruction {
157 my ($self, $data) = @_;
159 return if (!defined($self->{'obj'}));
161 if (ref($self->{'obj'}) eq 'XML::TemplateSAX::Buffer') {
162 $self->{'obj'}->processing_instruction($data);
166 $self->SUPER::processing_instruction($data);
170 my ($self, $data) = @_;
172 my $stack = $self->{'stack'};
173 if (scalar @$stack > 0) {
174 my $top = $stack->[scalar @$stack - 1];
176 if ($self->{'level'} == $top->[0]) {
177 my $obj = $self->{'obj'};
179 # did we just finish a clone operation?
180 if (ref($obj) eq 'XML::TemplateSAX::Buffer') {
181 for my $instance (@{$obj->{'ptr'}}) {
182 $self->{'obj'} = $instance;
187 $self->SUPER::end_element($data);
188 $self->{'obj'} = $top->[1];
197 return if (!defined($self->{'obj'}));
199 if (ref($self->{'obj'}) eq 'XML::TemplateSAX::Buffer') {
200 $self->{'obj'}->end_element($data);
204 $self->SUPER::end_element($data);