#!/usr/bin/perl -w
# $Id: bench_sax_base_libxml_complex,v 1.2 2003/09/19 18:52:26 mrodrigu Exp $
use strict;
use simple_benchmark; # to get memory size
use XML::LibXML::SAX;
use XML::SAX::Machines qw(:all); # to pipe the 2 SAX handlers
use XML::SAX::Writer;

use Getopt::Long;

my( $in_file, $print);
GetOptions( 'print!' => \$print, 'in_file=s' =>\$in_file); 
$in_file ||= 'test.xml';
$print= 1 unless( defined $print);

my @filters=  qw( XML::LibXML::SAX HandlerDelete HandlerDuplicate HandlerChangeTag HandlerPrefix HandlerAddAtt
									HandlerErase
                );
push @filters, 'XML::SAX::Writer' if( $print);

@filters= map { $_->new() } @filters;  # I should not need this, but I do!

Pipeline( @filters)->parse_uri( $in_file);

package HandlerDelete;
use base qw( XML::SAX::Base);
sub new { return bless { level => 0, in_delete => 0, delete_level => -1 }; }
sub start_element { my( $h, $elt)= @_;
		                $h->{level}++; 
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'delete'))
										  { $h->{in_delete}= 1; 
										    $h->{delete_level}= $h->{level}; 
									    } 
									  else
		                  { $h->SUPER::start_element( $elt) unless( $h->{in_delete}); } 
								  }
sub end_element { my( $h, $elt)= @_;
		              if(  $h->{in_delete})
                    { if( ($elt->{Name} eq 'process') && ($h->{level}== $h->{delete_level}) )
												 { $h->{in_delete}= 0; }
										}
		              else
									  { $h->SUPER::end_element( $elt); }
		              $h->{level}--;
								}
sub characters { my( $h, $chars)= @_; $h->SUPER::characters( $chars) unless( $h->{in_delete}); }

package HandlerDuplicate;
use base qw( XML::SAX::Base);
sub new { return bless { level => 0, in_duplicate => 0, duplicate_level => -1, stored_events => [] }; }
sub start_element { my( $h, $elt)= @_;
		                $h->SUPER::start_element( $elt);  
		                $h->{level}++; 
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'duplicate'))
										  { $h->{in_duplicate}= 1; 
										    $h->{duplicate_level}= $h->{level}; 
									    } 
										if( $h->{in_duplicate}) { push @{$h->{stored_events}}, { type => 'start_element', event => $elt }; }
								  }
sub end_element { my( $h, $elt)= @_;
									$h->SUPER::end_element( $elt); 
									if( $h->{in_duplicate})
                    { push @{$h->{stored_events}}, { type => 'end_element', event => $elt };  
                      if( ($elt->{Name} eq 'process') && ($h->{level} == $h->{duplicate_level}) )
												 { $h->{in_duplicate}= 0; 
													 $h->replay_stored_events;
													 $h->{stored_events}= [];
												 }
										}
		              $h->{level}--;
								}
								
sub characters { my( $h, $chars)= @_; 
						     $h->SUPER::characters( $chars);
		             if( $h->{in_duplicate}) { push @{$h->{stored_events}}, { type => 'characters', event => $chars }; }
						   }

sub replay_stored_events
  { my $h= shift;
    foreach my $event ( @{$h->{stored_events}})
      { my $type= $event->{type};
				my $data= $event->{event};
        if( $type eq 'start_element')
          { $h->SUPER::start_element( $data); }
        elsif( $type eq 'end_element')
          { $h->SUPER::end_element( $data); }
        elsif( $type eq 'characters')
          { $h->SUPER::characters( $data); }
      }
  }

package HandlerChangeTag;
use base qw( XML::SAX::Base);
sub new { return bless { level => 0, change_level => -1 }; }
sub start_element { my( $h, $elt)= @_;
		                $h->{level}++; 
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'change_tag'))
										  { $h->{change_level}= $h->{level}; 
												$elt->{Name}= 'new_tag'; 
									    } 
		                $h->SUPER::start_element( $elt); 
								  }
sub end_element { my( $h, $elt)= @_;
                    { if( ($elt->{Name} eq 'process') && ($h->{level}== $h->{change_level}) )
												{ $h->{change_level}= -1;
														$elt->{Name}= 'new_tag';	
												}
										}
									$h->SUPER::end_element( $elt);
		              $h->{level}--;
								}

package HandlerPrefix;
use base qw( XML::SAX::Base);
sub start_element { my( $h, $elt)= @_;
										$h->SUPER::start_element( $elt); 
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'prefix'))
										  { $h->SUPER::start_element( { Name => 'prefix' });
												$h->SUPER::characters( { Data => "prefixed "});
										    $h->SUPER::end_element( { Name => 'prefix' });
											}
								  }

								
package HandlerAddAtt;
use base qw( XML::SAX::Base);
sub start_element { my( $h, $elt)= @_;
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'add_att'))
										  { $elt->{Attributes}->{'{}new_att'}= { Name => 'new_att', Value => 'foo' }; }
										$h->SUPER::start_element( $elt); 
								  }

package HandlerErase;
use base qw( XML::SAX::Base);
sub new { return bless { level => 0, in_erase => 0, erase_level => -1 }; }
sub start_element { my( $h, $elt)= @_;
		                $h->{level}++; 
				            if( ($elt->{Name} eq 'process') && ( ($elt->{Attributes}->{'{}action'}->{Value}||'') eq 'erase'))
										  { $h->{in_erase}= 1; 
										    $h->{erase_level}= $h->{level}; 
									    } 
									  else
		                  { $h->SUPER::start_element( $elt); } 
								  }
sub end_element { my( $h, $elt)= @_;
		              if( $h->{in_erase} &&  ($elt->{Name} eq 'process') && ($h->{level}== $h->{erase_level}) )
                    { $h->{in_erase}= 0; }
		              else
									  { $h->SUPER::end_element( $elt); }
		              $h->{level}--;
								}

