commit 20732bde5cec3132a16cc35aff128ebe5e2aa5af Author: su-fang Date: Thu Sep 1 16:05:48 2022 +0800 Import Upstream version 1.09 diff --git a/BuildSAXBase.pl b/BuildSAXBase.pl new file mode 100644 index 0000000..7818fba --- /dev/null +++ b/BuildSAXBase.pl @@ -0,0 +1,847 @@ +#!/usr/bin/perl +# +# This file is used to generate lib/XML/SAX/Base.pm. There is a pre-generated +# Base.pm file included in the distribution so you don't need to run this +# script unless you are attempting to modify the code. +# +# The code in this file was adapted from the Makefile.PL when XML::SAX::Base +# was split back out into its own distribution. +# +# You can manually run this file: +# +# perl ./BuildSAXBase.pl +# +# or better yet it will be invoked by automatically Dist::Zilla when building +# a release from the git repository. +# +# dzil build +# + +package SAX::Base::Builder; + +use strict; +use warnings; + +use File::Spec; + +write_xml_sax_base() unless caller(); + +sub build_xml_sax_base { + my $code = <<'EOHEADER'; +package XML::SAX::Base; + +# version 0.10 - Kip Hampton +# version 0.13 - Robin Berjon +# version 0.15 - Kip Hampton +# version 0.17 - Kip Hampton +# version 0.19 - Kip Hampton +# version 0.21 - Kip Hampton +# version 0.22 - Robin Berjon +# version 0.23 - Matt Sergeant +# version 0.24 - Robin Berjon +# version 0.25 - Kip Hampton +# version 1.00 - Kip Hampton +# version 1.01 - Kip Hampton +# version 1.02 - Robin Berjon +# version 1.03 - Matt Sergeant +# version 1.04 - Kip Hampton +# version 1.05 - Grant McLean +# version 1.06 - Grant McLean +# version 1.07 - Grant McLean +# version 1.08 - Grant McLean + +#-----------------------------------------------------# +# STOP!!!!! +# +# This file is generated by the 'BuildSAXBase.pl' file +# that ships with the XML::SAX::Base distribution. +# If you need to make changes, patch that file NOT +# XML/SAX/Base.pm Better yet, fork the git repository +# commit your changes and send a pull request: +# https://github.com/grantm/XML-SAX-Base +#-----------------------------------------------------# + +use strict; + +use XML::SAX::Exception qw(); + +EOHEADER + + my %EVENT_SPEC = ( + start_document => [qw(ContentHandler DocumentHandler Handler)], + end_document => [qw(ContentHandler DocumentHandler Handler)], + start_element => [qw(ContentHandler DocumentHandler Handler)], + end_element => [qw(ContentHandler DocumentHandler Handler)], + characters => [qw(ContentHandler DocumentHandler Handler)], + processing_instruction => [qw(ContentHandler DocumentHandler Handler)], + ignorable_whitespace => [qw(ContentHandler DocumentHandler Handler)], + set_document_locator => [qw(ContentHandler DocumentHandler Handler)], + start_prefix_mapping => [qw(ContentHandler Handler)], + end_prefix_mapping => [qw(ContentHandler Handler)], + skipped_entity => [qw(ContentHandler Handler)], + start_cdata => [qw(DocumentHandler LexicalHandler Handler)], + end_cdata => [qw(DocumentHandler LexicalHandler Handler)], + comment => [qw(DocumentHandler LexicalHandler Handler)], + entity_reference => [qw(DocumentHandler Handler)], + notation_decl => [qw(DTDHandler Handler)], + unparsed_entity_decl => [qw(DTDHandler Handler)], + element_decl => [qw(DeclHandler Handler)], + attlist_decl => [qw(DTDHandler Handler)], + doctype_decl => [qw(DTDHandler Handler)], + xml_decl => [qw(DTDHandler Handler)], + entity_decl => [qw(DTDHandler Handler)], + attribute_decl => [qw(DeclHandler Handler)], + internal_entity_decl => [qw(DeclHandler Handler)], + external_entity_decl => [qw(DeclHandler Handler)], + resolve_entity => [qw(EntityResolver Handler)], + start_dtd => [qw(LexicalHandler Handler)], + end_dtd => [qw(LexicalHandler Handler)], + start_entity => [qw(LexicalHandler Handler)], + end_entity => [qw(LexicalHandler Handler)], + warning => [qw(ErrorHandler Handler)], + error => [qw(ErrorHandler Handler)], + fatal_error => [qw(ErrorHandler Handler)], + ); + + for my $ev (keys %EVENT_SPEC) { + $code .= <<" EOTOPCODE"; +sub $ev { + my \$self = shift; + if (defined \$self->{Methods}->{'$ev'}) { + \$self->{Methods}->{'$ev'}->(\@_); + } + else { + my \$method; + my \$callbacks; + if (exists \$self->{ParseOptions}) { + \$callbacks = \$self->{ParseOptions}; + } + else { + \$callbacks = \$self; + } + if (0) { # dummy to make elsif's below compile + } + EOTOPCODE + + my ($can_string, $aload_string); + for my $h (@{$EVENT_SPEC{$ev}}) { + $can_string .= <<" EOCANBLOCK"; + elsif (defined \$callbacks->{'$h'} and \$method = \$callbacks->{'$h'}->can('$ev') ) { + my \$handler = \$callbacks->{'$h'}; + \$self->{Methods}->{'$ev'} = sub { \$method->(\$handler, \@_) }; + return \$method->(\$handler, \@_); + } + EOCANBLOCK + $aload_string .= <<" EOALOADBLOCK"; + elsif (defined \$callbacks->{'$h'} + and \$callbacks->{'$h'}->can('AUTOLOAD') + and \$callbacks->{'$h'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my \$res = eval { \$callbacks->{'$h'}->$ev(\@_) }; + if (\$@) { + die \$@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my \$handler = \$callbacks->{'$h'}; + \$self->{Methods}->{'$ev'} = sub { \$handler->$ev(\@_) }; + } + return \$res; + } + EOALOADBLOCK + } + + $code .= $can_string . $aload_string; + + $code .= <<" EOFALLTHROUGH"; + else { + \$self->{Methods}->{'$ev'} = sub { }; + } + } + EOFALLTHROUGH + + $code .= "\n}\n\n"; + } + + $code .= <<'BODY'; +#-------------------------------------------------------------------# +# Class->new(%options) +#-------------------------------------------------------------------# +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $options = ($#_ == 0) ? shift : { @_ }; + + unless ( defined( $options->{Handler} ) or + defined( $options->{ContentHandler} ) or + defined( $options->{DTDHandler} ) or + defined( $options->{DocumentHandler} ) or + defined( $options->{LexicalHandler} ) or + defined( $options->{ErrorHandler} ) or + defined( $options->{DeclHandler} ) ) { + + $options->{Handler} = XML::SAX::Base::NoHandler->new; + } + + my $self = bless $options, $class; + # turn NS processing on by default + $self->set_feature('http://xml.org/sax/features/namespaces', 1); + return $self; +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse(%options) +#-------------------------------------------------------------------# +sub parse { + my $self = shift; + my $parse_options = $self->get_options(@_); + local $self->{ParseOptions} = $parse_options; + if ($self->{Parent}) { # calling parse on a filter for some reason + return $self->{Parent}->parse($parse_options); + } + else { + my $method; + if (defined $parse_options->{Source}{CharacterStream} and $method = $self->can('_parse_characterstream')) { + warn("parse charstream???\n"); + return $method->($self, $parse_options->{Source}{CharacterStream}); + } + elsif (defined $parse_options->{Source}{ByteStream} and $method = $self->can('_parse_bytestream')) { + return $method->($self, $parse_options->{Source}{ByteStream}); + } + elsif (defined $parse_options->{Source}{String} and $method = $self->can('_parse_string')) { + return $method->($self, $parse_options->{Source}{String}); + } + elsif (defined $parse_options->{Source}{SystemId} and $method = $self->can('_parse_systemid')) { + return $method->($self, $parse_options->{Source}{SystemId}); + } + else { + die "No _parse_* routine defined on this driver (If it is a filter, remember to set the Parent property. If you call the parse() method, make sure to set a Source. You may want to call parse_uri, parse_string or parse_file instead.) [$self]"; + } + } +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_file(%options) +#-------------------------------------------------------------------# +sub parse_file { + my $self = shift; + my $file = shift; + return $self->parse_uri($file, @_) if ref(\$file) eq 'SCALAR'; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{ByteStream} = $file; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_uri(%options) +#-------------------------------------------------------------------# +sub parse_uri { + my $self = shift; + my $file = shift; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{SystemId} = $file; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_string(%options) +#-------------------------------------------------------------------# +sub parse_string { + my $self = shift; + my $string = shift; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{String} = $string; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_options +#-------------------------------------------------------------------# +sub get_options { + my $self = shift; + + if (@_ == 1) { + return { %$self, %{$_[0]} }; + } else { + return { %$self, @_ }; + } +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_features +#-------------------------------------------------------------------# +sub get_features { + return ( + 'http://xml.org/sax/features/external-general-entities' => undef, + 'http://xml.org/sax/features/external-parameter-entities' => undef, + 'http://xml.org/sax/features/is-standalone' => undef, + 'http://xml.org/sax/features/lexical-handler' => undef, + 'http://xml.org/sax/features/parameter-entities' => undef, + 'http://xml.org/sax/features/namespaces' => 1, + 'http://xml.org/sax/features/namespace-prefixes' => 0, + 'http://xml.org/sax/features/string-interning' => undef, + 'http://xml.org/sax/features/use-attributes2' => undef, + 'http://xml.org/sax/features/use-locator2' => undef, + 'http://xml.org/sax/features/validation' => undef, + + 'http://xml.org/sax/properties/dom-node' => undef, + 'http://xml.org/sax/properties/xml-string' => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_feature +#-------------------------------------------------------------------# +sub get_feature { + my $self = shift; + my $feat = shift; + + # check %FEATURES to see if it's there, and return it if so + # throw XML::SAX::Exception::NotRecognized if it's not there + # throw XML::SAX::Exception::NotSupported if it's there but we + # don't support it + + my %features = $self->get_features(); + if (exists $features{$feat}) { + my %supported = map { $_ => 1 } $self->supported_features(); + if ($supported{$feat}) { + return $self->{__PACKAGE__ . "::Features"}{$feat}; + } + throw XML::SAX::Exception::NotSupported( + Message => "The feature '$feat' is not supported by " . ref($self), + Exception => undef, + ); + } + throw XML::SAX::Exception::NotRecognized( + Message => "The feature '$feat' is not recognized by " . ref($self), + Exception => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# set_feature +#-------------------------------------------------------------------# +sub set_feature { + my $self = shift; + my $feat = shift; + my $value = shift; + # check %FEATURES to see if it's there, and set it if so + # throw XML::SAX::Exception::NotRecognized if it's not there + # throw XML::SAX::Exception::NotSupported if it's there but we + # don't support it + + my %features = $self->get_features(); + if (exists $features{$feat}) { + my %supported = map { $_ => 1 } $self->supported_features(); + if ($supported{$feat}) { + return $self->{__PACKAGE__ . "::Features"}{$feat} = $value; + } + throw XML::SAX::Exception::NotSupported( + Message => "The feature '$feat' is not supported by " . ref($self), + Exception => undef, + ); + } + throw XML::SAX::Exception::NotRecognized( + Message => "The feature '$feat' is not recognized by " . ref($self), + Exception => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_handler and friends +#-------------------------------------------------------------------# +sub get_handler { + my $self = shift; + my $handler_type = shift; + $handler_type ||= 'Handler'; + return defined( $self->{$handler_type} ) ? $self->{$handler_type} : undef; +} + +sub get_document_handler { + my $self = shift; + return $self->get_handler('DocumentHandler', @_); +} + +sub get_content_handler { + my $self = shift; + return $self->get_handler('ContentHandler', @_); +} + +sub get_dtd_handler { + my $self = shift; + return $self->get_handler('DTDHandler', @_); +} + +sub get_lexical_handler { + my $self = shift; + return $self->get_handler('LexicalHandler', @_); +} + +sub get_decl_handler { + my $self = shift; + return $self->get_handler('DeclHandler', @_); +} + +sub get_error_handler { + my $self = shift; + return $self->get_handler('ErrorHandler', @_); +} + +sub get_entity_resolver { + my $self = shift; + return $self->get_handler('EntityResolver', @_); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# set_handler and friends +#-------------------------------------------------------------------# +sub set_handler { + my $self = shift; + my ($new_handler, $handler_type) = reverse @_; + $handler_type ||= 'Handler'; + $self->{Methods} = {} if $self->{Methods}; + $self->{$handler_type} = $new_handler; + $self->{ParseOptions}->{$handler_type} = $new_handler; + return 1; +} + +sub set_document_handler { + my $self = shift; + return $self->set_handler('DocumentHandler', @_); +} + +sub set_content_handler { + my $self = shift; + return $self->set_handler('ContentHandler', @_); +} +sub set_dtd_handler { + my $self = shift; + return $self->set_handler('DTDHandler', @_); +} +sub set_lexical_handler { + my $self = shift; + return $self->set_handler('LexicalHandler', @_); +} +sub set_decl_handler { + my $self = shift; + return $self->set_handler('DeclHandler', @_); +} +sub set_error_handler { + my $self = shift; + return $self->set_handler('ErrorHandler', @_); +} +sub set_entity_resolver { + my $self = shift; + return $self->set_handler('EntityResolver', @_); +} + +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# supported_features +#-------------------------------------------------------------------# +sub supported_features { + my $self = shift; + # Only namespaces are required by all parsers + return ( + 'http://xml.org/sax/features/namespaces', + ); +} +#-------------------------------------------------------------------# + +sub no_op { + # this space intentionally blank +} + + +package XML::SAX::Base::NoHandler; + +# we need a fake handler that doesn't implement anything, this +# simplifies the code a lot (though given the recent changes, +# it may be better to do without) +sub new { + #warn "no handler called\n"; + return bless {}; +} + +1; + +BODY + + $code .= "__END__\n"; + + $code .= <<'FOOTER'; + +=head1 NAME + +XML::SAX::Base - Base class SAX Drivers and Filters + +=head1 SYNOPSIS + + package MyFilter; + use XML::SAX::Base; + @ISA = ('XML::SAX::Base'); + +=head1 DESCRIPTION + +This module has a very simple task - to be a base class for PerlSAX +drivers and filters. It's default behaviour is to pass the input directly +to the output unchanged. It can be useful to use this module as a base class +so you don't have to, for example, implement the characters() callback. + +The main advantages that it provides are easy dispatching of events the right +way (ie it takes care for you of checking that the handler has implemented +that method, or has defined an AUTOLOAD), and the guarantee that filters +will pass along events that they aren't implementing to handlers downstream +that might nevertheless be interested in them. + +=head1 WRITING SAX DRIVERS AND FILTERS + +The Perl Sax API Reference is at L. + +Writing SAX Filters is tremendously easy: all you need to do is +inherit from this module, and define the events you want to handle. A +more detailed explanation can be found at +http://www.xml.com/pub/a/2001/10/10/sax-filters.html. + +Writing Drivers is equally simple. The one thing you need to pay +attention to is B to call events yourself (this applies to Filters +as well). For instance: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something + $self->{Handler}->start_element($data); # BAD + } + +The above example works well as precisely that: an example. But it has +several faults: 1) it doesn't test to see whether the handler defines +start_element. Perhaps it doesn't want to see that event, in which +case you shouldn't throw it (otherwise it'll die). 2) it doesn't check +ContentHandler and then Handler (ie it doesn't look to see that the +user hasn't requested events on a specific handler, and if not on the +default one), 3) if it did check all that, not only would the code be +cumbersome (see this module's source to get an idea) but it would also +probably have to check for a DocumentHandler (in case this were SAX1) +and for AUTOLOADs potentially defined in all these packages. As you can +tell, that would be fairly painful. Instead of going through that, +simply remember to use code similar to the following instead: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something to filter + $self->SUPER::start_element($data); # GOOD (and easy) ! + } + +This way, once you've done your job you hand the ball back to +XML::SAX::Base and it takes care of all those problems for you! + +Note that the above example doesn't apply to filters only, drivers +will benefit from the exact same feature. + +=head1 METHODS + +A number of methods are defined within this class for the purpose of +inheritance. Some probably don't need to be overridden (eg parse_file) +but some clearly should be (eg parse). Options for these methods are +described in the PerlSAX2 specification available from +http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/perl-xml/libxml-perl/doc/sax-2.0.html?rev=HEAD&content-type=text/html. + +=over 4 + +=item * parse + +The parse method is the main entry point to parsing documents. Internally +the parse method will detect what type of "thing" you are parsing, and +call the appropriate method in your implementation class. Here is the +mapping table of what is in the Source options (see the Perl SAX 2.0 +specification for the meaning of these values): + + Source Contains parse() calls + =============== ============= + CharacterStream (*) _parse_characterstream($stream, $options) + ByteStream _parse_bytestream($stream, $options) + String _parse_string($string, $options) + SystemId _parse_systemid($string, $options) + +However note that these methods may not be sensible if your driver class +is not for parsing XML. An example might be a DBI driver that generates +XML/SAX from a database table. If that is the case, you likely want to +write your own parse() method. + +Also note that the Source may contain both a PublicId entry, and an +Encoding entry. To get at these, examine $options->{Source} as passed +to your method. + +(*) A CharacterStream is a filehandle that does not need any encoding +translation done on it. This is implemented as a regular filehandle +and only works under Perl 5.7.2 or higher using PerlIO. To get a single +character, or number of characters from it, use the perl core read() +function. To get a single byte from it (or number of bytes), you can +use sysread(). The encoding of the stream should be in the Encoding +entry for the Source. + +=item * parse_file, parse_uri, parse_string + +These are all convenience variations on parse(), and in fact simply +set up the options before calling it. You probably don't need to +override these. + +=item * get_options + +This is a convenience method to get options in SAX2 style, or more +generically either as hashes or as hashrefs (it returns a hashref). +You will probably want to use this method in your own implementations +of parse() and of new(). + +=item * get_feature, set_feature + +These simply get and set features, and throw the +appropriate exceptions defined in the specification if need be. + +If your subclass defines features not defined in this one, +then you should override these methods in such a way that they check for +your features first, and then call the base class's methods +for features not defined by your class. An example would be: + + sub get_feature { + my $self = shift; + my $feat = shift; + if (exists $MY_FEATURES{$feat}) { + # handle the feature in various ways + } + else { + return $self->SUPER::get_feature($feat); + } + } + +Currently this part is unimplemented. + + +=item * set_handler + +This method takes a handler type (Handler, ContentHandler, etc.) and a +handler object as arguments, and changes the current handler for that +handler type, while taking care of resetting the internal state that +needs to be reset. This allows one to change a handler during parse +without running into problems (changing it on the parser object +directly will most likely cause trouble). + +=item * set_document_handler, set_content_handler, set_dtd_handler, set_lexical_handler, set_decl_handler, set_error_handler, set_entity_resolver + +These are just simple wrappers around the former method, and take a +handler object as their argument. Internally they simply call +set_handler with the correct arguments. + +=item * get_handler + +The inverse of set_handler, this method takes a an optional string containing a handler type (DTDHandler, +ContentHandler, etc. 'Handler' is used if no type is passed). It returns a reference to the object that implements +that class, or undef if that handler type is not set for the current driver/filter. + +=item * get_document_handler, get_content_handler, get_dtd_handler, get_lexical_handler, get_decl_handler, +get_error_handler, get_entity_resolver + +These are just simple wrappers around the get_handler() method, and take no arguments. Internally +they simply call get_handler with the correct handler type name. + +=back + +It would be rather useless to describe all the methods that this +module implements here. They are all the methods supported in SAX1 and +SAX2. In case your memory is a little short, here is a list. The +apparent duplicates are there so that both versions of SAX can be +supported. + +=over 4 + +=item * start_document + +=item * end_document + +=item * start_element + +=item * start_document + +=item * end_document + +=item * start_element + +=item * end_element + +=item * characters + +=item * processing_instruction + +=item * ignorable_whitespace + +=item * set_document_locator + +=item * start_prefix_mapping + +=item * end_prefix_mapping + +=item * skipped_entity + +=item * start_cdata + +=item * end_cdata + +=item * comment + +=item * entity_reference + +=item * notation_decl + +=item * unparsed_entity_decl + +=item * element_decl + +=item * attlist_decl + +=item * doctype_decl + +=item * xml_decl + +=item * entity_decl + +=item * attribute_decl + +=item * internal_entity_decl + +=item * external_entity_decl + +=item * resolve_entity + +=item * start_dtd + +=item * end_dtd + +=item * start_entity + +=item * end_entity + +=item * warning + +=item * error + +=item * fatal_error + +=back + +=head1 TODO + + - more tests + - conform to the "SAX Filters" and "Java and DOM compatibility" + sections of the SAX2 document. + +=head1 AUTHOR + +Kip Hampton (khampton@totalcinema.com) did most of the work, after porting +it from XML::Filter::Base. + +Robin Berjon (robin@knowscape.com) pitched in with patches to make it +usable as a base for drivers as well as filters, along with other patches. + +Matt Sergeant (matt@sergeant.org) wrote the original XML::Filter::Base, +and patched a few things here and there, and imported it into +the XML::SAX distribution. + +=head1 SEE ALSO + +L + +=cut + +FOOTER + + + return $code; +} + + +sub write_xml_sax_base { + confirm_forced_update(); + + my $path = File::Spec->catfile("lib", "XML", "SAX", "Base.pm"); + save_original_xml_sax_base($path); + + my $code = build_xml_sax_base(); + $code = add_version_stanzas($code); + + open my $fh, ">", $path or die "Cannot write $path: $!"; + print $fh $code; + close $fh or die "Error writing $path: $!"; + print "Wrote $path\n"; +} + + +sub confirm_forced_update { + return if grep { $_ eq '--force' } @ARGV; + + print <<'EOF'; +*** WARNING *** + +The BuildSAXBase.pl script is used to generate the lib/XML/SAX/Base.pm file. +However a pre-generated version of Base.pm is included in the distribution +so you do not need to run this script unless you intend to modify the code. + +You must use the --force option to deliberately overwrite the distributed +version of lib/XML/SAX/Base.pm + +EOF + + exit; +} + + +sub save_original_xml_sax_base { + my($path) = @_; + + return unless -e $path; + (my $save_path = $path) =~ s{Base}{Base-orig}; + return if -e $save_path; + print "Saving $path to $save_path\n"; + rename($path, $save_path); +} + + +sub add_version_stanzas { + my($code) = @_; + + my $version = get_xml_sax_base_version(); + $code =~ s<^(package\s+(\w[:\w]+).*?\n)> + <${1}BEGIN {\n \$${2}::VERSION = '$version';\n}\n>mg; + return $code; +} + + +sub get_xml_sax_base_version { + open my $fh, '<', 'dist.ini' or die "open() { + m{^\s*version\s*=\s*(\S+)} && return $1; + } + die "Failed to find version in dist.ini"; +} + diff --git a/Changes b/Changes new file mode 100644 index 0000000..7328c77 --- /dev/null +++ b/Changes @@ -0,0 +1,88 @@ +Revision history for Perl extension XML::SAX::Base. + +1.09 2017-04-03 21:00:06+12:00 Pacific/Auckland + - fix test suite to work without '.' in @INC (RT#120435, pull request + from James E Keenan) + +1.08 2011-09-14 20:37:39 Pacific/Auckland + - rename BuildSAXBase.PL => BuildSAXBase.pl + - add link to Perl SAX API Reference + +1.07 2011-09-10 11:35:27 Pacific/Auckland + - modify BuildSAXBase.PL to include version stanzas when run manually + - make BuildSAXBase.PL harmless unless run with --force option + +1.06 2011-09-08 23:10:25 Pacific/Auckland + - switch distribution to use Dist::Zilla for packaging + - generate XML/SAX/Base.pm at release time rather than install + - don't generate XML/SAX/Exception at all - it's static + - add git repo to metadata + +1.05 Mon Sep 05 2011 + - Re-released separately from XML-SAX distribution + - tweak to suppress benign warning (released 2007-02-08 as part of XML-SAX 0.15) + +1.04 Mon Apr 28 23:56:33 2001 + - plugged major memory leak (thanks to Richard Titmuss for the catch and Matt Sergeant for the patch). + - added get_handler method (and friends). + - added to test suite + +1.03 Mon Jan 21 2002 + - set namespaces feature on by default as per SAX spec + +1.02 Fri Nov 30 2001 + - implemented get/set_feature in terms of supported_features + +1.01 Mon Nov 26 01:56:33 2001 + - added set_handler method (and friends). + - added to test suite + +1.00 Tue Nov 20 01:01:22 2001 + - created standalone 1.0 distribution. + +0.22 Tue Oct 30 18:54:03 2001 + - changed the name to reflect the fact that this is really + a base class for any kind of SAX Driver (Fitlers being only + a specific case of Drivers). + - added some more SAX2 compatibility options + + +0.19 - 0.21 Sun Oct 14 11:06:23 2001 + - Major architectural changes. + - Base now uses an agressive method caching strategy + in which the various possible handler classes are + explicity checked (via 'can') for a method implementation. + Failing that, the classes are examined for an + 'AUTOLOAD' sub and the given method is called directly + on that class-- if that call dies for a reason other + "Can't find object method 'foo'" the error is propigated. + If an appropriate method is found, the coderef cached + in the instance's 'Methods' HASH + ($self->{Methods}->{$method_name}) which is used for + subsequent calls to that method. + +0.17 - Fri Oct 12 23:43 2001 + - More clean-up. + +0.15 Mon Oct 08 18:12:33 2001 + - added 'autogen.pl' to generate Base.pm offline + rather than building subs at compile time. + - fixed 'dangling $@' that was causing parse to die + in undesirable cases because, although the module was + rightly skipping over cases where a handler method + was not implemented, $@ was still set globally and + causing problems further up the food-chain. + *pizzas welcome* ;-> + +0.11 Sat Oct 06 21:08:42 2001 + - modifications by Robin Berjon to provide full SAX1 and + SAX2 support, along with proper handler defaulting and + dispatching. + +0.10 Sat Sep 01 08:53:42 2001 + - patches by Kip Hampton to avoid throwing events that + aren't defined + +0.01 Fri May 18 16:26:33 2001 + - original version; created by h2xs 1.19 + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..86ddde1 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,31 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.022. +BuildSAXBase.pl +Changes +MANIFEST +META.json +META.yml +Makefile.PL +README +dist.ini +lib/XML/SAX/Base.pm +lib/XML/SAX/Exception.pm +t/00basic.t +t/01exception.t +t/01simpledriver.t +t/02simplefilter.t +t/03chdriver.t +t/04chfilter.t +t/05dtdhdriver.t +t/06lexhdriver.t +t/07declhdriver.t +t/08errorhdriver.t +t/09resoldriver.t +t/10dochdriver.t +t/11sax1multiclass.t +t/12sax2multiclass.t +t/13handlerswitch.t +t/14downstreamswitch.t +t/15parentswitch.t +t/16gethandlers.t +t/events.pl +t/release-pod-syntax.t diff --git a/META.json b/META.json new file mode 100644 index 0000000..1b00fe7 --- /dev/null +++ b/META.json @@ -0,0 +1,48 @@ +{ + "abstract" : "Base class for SAX Drivers and Filters", + "author" : [ + "Grant McLean " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 5.022, CPAN::Meta::Converter version 2.142690", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "XML-SAX-Base", + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "develop" : { + "requires" : { + "Test::Pod" : "1.41" + } + }, + "runtime" : { + "requires" : { + "perl" : "5.008" + } + }, + "test" : { + "requires" : { + "Test::More" : "0.88" + } + } + }, + "release_status" : "stable", + "resources" : { + "repository" : { + "type" : "git", + "url" : "git://github.com/grantm/XML-SAX-Base.git", + "web" : "https://github.com/grantm/XML-SAX-Base" + } + }, + "version" : "1.09" +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..ae90148 --- /dev/null +++ b/META.yml @@ -0,0 +1,20 @@ +--- +abstract: 'Base class for SAX Drivers and Filters' +author: + - 'Grant McLean ' +build_requires: + Test::More: 0.88 +configure_requires: + ExtUtils::MakeMaker: 0 +dynamic_config: 0 +generated_by: 'Dist::Zilla version 5.022, CPAN::Meta::Converter version 2.142690' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: XML-SAX-Base +requires: + perl: 5.008 +resources: + repository: git://github.com/grantm/XML-SAX-Base.git +version: 1.09 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..6b93e7a --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,52 @@ + +# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.022. +use strict; +use warnings; + +use 5.008; + +use ExtUtils::MakeMaker; + + + +my %WriteMakefileArgs = ( + "ABSTRACT" => "Base class for SAX Drivers and Filters", + "AUTHOR" => "Grant McLean ", + "CONFIGURE_REQUIRES" => { + "ExtUtils::MakeMaker" => 0 + }, + "DISTNAME" => "XML-SAX-Base", + "EXE_FILES" => [], + "LICENSE" => "perl", + "MIN_PERL_VERSION" => "5.008", + "NAME" => "XML::SAX::Base", + "PREREQ_PM" => {}, + "TEST_REQUIRES" => { + "Test::More" => "0.88" + }, + "VERSION" => "1.09", + "test" => { + "TESTS" => "t/*.t" + } +); + + +my %FallbackPrereqs = ( + "ExtUtils::MakeMaker" => 0, + "Test::More" => "0.88" +); + + +unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { + delete $WriteMakefileArgs{TEST_REQUIRES}; + delete $WriteMakefileArgs{BUILD_REQUIRES}; + $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; +} + +delete $WriteMakefileArgs{CONFIGURE_REQUIRES} + unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; + +WriteMakefile(%WriteMakefileArgs); + + + diff --git a/README b/README new file mode 100644 index 0000000..9819245 --- /dev/null +++ b/README @@ -0,0 +1,289 @@ +XML::SAX::Base is intended for use as a base class for SAX filter modules +and XML parsers generating SAX events. + +If you simply wish to build a SAX handler class to 'consume' SAX events you +do not need to use XML::SAX::Base directly although you will need to install +XML::SAX. + +This module used to be distributed as part of the XML:SAX distribution but +is now distributed separately and referenced as a dependency by XML::SAX. + +INSTALLATION: + +via tarball: + +% tar -zxvf XML-SAX-Base-xxx.tar.gz +% perl Makefile.PL +% make && make test +% make install + +via CPAN shell: + +% perl -MCPAN -e shell +% install XML::SAX::Base + +The rest of this file consists of the fine XML::SAX::Base documentation +contributed by Robin Berjon. + +Enjoy! + +=head1 NAME + +XML::SAX::Base - Base class SAX Drivers and Filters + +=head1 SYNOPSIS + + package MyFilter; + use XML::SAX::Base; + @ISA = ('XML::SAX::Base'); + +=head1 DESCRIPTION + +This module has a very simple task - to be a base class for PerlSAX +drivers and filters. It's default behaviour is to pass the input directly +to the output unchanged. It can be useful to use this module as a base class +so you don't have to, for example, implement the characters() callback. + +The main advantages that it provides are easy dispatching of events the right +way (ie it takes care for you of checking that the handler has implemented +that method, or has defined an AUTOLOAD), and the guarantee that filters +will pass along events that they aren't implementing to handlers downstream +that might nevertheless be interested in them. + +=head1 WRITING SAX DRIVERS AND FILTERS + +The Perl Sax API Reference is at L. + +Writing SAX Filters is tremendously easy: all you need to do is +inherit from this module, and define the events you want to handle. A +more detailed explanation can be found at +http://www.xml.com/pub/a/2001/10/10/sax-filters.html. + +Writing Drivers is equally simple. The one thing you need to pay +attention to is B to call events yourself (this applies to Filters +as well). For instance: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something + $self->{Handler}->start_element($data); # BAD + } + +The above example works well as precisely that: an example. But it has +several faults: 1) it doesn't test to see whether the handler defines +start_element. Perhaps it doesn't want to see that event, in which +case you shouldn't throw it (otherwise it'll die). 2) it doesn't check +ContentHandler and then Handler (ie it doesn't look to see that the +user hasn't requested events on a specific handler, and if not on the +default one), 3) if it did check all that, not only would the code be +cumbersome (see this module's source to get an idea) but it would also +probably have to check for a DocumentHandler (in case this were SAX1) +and for AUTOLOADs potentially defined in all these packages. As you can +tell, that would be fairly painful. Instead of going through that, +simply remember to use code similar to the following instead: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something to filter + $self->SUPER::start_element($data); # GOOD (and easy) ! + } + +This way, once you've done your job you hand the ball back to +XML::SAX::Base and it takes care of all those problems for you! + +Note that the above example doesn't apply to filters only, drivers +will benefit from the exact same feature. + +=head1 METHODS + +A number of methods are defined within this class for the purpose of +inheritance. Some probably don't need to be overridden (eg parse_file) +but some clearly should be (eg parse). Options for these methods are +described in the PerlSAX2 specification available from +http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/perl-xml/libxml-perl/doc/sax-2.0.html?rev=HEAD&content-type=text/html. + +=over 4 + +=item * parse + +The parse method is the main entry point to parsing documents. Internally +the parse method will detect what type of "thing" you are parsing, and +call the appropriate method in your implementation class. Here is the +mapping table of what is in the Source options (see the Perl SAX 2.0 +specification for the meaning of these values): + + Source Contains parse() calls + =============== ============= + CharacterStream (*) _parse_characterstream($stream, $options) + ByteStream _parse_bytestream($stream, $options) + String _parse_string($string, $options) + SystemId _parse_systemid($string, $options) + +However note that these methods may not be sensible if your driver class +is not for parsing XML. An example might be a DBI driver that generates +XML/SAX from a database table. If that is the case, you likely want to +write your own parse() method. + +Also note that the Source may contain both a PublicId entry, and an +Encoding entry. To get at these, examine $options->{Source} as passed +to your method. + +(*) A CharacterStream is a filehandle that does not need any encoding +translation done on it. This is implemented as a regular filehandle +and only works under Perl 5.7.2 or higher using PerlIO. To get a single +character, or number of characters from it, use the perl core read() +function. To get a single byte from it (or number of bytes), you can +use sysread(). The encoding of the stream should be in the Encoding +entry for the Source. + +=item * parse_file, parse_uri, parse_string + +These are all convenience variations on parse(), and in fact simply +set up the options before calling it. You probably don't need to +override these. + +=item * get_options + +This is a convenience method to get options in SAX2 style, or more +generically either as hashes or as hashrefs (it returns a hashref). +You will probably want to use this method in your own implementations +of parse() and of new(). + +=item * get_feature, set_feature + +These simply get and set features, and throw the +appropriate exceptions defined in the specification if need be. + +If your subclass defines features not defined in this one, +then you should override these methods in such a way that they check for +your features first, and then call the base class's methods +for features not defined by your class. An example would be: + + sub get_feature { + my $self = shift; + my $feat = shift; + if (exists $MY_FEATURES{$feat}) { + # handle the feature in various ways + } + else { + return $self->SUPER::get_feature($feat); + } + } + +Currently this part is unimplemented. + +=back + +It would be rather useless to describe all the methods that this +module implements here. They are all the methods supported in SAX1 and +SAX2. In case your memory is a little short, here is a list. The +apparent duplicates are there so that both versions of SAX can be +supported. + +=over 4 + +=item * start_document + +=item * end_document + +=item * start_element + +=item * start_document + +=item * end_document + +=item * start_element + +=item * end_element + +=item * characters + +=item * processing_instruction + +=item * ignorable_whitespace + +=item * set_document_locator + +=item * start_prefix_mapping + +=item * end_prefix_mapping + +=item * skipped_entity + +=item * start_cdata + +=item * end_cdata + +=item * comment + +=item * entity_reference + +=item * notation_decl + +=item * unparsed_entity_decl + +=item * element_decl + +=item * attlist_decl + +=item * doctype_decl + +=item * xml_decl + +=item * entity_decl + +=item * attribute_decl + +=item * internal_entity_decl + +=item * external_entity_decl + +=item * resolve_entity + +=item * start_dtd + +=item * end_dtd + +=item * start_entity + +=item * end_entity + +=item * warning + +=item * error + +=item * fatal_error + +=back + +=head1 TODO + + - more tests + - conform to the "SAX Filters" and "Java and DOM compatibility" + sections of the SAX2 document. + +=head1 AUTHOR + +Kip Hampton (khampton@totalcinema.com) did most of the work, after porting +it from XML::Filter::Base. + +Robin Berjon (robin@knowscape.com) pitched in with patches to make it +usable as a base for drivers as well as filters, along with other patches. + +Matt Sergeant (matt@sergeant.org) wrote the original XML::Filter::Base, +and patched a few things here and there, and imported it into +the XML::SAX distribution. + +=head1 SEE ALSO + +L + +=cut diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..23c75d4 --- /dev/null +++ b/dist.ini @@ -0,0 +1,33 @@ +name = XML-SAX-Base +author = Grant McLean +license = Perl_5 +copyright_holder = Grant McLean +copyright_year = 2011 +main_module = lib/XML/SAX/Base.pm +abstract = Base class for SAX Drivers and Filters +repository = git://github.com/grantm/XML-SAX-Base.git + +version = 1.09 + +[Repository] +[NextRelease] +[PodSyntaxTests] +[MetaJSON] +[MetaYAML] +[PkgVersion] +[@Git] + +[BuildSAXBase] + +[@Filter] +-bundle = @Basic +-remove = Readme +-remove = License +-remove = MetaYAML + +[Prereqs] +perl = 5.008 + +[Prereqs / TestRequires] +Test::More = 0.88 + diff --git a/lib/XML/SAX/Base.pm b/lib/XML/SAX/Base.pm new file mode 100644 index 0000000..0ffb703 --- /dev/null +++ b/lib/XML/SAX/Base.pm @@ -0,0 +1,3170 @@ +package XML::SAX::Base; +$XML::SAX::Base::VERSION = '1.09'; +# version 0.10 - Kip Hampton +# version 0.13 - Robin Berjon +# version 0.15 - Kip Hampton +# version 0.17 - Kip Hampton +# version 0.19 - Kip Hampton +# version 0.21 - Kip Hampton +# version 0.22 - Robin Berjon +# version 0.23 - Matt Sergeant +# version 0.24 - Robin Berjon +# version 0.25 - Kip Hampton +# version 1.00 - Kip Hampton +# version 1.01 - Kip Hampton +# version 1.02 - Robin Berjon +# version 1.03 - Matt Sergeant +# version 1.04 - Kip Hampton +# version 1.05 - Grant McLean +# version 1.06 - Grant McLean +# version 1.07 - Grant McLean +# version 1.08 - Grant McLean + +#-----------------------------------------------------# +# STOP!!!!! +# +# This file is generated by the 'BuildSAXBase.pl' file +# that ships with the XML::SAX::Base distribution. +# If you need to make changes, patch that file NOT +# XML/SAX/Base.pm Better yet, fork the git repository +# commit your changes and send a pull request: +# https://github.com/grantm/XML-SAX-Base +#-----------------------------------------------------# + +use strict; + +use XML::SAX::Exception qw(); + +sub end_entity { + my $self = shift; + if (defined $self->{Methods}->{'end_entity'}) { + $self->{Methods}->{'end_entity'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_entity') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_entity') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->end_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_entity'} = sub { $handler->end_entity(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_entity'} = sub { $handler->end_entity(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_entity'} = sub { }; + } + } + +} + +sub set_document_locator { + my $self = shift; + if (defined $self->{Methods}->{'set_document_locator'}) { + $self->{Methods}->{'set_document_locator'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('set_document_locator') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('set_document_locator') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('set_document_locator') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'set_document_locator'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->set_document_locator(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->set_document_locator(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->set_document_locator(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'set_document_locator'} = sub { $handler->set_document_locator(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'set_document_locator'} = sub { }; + } + } + +} + +sub notation_decl { + my $self = shift; + if (defined $self->{Methods}->{'notation_decl'}) { + $self->{Methods}->{'notation_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('notation_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'notation_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('notation_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'notation_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->notation_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'notation_decl'} = sub { $handler->notation_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->notation_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'notation_decl'} = sub { $handler->notation_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'notation_decl'} = sub { }; + } + } + +} + +sub attlist_decl { + my $self = shift; + if (defined $self->{Methods}->{'attlist_decl'}) { + $self->{Methods}->{'attlist_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('attlist_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'attlist_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('attlist_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'attlist_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->attlist_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'attlist_decl'} = sub { $handler->attlist_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->attlist_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'attlist_decl'} = sub { $handler->attlist_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'attlist_decl'} = sub { }; + } + } + +} + +sub fatal_error { + my $self = shift; + if (defined $self->{Methods}->{'fatal_error'}) { + $self->{Methods}->{'fatal_error'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('fatal_error') ) { + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'fatal_error'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('fatal_error') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'fatal_error'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ErrorHandler'} + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ErrorHandler'}->fatal_error(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'fatal_error'} = sub { $handler->fatal_error(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->fatal_error(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'fatal_error'} = sub { $handler->fatal_error(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'fatal_error'} = sub { }; + } + } + +} + +sub start_document { + my $self = shift; + if (defined $self->{Methods}->{'start_document'}) { + $self->{Methods}->{'start_document'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_document') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_document') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_document') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->start_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->start_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_document'} = sub { $handler->start_document(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_document'} = sub { }; + } + } + +} + +sub warning { + my $self = shift; + if (defined $self->{Methods}->{'warning'}) { + $self->{Methods}->{'warning'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('warning') ) { + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'warning'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('warning') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'warning'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ErrorHandler'} + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ErrorHandler'}->warning(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'warning'} = sub { $handler->warning(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->warning(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'warning'} = sub { $handler->warning(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'warning'} = sub { }; + } + } + +} + +sub ignorable_whitespace { + my $self = shift; + if (defined $self->{Methods}->{'ignorable_whitespace'}) { + $self->{Methods}->{'ignorable_whitespace'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('ignorable_whitespace') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('ignorable_whitespace') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('ignorable_whitespace') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->ignorable_whitespace(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->ignorable_whitespace(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->ignorable_whitespace(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'ignorable_whitespace'} = sub { $handler->ignorable_whitespace(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'ignorable_whitespace'} = sub { }; + } + } + +} + +sub resolve_entity { + my $self = shift; + if (defined $self->{Methods}->{'resolve_entity'}) { + $self->{Methods}->{'resolve_entity'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'EntityResolver'} and $method = $callbacks->{'EntityResolver'}->can('resolve_entity') ) { + my $handler = $callbacks->{'EntityResolver'}; + $self->{Methods}->{'resolve_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('resolve_entity') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'resolve_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'EntityResolver'} + and $callbacks->{'EntityResolver'}->can('AUTOLOAD') + and $callbacks->{'EntityResolver'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'EntityResolver'}->resolve_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'EntityResolver'}; + $self->{Methods}->{'resolve_entity'} = sub { $handler->resolve_entity(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->resolve_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'resolve_entity'} = sub { $handler->resolve_entity(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'resolve_entity'} = sub { }; + } + } + +} + +sub external_entity_decl { + my $self = shift; + if (defined $self->{Methods}->{'external_entity_decl'}) { + $self->{Methods}->{'external_entity_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('external_entity_decl') ) { + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'external_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('external_entity_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'external_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DeclHandler'} + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DeclHandler'}->external_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'external_entity_decl'} = sub { $handler->external_entity_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->external_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'external_entity_decl'} = sub { $handler->external_entity_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'external_entity_decl'} = sub { }; + } + } + +} + +sub entity_reference { + my $self = shift; + if (defined $self->{Methods}->{'entity_reference'}) { + $self->{Methods}->{'entity_reference'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('entity_reference') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'entity_reference'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('entity_reference') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'entity_reference'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->entity_reference(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'entity_reference'} = sub { $handler->entity_reference(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->entity_reference(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'entity_reference'} = sub { $handler->entity_reference(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'entity_reference'} = sub { }; + } + } + +} + +sub start_entity { + my $self = shift; + if (defined $self->{Methods}->{'start_entity'}) { + $self->{Methods}->{'start_entity'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_entity') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_entity') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->start_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_entity'} = sub { $handler->start_entity(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_entity'} = sub { $handler->start_entity(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_entity'} = sub { }; + } + } + +} + +sub end_dtd { + my $self = shift; + if (defined $self->{Methods}->{'end_dtd'}) { + $self->{Methods}->{'end_dtd'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_dtd') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_dtd'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_dtd') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_dtd'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->end_dtd(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_dtd'} = sub { $handler->end_dtd(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_dtd(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_dtd'} = sub { $handler->end_dtd(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_dtd'} = sub { }; + } + } + +} + +sub element_decl { + my $self = shift; + if (defined $self->{Methods}->{'element_decl'}) { + $self->{Methods}->{'element_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('element_decl') ) { + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'element_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('element_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'element_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DeclHandler'} + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DeclHandler'}->element_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'element_decl'} = sub { $handler->element_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->element_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'element_decl'} = sub { $handler->element_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'element_decl'} = sub { }; + } + } + +} + +sub start_element { + my $self = shift; + if (defined $self->{Methods}->{'start_element'}) { + $self->{Methods}->{'start_element'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_element') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_element') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_element') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->start_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->start_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_element'} = sub { $handler->start_element(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_element'} = sub { }; + } + } + +} + +sub error { + my $self = shift; + if (defined $self->{Methods}->{'error'}) { + $self->{Methods}->{'error'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ErrorHandler'} and $method = $callbacks->{'ErrorHandler'}->can('error') ) { + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'error'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('error') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'error'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ErrorHandler'} + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') + and $callbacks->{'ErrorHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ErrorHandler'}->error(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ErrorHandler'}; + $self->{Methods}->{'error'} = sub { $handler->error(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->error(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'error'} = sub { $handler->error(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'error'} = sub { }; + } + } + +} + +sub xml_decl { + my $self = shift; + if (defined $self->{Methods}->{'xml_decl'}) { + $self->{Methods}->{'xml_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('xml_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'xml_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('xml_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'xml_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->xml_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'xml_decl'} = sub { $handler->xml_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->xml_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'xml_decl'} = sub { $handler->xml_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'xml_decl'} = sub { }; + } + } + +} + +sub end_document { + my $self = shift; + if (defined $self->{Methods}->{'end_document'}) { + $self->{Methods}->{'end_document'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_document') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_document') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_document') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_document'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->end_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->end_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_document(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_document'} = sub { $handler->end_document(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_document'} = sub { }; + } + } + +} + +sub attribute_decl { + my $self = shift; + if (defined $self->{Methods}->{'attribute_decl'}) { + $self->{Methods}->{'attribute_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('attribute_decl') ) { + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'attribute_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('attribute_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'attribute_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DeclHandler'} + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DeclHandler'}->attribute_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'attribute_decl'} = sub { $handler->attribute_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->attribute_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'attribute_decl'} = sub { $handler->attribute_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'attribute_decl'} = sub { }; + } + } + +} + +sub internal_entity_decl { + my $self = shift; + if (defined $self->{Methods}->{'internal_entity_decl'}) { + $self->{Methods}->{'internal_entity_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DeclHandler'} and $method = $callbacks->{'DeclHandler'}->can('internal_entity_decl') ) { + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'internal_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('internal_entity_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'internal_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DeclHandler'} + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') + and $callbacks->{'DeclHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DeclHandler'}->internal_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DeclHandler'}; + $self->{Methods}->{'internal_entity_decl'} = sub { $handler->internal_entity_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->internal_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'internal_entity_decl'} = sub { $handler->internal_entity_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'internal_entity_decl'} = sub { }; + } + } + +} + +sub doctype_decl { + my $self = shift; + if (defined $self->{Methods}->{'doctype_decl'}) { + $self->{Methods}->{'doctype_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('doctype_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'doctype_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('doctype_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'doctype_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->doctype_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'doctype_decl'} = sub { $handler->doctype_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->doctype_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'doctype_decl'} = sub { $handler->doctype_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'doctype_decl'} = sub { }; + } + } + +} + +sub unparsed_entity_decl { + my $self = shift; + if (defined $self->{Methods}->{'unparsed_entity_decl'}) { + $self->{Methods}->{'unparsed_entity_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('unparsed_entity_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'unparsed_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('unparsed_entity_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'unparsed_entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->unparsed_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'unparsed_entity_decl'} = sub { $handler->unparsed_entity_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->unparsed_entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'unparsed_entity_decl'} = sub { $handler->unparsed_entity_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'unparsed_entity_decl'} = sub { }; + } + } + +} + +sub skipped_entity { + my $self = shift; + if (defined $self->{Methods}->{'skipped_entity'}) { + $self->{Methods}->{'skipped_entity'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('skipped_entity') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'skipped_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('skipped_entity') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'skipped_entity'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->skipped_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'skipped_entity'} = sub { $handler->skipped_entity(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->skipped_entity(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'skipped_entity'} = sub { $handler->skipped_entity(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'skipped_entity'} = sub { }; + } + } + +} + +sub end_prefix_mapping { + my $self = shift; + if (defined $self->{Methods}->{'end_prefix_mapping'}) { + $self->{Methods}->{'end_prefix_mapping'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_prefix_mapping') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_prefix_mapping'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_prefix_mapping') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_prefix_mapping'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->end_prefix_mapping(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_prefix_mapping'} = sub { $handler->end_prefix_mapping(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_prefix_mapping(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_prefix_mapping'} = sub { $handler->end_prefix_mapping(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_prefix_mapping'} = sub { }; + } + } + +} + +sub characters { + my $self = shift; + if (defined $self->{Methods}->{'characters'}) { + $self->{Methods}->{'characters'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('characters') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'characters'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('characters') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'characters'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('characters') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'characters'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->characters(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'characters'} = sub { $handler->characters(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->characters(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'characters'} = sub { $handler->characters(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->characters(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'characters'} = sub { $handler->characters(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'characters'} = sub { }; + } + } + +} + +sub comment { + my $self = shift; + if (defined $self->{Methods}->{'comment'}) { + $self->{Methods}->{'comment'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('comment') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'comment'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('comment') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'comment'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('comment') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'comment'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->comment(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'comment'} = sub { $handler->comment(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->comment(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'comment'} = sub { $handler->comment(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->comment(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'comment'} = sub { $handler->comment(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'comment'} = sub { }; + } + } + +} + +sub start_dtd { + my $self = shift; + if (defined $self->{Methods}->{'start_dtd'}) { + $self->{Methods}->{'start_dtd'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_dtd') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_dtd'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_dtd') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_dtd'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->start_dtd(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_dtd'} = sub { $handler->start_dtd(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_dtd(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_dtd'} = sub { $handler->start_dtd(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_dtd'} = sub { }; + } + } + +} + +sub entity_decl { + my $self = shift; + if (defined $self->{Methods}->{'entity_decl'}) { + $self->{Methods}->{'entity_decl'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DTDHandler'} and $method = $callbacks->{'DTDHandler'}->can('entity_decl') ) { + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('entity_decl') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'entity_decl'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DTDHandler'} + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') + and $callbacks->{'DTDHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DTDHandler'}->entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DTDHandler'}; + $self->{Methods}->{'entity_decl'} = sub { $handler->entity_decl(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->entity_decl(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'entity_decl'} = sub { $handler->entity_decl(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'entity_decl'} = sub { }; + } + } + +} + +sub start_prefix_mapping { + my $self = shift; + if (defined $self->{Methods}->{'start_prefix_mapping'}) { + $self->{Methods}->{'start_prefix_mapping'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('start_prefix_mapping') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_prefix_mapping'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_prefix_mapping') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_prefix_mapping'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->start_prefix_mapping(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'start_prefix_mapping'} = sub { $handler->start_prefix_mapping(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_prefix_mapping(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_prefix_mapping'} = sub { $handler->start_prefix_mapping(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_prefix_mapping'} = sub { }; + } + } + +} + +sub end_cdata { + my $self = shift; + if (defined $self->{Methods}->{'end_cdata'}) { + $self->{Methods}->{'end_cdata'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_cdata') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('end_cdata') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_cdata') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->end_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->end_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_cdata'} = sub { $handler->end_cdata(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_cdata'} = sub { }; + } + } + +} + +sub processing_instruction { + my $self = shift; + if (defined $self->{Methods}->{'processing_instruction'}) { + $self->{Methods}->{'processing_instruction'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('processing_instruction') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('processing_instruction') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('processing_instruction') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'processing_instruction'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->processing_instruction(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->processing_instruction(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->processing_instruction(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'processing_instruction'} = sub { $handler->processing_instruction(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'processing_instruction'} = sub { }; + } + } + +} + +sub end_element { + my $self = shift; + if (defined $self->{Methods}->{'end_element'}) { + $self->{Methods}->{'end_element'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'ContentHandler'} and $method = $callbacks->{'ContentHandler'}->can('end_element') ) { + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('end_element') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('end_element') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_element'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'ContentHandler'} + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') + and $callbacks->{'ContentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'ContentHandler'}->end_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'ContentHandler'}; + $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->end_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->end_element(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'end_element'} = sub { $handler->end_element(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'end_element'} = sub { }; + } + } + +} + +sub start_cdata { + my $self = shift; + if (defined $self->{Methods}->{'start_cdata'}) { + $self->{Methods}->{'start_cdata'}->(@_); + } + else { + my $method; + my $callbacks; + if (exists $self->{ParseOptions}) { + $callbacks = $self->{ParseOptions}; + } + else { + $callbacks = $self; + } + if (0) { # dummy to make elsif's below compile + } + elsif (defined $callbacks->{'DocumentHandler'} and $method = $callbacks->{'DocumentHandler'}->can('start_cdata') ) { + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'LexicalHandler'} and $method = $callbacks->{'LexicalHandler'}->can('start_cdata') ) { + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('start_cdata') ) { + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_cdata'} = sub { $method->($handler, @_) }; + return $method->($handler, @_); + } + elsif (defined $callbacks->{'DocumentHandler'} + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') + and $callbacks->{'DocumentHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'DocumentHandler'}->start_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'DocumentHandler'}; + $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'LexicalHandler'} + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') + and $callbacks->{'LexicalHandler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'LexicalHandler'}->start_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'LexicalHandler'}; + $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) }; + } + return $res; + } + elsif (defined $callbacks->{'Handler'} + and $callbacks->{'Handler'}->can('AUTOLOAD') + and $callbacks->{'Handler'}->can('AUTOLOAD') ne (UNIVERSAL->can('AUTOLOAD') || '') + ) + { + my $res = eval { $callbacks->{'Handler'}->start_cdata(@_) }; + if ($@) { + die $@; + } + else { + # I think there's a buggette here... + # if the first call throws an exception, we don't set it up right. + # Not fatal, but we might want to address it. + my $handler = $callbacks->{'Handler'}; + $self->{Methods}->{'start_cdata'} = sub { $handler->start_cdata(@_) }; + } + return $res; + } + else { + $self->{Methods}->{'start_cdata'} = sub { }; + } + } + +} + +#-------------------------------------------------------------------# +# Class->new(%options) +#-------------------------------------------------------------------# +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $options = ($#_ == 0) ? shift : { @_ }; + + unless ( defined( $options->{Handler} ) or + defined( $options->{ContentHandler} ) or + defined( $options->{DTDHandler} ) or + defined( $options->{DocumentHandler} ) or + defined( $options->{LexicalHandler} ) or + defined( $options->{ErrorHandler} ) or + defined( $options->{DeclHandler} ) ) { + + $options->{Handler} = XML::SAX::Base::NoHandler->new; + } + + my $self = bless $options, $class; + # turn NS processing on by default + $self->set_feature('http://xml.org/sax/features/namespaces', 1); + return $self; +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse(%options) +#-------------------------------------------------------------------# +sub parse { + my $self = shift; + my $parse_options = $self->get_options(@_); + local $self->{ParseOptions} = $parse_options; + if ($self->{Parent}) { # calling parse on a filter for some reason + return $self->{Parent}->parse($parse_options); + } + else { + my $method; + if (defined $parse_options->{Source}{CharacterStream} and $method = $self->can('_parse_characterstream')) { + warn("parse charstream???\n"); + return $method->($self, $parse_options->{Source}{CharacterStream}); + } + elsif (defined $parse_options->{Source}{ByteStream} and $method = $self->can('_parse_bytestream')) { + return $method->($self, $parse_options->{Source}{ByteStream}); + } + elsif (defined $parse_options->{Source}{String} and $method = $self->can('_parse_string')) { + return $method->($self, $parse_options->{Source}{String}); + } + elsif (defined $parse_options->{Source}{SystemId} and $method = $self->can('_parse_systemid')) { + return $method->($self, $parse_options->{Source}{SystemId}); + } + else { + die "No _parse_* routine defined on this driver (If it is a filter, remember to set the Parent property. If you call the parse() method, make sure to set a Source. You may want to call parse_uri, parse_string or parse_file instead.) [$self]"; + } + } +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_file(%options) +#-------------------------------------------------------------------# +sub parse_file { + my $self = shift; + my $file = shift; + return $self->parse_uri($file, @_) if ref(\$file) eq 'SCALAR'; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{ByteStream} = $file; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_uri(%options) +#-------------------------------------------------------------------# +sub parse_uri { + my $self = shift; + my $file = shift; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{SystemId} = $file; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# $p->parse_string(%options) +#-------------------------------------------------------------------# +sub parse_string { + my $self = shift; + my $string = shift; + my $parse_options = $self->get_options(@_); + $parse_options->{Source}{String} = $string; + return $self->parse($parse_options); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_options +#-------------------------------------------------------------------# +sub get_options { + my $self = shift; + + if (@_ == 1) { + return { %$self, %{$_[0]} }; + } else { + return { %$self, @_ }; + } +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_features +#-------------------------------------------------------------------# +sub get_features { + return ( + 'http://xml.org/sax/features/external-general-entities' => undef, + 'http://xml.org/sax/features/external-parameter-entities' => undef, + 'http://xml.org/sax/features/is-standalone' => undef, + 'http://xml.org/sax/features/lexical-handler' => undef, + 'http://xml.org/sax/features/parameter-entities' => undef, + 'http://xml.org/sax/features/namespaces' => 1, + 'http://xml.org/sax/features/namespace-prefixes' => 0, + 'http://xml.org/sax/features/string-interning' => undef, + 'http://xml.org/sax/features/use-attributes2' => undef, + 'http://xml.org/sax/features/use-locator2' => undef, + 'http://xml.org/sax/features/validation' => undef, + + 'http://xml.org/sax/properties/dom-node' => undef, + 'http://xml.org/sax/properties/xml-string' => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_feature +#-------------------------------------------------------------------# +sub get_feature { + my $self = shift; + my $feat = shift; + + # check %FEATURES to see if it's there, and return it if so + # throw XML::SAX::Exception::NotRecognized if it's not there + # throw XML::SAX::Exception::NotSupported if it's there but we + # don't support it + + my %features = $self->get_features(); + if (exists $features{$feat}) { + my %supported = map { $_ => 1 } $self->supported_features(); + if ($supported{$feat}) { + return $self->{__PACKAGE__ . "::Features"}{$feat}; + } + throw XML::SAX::Exception::NotSupported( + Message => "The feature '$feat' is not supported by " . ref($self), + Exception => undef, + ); + } + throw XML::SAX::Exception::NotRecognized( + Message => "The feature '$feat' is not recognized by " . ref($self), + Exception => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# set_feature +#-------------------------------------------------------------------# +sub set_feature { + my $self = shift; + my $feat = shift; + my $value = shift; + # check %FEATURES to see if it's there, and set it if so + # throw XML::SAX::Exception::NotRecognized if it's not there + # throw XML::SAX::Exception::NotSupported if it's there but we + # don't support it + + my %features = $self->get_features(); + if (exists $features{$feat}) { + my %supported = map { $_ => 1 } $self->supported_features(); + if ($supported{$feat}) { + return $self->{__PACKAGE__ . "::Features"}{$feat} = $value; + } + throw XML::SAX::Exception::NotSupported( + Message => "The feature '$feat' is not supported by " . ref($self), + Exception => undef, + ); + } + throw XML::SAX::Exception::NotRecognized( + Message => "The feature '$feat' is not recognized by " . ref($self), + Exception => undef, + ); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# get_handler and friends +#-------------------------------------------------------------------# +sub get_handler { + my $self = shift; + my $handler_type = shift; + $handler_type ||= 'Handler'; + return defined( $self->{$handler_type} ) ? $self->{$handler_type} : undef; +} + +sub get_document_handler { + my $self = shift; + return $self->get_handler('DocumentHandler', @_); +} + +sub get_content_handler { + my $self = shift; + return $self->get_handler('ContentHandler', @_); +} + +sub get_dtd_handler { + my $self = shift; + return $self->get_handler('DTDHandler', @_); +} + +sub get_lexical_handler { + my $self = shift; + return $self->get_handler('LexicalHandler', @_); +} + +sub get_decl_handler { + my $self = shift; + return $self->get_handler('DeclHandler', @_); +} + +sub get_error_handler { + my $self = shift; + return $self->get_handler('ErrorHandler', @_); +} + +sub get_entity_resolver { + my $self = shift; + return $self->get_handler('EntityResolver', @_); +} +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# set_handler and friends +#-------------------------------------------------------------------# +sub set_handler { + my $self = shift; + my ($new_handler, $handler_type) = reverse @_; + $handler_type ||= 'Handler'; + $self->{Methods} = {} if $self->{Methods}; + $self->{$handler_type} = $new_handler; + $self->{ParseOptions}->{$handler_type} = $new_handler; + return 1; +} + +sub set_document_handler { + my $self = shift; + return $self->set_handler('DocumentHandler', @_); +} + +sub set_content_handler { + my $self = shift; + return $self->set_handler('ContentHandler', @_); +} +sub set_dtd_handler { + my $self = shift; + return $self->set_handler('DTDHandler', @_); +} +sub set_lexical_handler { + my $self = shift; + return $self->set_handler('LexicalHandler', @_); +} +sub set_decl_handler { + my $self = shift; + return $self->set_handler('DeclHandler', @_); +} +sub set_error_handler { + my $self = shift; + return $self->set_handler('ErrorHandler', @_); +} +sub set_entity_resolver { + my $self = shift; + return $self->set_handler('EntityResolver', @_); +} + +#-------------------------------------------------------------------# + +#-------------------------------------------------------------------# +# supported_features +#-------------------------------------------------------------------# +sub supported_features { + my $self = shift; + # Only namespaces are required by all parsers + return ( + 'http://xml.org/sax/features/namespaces', + ); +} +#-------------------------------------------------------------------# + +sub no_op { + # this space intentionally blank +} + + +package XML::SAX::Base::NoHandler; +$XML::SAX::Base::NoHandler::VERSION = '1.09'; +# we need a fake handler that doesn't implement anything, this +# simplifies the code a lot (though given the recent changes, +# it may be better to do without) +sub new { + #warn "no handler called\n"; + return bless {}; +} + +1; + +__END__ + +=head1 NAME + +XML::SAX::Base - Base class SAX Drivers and Filters + +=head1 SYNOPSIS + + package MyFilter; + use XML::SAX::Base; + @ISA = ('XML::SAX::Base'); + +=head1 DESCRIPTION + +This module has a very simple task - to be a base class for PerlSAX +drivers and filters. It's default behaviour is to pass the input directly +to the output unchanged. It can be useful to use this module as a base class +so you don't have to, for example, implement the characters() callback. + +The main advantages that it provides are easy dispatching of events the right +way (ie it takes care for you of checking that the handler has implemented +that method, or has defined an AUTOLOAD), and the guarantee that filters +will pass along events that they aren't implementing to handlers downstream +that might nevertheless be interested in them. + +=head1 WRITING SAX DRIVERS AND FILTERS + +The Perl Sax API Reference is at L. + +Writing SAX Filters is tremendously easy: all you need to do is +inherit from this module, and define the events you want to handle. A +more detailed explanation can be found at +http://www.xml.com/pub/a/2001/10/10/sax-filters.html. + +Writing Drivers is equally simple. The one thing you need to pay +attention to is B to call events yourself (this applies to Filters +as well). For instance: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something + $self->{Handler}->start_element($data); # BAD + } + +The above example works well as precisely that: an example. But it has +several faults: 1) it doesn't test to see whether the handler defines +start_element. Perhaps it doesn't want to see that event, in which +case you shouldn't throw it (otherwise it'll die). 2) it doesn't check +ContentHandler and then Handler (ie it doesn't look to see that the +user hasn't requested events on a specific handler, and if not on the +default one), 3) if it did check all that, not only would the code be +cumbersome (see this module's source to get an idea) but it would also +probably have to check for a DocumentHandler (in case this were SAX1) +and for AUTOLOADs potentially defined in all these packages. As you can +tell, that would be fairly painful. Instead of going through that, +simply remember to use code similar to the following instead: + + package MyFilter; + use base qw(XML::SAX::Base); + + sub start_element { + my $self = shift; + my $data = shift; + # do something to filter + $self->SUPER::start_element($data); # GOOD (and easy) ! + } + +This way, once you've done your job you hand the ball back to +XML::SAX::Base and it takes care of all those problems for you! + +Note that the above example doesn't apply to filters only, drivers +will benefit from the exact same feature. + +=head1 METHODS + +A number of methods are defined within this class for the purpose of +inheritance. Some probably don't need to be overridden (eg parse_file) +but some clearly should be (eg parse). Options for these methods are +described in the PerlSAX2 specification available from +http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/~checkout~/perl-xml/libxml-perl/doc/sax-2.0.html?rev=HEAD&content-type=text/html. + +=over 4 + +=item * parse + +The parse method is the main entry point to parsing documents. Internally +the parse method will detect what type of "thing" you are parsing, and +call the appropriate method in your implementation class. Here is the +mapping table of what is in the Source options (see the Perl SAX 2.0 +specification for the meaning of these values): + + Source Contains parse() calls + =============== ============= + CharacterStream (*) _parse_characterstream($stream, $options) + ByteStream _parse_bytestream($stream, $options) + String _parse_string($string, $options) + SystemId _parse_systemid($string, $options) + +However note that these methods may not be sensible if your driver class +is not for parsing XML. An example might be a DBI driver that generates +XML/SAX from a database table. If that is the case, you likely want to +write your own parse() method. + +Also note that the Source may contain both a PublicId entry, and an +Encoding entry. To get at these, examine $options->{Source} as passed +to your method. + +(*) A CharacterStream is a filehandle that does not need any encoding +translation done on it. This is implemented as a regular filehandle +and only works under Perl 5.7.2 or higher using PerlIO. To get a single +character, or number of characters from it, use the perl core read() +function. To get a single byte from it (or number of bytes), you can +use sysread(). The encoding of the stream should be in the Encoding +entry for the Source. + +=item * parse_file, parse_uri, parse_string + +These are all convenience variations on parse(), and in fact simply +set up the options before calling it. You probably don't need to +override these. + +=item * get_options + +This is a convenience method to get options in SAX2 style, or more +generically either as hashes or as hashrefs (it returns a hashref). +You will probably want to use this method in your own implementations +of parse() and of new(). + +=item * get_feature, set_feature + +These simply get and set features, and throw the +appropriate exceptions defined in the specification if need be. + +If your subclass defines features not defined in this one, +then you should override these methods in such a way that they check for +your features first, and then call the base class's methods +for features not defined by your class. An example would be: + + sub get_feature { + my $self = shift; + my $feat = shift; + if (exists $MY_FEATURES{$feat}) { + # handle the feature in various ways + } + else { + return $self->SUPER::get_feature($feat); + } + } + +Currently this part is unimplemented. + + +=item * set_handler + +This method takes a handler type (Handler, ContentHandler, etc.) and a +handler object as arguments, and changes the current handler for that +handler type, while taking care of resetting the internal state that +needs to be reset. This allows one to change a handler during parse +without running into problems (changing it on the parser object +directly will most likely cause trouble). + +=item * set_document_handler, set_content_handler, set_dtd_handler, set_lexical_handler, set_decl_handler, set_error_handler, set_entity_resolver + +These are just simple wrappers around the former method, and take a +handler object as their argument. Internally they simply call +set_handler with the correct arguments. + +=item * get_handler + +The inverse of set_handler, this method takes a an optional string containing a handler type (DTDHandler, +ContentHandler, etc. 'Handler' is used if no type is passed). It returns a reference to the object that implements +that class, or undef if that handler type is not set for the current driver/filter. + +=item * get_document_handler, get_content_handler, get_dtd_handler, get_lexical_handler, get_decl_handler, +get_error_handler, get_entity_resolver + +These are just simple wrappers around the get_handler() method, and take no arguments. Internally +they simply call get_handler with the correct handler type name. + +=back + +It would be rather useless to describe all the methods that this +module implements here. They are all the methods supported in SAX1 and +SAX2. In case your memory is a little short, here is a list. The +apparent duplicates are there so that both versions of SAX can be +supported. + +=over 4 + +=item * start_document + +=item * end_document + +=item * start_element + +=item * start_document + +=item * end_document + +=item * start_element + +=item * end_element + +=item * characters + +=item * processing_instruction + +=item * ignorable_whitespace + +=item * set_document_locator + +=item * start_prefix_mapping + +=item * end_prefix_mapping + +=item * skipped_entity + +=item * start_cdata + +=item * end_cdata + +=item * comment + +=item * entity_reference + +=item * notation_decl + +=item * unparsed_entity_decl + +=item * element_decl + +=item * attlist_decl + +=item * doctype_decl + +=item * xml_decl + +=item * entity_decl + +=item * attribute_decl + +=item * internal_entity_decl + +=item * external_entity_decl + +=item * resolve_entity + +=item * start_dtd + +=item * end_dtd + +=item * start_entity + +=item * end_entity + +=item * warning + +=item * error + +=item * fatal_error + +=back + +=head1 TODO + + - more tests + - conform to the "SAX Filters" and "Java and DOM compatibility" + sections of the SAX2 document. + +=head1 AUTHOR + +Kip Hampton (khampton@totalcinema.com) did most of the work, after porting +it from XML::Filter::Base. + +Robin Berjon (robin@knowscape.com) pitched in with patches to make it +usable as a base for drivers as well as filters, along with other patches. + +Matt Sergeant (matt@sergeant.org) wrote the original XML::Filter::Base, +and patched a few things here and there, and imported it into +the XML::SAX distribution. + +=head1 SEE ALSO + +L + +=cut + diff --git a/lib/XML/SAX/Exception.pm b/lib/XML/SAX/Exception.pm new file mode 100644 index 0000000..c30e29a --- /dev/null +++ b/lib/XML/SAX/Exception.pm @@ -0,0 +1,126 @@ +package XML::SAX::Exception; +$XML::SAX::Exception::VERSION = '1.09'; +use strict; + +use overload '""' => "stringify", + 'fallback' => 1; + +use vars qw($StackTrace); + +use Carp; + +$StackTrace = $ENV{XML_DEBUG} || 0; + +# Other exception classes: + +@XML::SAX::Exception::NotRecognized::ISA = ('XML::SAX::Exception'); +@XML::SAX::Exception::NotSupported::ISA = ('XML::SAX::Exception'); +@XML::SAX::Exception::Parse::ISA = ('XML::SAX::Exception'); + + +sub throw { + my $class = shift; + if (ref($class)) { + die $class; + } + die $class->new(@_); +} + +sub new { + my $class = shift; + my %opts = @_; + confess "Invalid options: " . join(', ', keys %opts) unless exists $opts{Message}; + + bless { ($StackTrace ? (StackTrace => stacktrace()) : ()), %opts }, + $class; +} + +sub stringify { + my $self = shift; + local $^W; + my $error; + if (exists $self->{LineNumber}) { + $error = $self->{Message} . " [Ln: " . $self->{LineNumber} . + ", Col: " . $self->{ColumnNumber} . "]"; + } + else { + $error = $self->{Message}; + } + if ($StackTrace) { + $error .= stackstring($self->{StackTrace}); + } + $error .= "\n"; + return $error; +} + +sub stacktrace { + my $i = 2; + my @fulltrace; + while (my @trace = caller($i++)) { + my %hash; + @hash{qw(Package Filename Line)} = @trace[0..2]; + push @fulltrace, \%hash; + } + return \@fulltrace; +} + +sub stackstring { + my $stacktrace = shift; + my $string = "\nFrom:\n"; + foreach my $current (@$stacktrace) { + $string .= $current->{Filename} . " Line: " . $current->{Line} . "\n"; + } + return $string; +} + +1; + +__END__ + +=head1 NAME + +XML::SAX::Exception - Exception classes for XML::SAX + +=head1 SYNOPSIS + + throw XML::SAX::Exception::NotSupported( + Message => "The foo feature is not supported", + ); + +=head1 DESCRIPTION + +This module is the base class for all SAX Exceptions, those defined in +the spec as well as those that one may create for one's own SAX errors. + +There are three subclasses included, corresponding to those of the SAX +spec: + + XML::SAX::Exception::NotSupported + XML::SAX::Exception::NotRecognized + XML::SAX::Exception::Parse + +Use them wherever you want, and as much as possible when you encounter +such errors. SAX is meant to use exceptions as much as possible to +flag problems. + +=head1 CREATING NEW EXCEPTION CLASSES + +All you need to do to create a new exception class is: + + @XML::SAX::Exception::MyException::ISA = ('XML::SAX::Exception') + +The given package doesn't need to exist, it'll behave correctly this +way. If your exception refines an existing exception class, then you +may also inherit from that instead of from the base class. + +=head1 THROWING EXCEPTIONS + +This is as simple as exemplified in the SYNOPSIS. In fact, there's +nothing more to know. All you have to do is: + + throw XML::SAX::Exception::MyException( Message => 'Something went wrong' ); + +and voila, you've thrown an exception which can be caught in an eval block. + +=cut + diff --git a/t/00basic.t b/t/00basic.t new file mode 100644 index 0000000..890ae7c --- /dev/null +++ b/t/00basic.t @@ -0,0 +1,6 @@ +use Test; +BEGIN { plan tests => 1 } +END { ok($loaded) } +use XML::SAX::Base; +$loaded++; + diff --git a/t/01exception.t b/t/01exception.t new file mode 100644 index 0000000..2e994d6 --- /dev/null +++ b/t/01exception.t @@ -0,0 +1,49 @@ +use Test; +BEGIN { plan tests => 14 } +use XML::SAX::Exception; +eval { + throw XML::SAX::Exception ( Message => "Test" ); +}; +ok($@); # test died +ok($@, "Test\n"); # test stringification +ok($@->isa('XML::SAX::Exception')); # test isa + +eval { + throw XML::SAX::Exception::Parse ( + Message => "Parse", + LineNumber => 12, + ColumnNumber => 2, + SystemId => "throw.xml", + PublicId => "Some // Public // Identifier", + ); +}; +ok($@); +ok($@->{Message}, "Parse"); +ok($@, qr/Parse/); +ok($@->{LineNumber}, 12); +ok($@->isa('XML::SAX::Exception::Parse')); + +eval { + throw XML::SAX::Exception::ThisOneDoesNotExist ( + Message => "Fubar", + ); +}; +ok($@); +ok(!UNIVERSAL::isa($@, 'XML::SAX::Exception')); + +eval { + throw XML::SAX::Exception::NotRecognized ( + Message => "Not Recognized", + ); +}; +ok($@); +ok($@->isa('XML::SAX::Exception')); + +eval { + throw XML::SAX::Exception::NotSupported ( + Message => "Not Supported", + ); +}; +ok($@); +ok($@->isa('XML::SAX::Exception')); + diff --git a/t/01simpledriver.t b/t/01simpledriver.t new file mode 100644 index 0000000..e3d9db6 --- /dev/null +++ b/t/01simpledriver.t @@ -0,0 +1,229 @@ +use Test; +BEGIN { plan tests => 1 } +use XML::SAX::Base; + +my $sax_it = SAXIterator->new(); +my $driver = Driver->new(Handler => $sax_it); + +my $retval = $driver->parse(); + +ok ($retval == 32); +# end main + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + + $self->SUPER::start_document; + $self->SUPER::start_element; + $self->SUPER::characters; + $self->SUPER::processing_instruction; + $self->SUPER::end_prefix_mapping; + $self->SUPER::start_prefix_mapping; + $self->SUPER::set_document_locator; + $self->SUPER::xml_decl; + $self->SUPER::ignorable_whitespace; + $self->SUPER::skipped_entity; + $self->SUPER::start_cdata; + $self->SUPER::end_cdata; + $self->SUPER::comment; + $self->SUPER::entity_reference; + $self->SUPER::unparsed_entity_decl; + $self->SUPER::element_decl; + $self->SUPER::attlist_decl; + $self->SUPER::doctype_decl; + $self->SUPER::entity_decl; + $self->SUPER::attribute_decl; + $self->SUPER::internal_entity_decl; + $self->SUPER::external_entity_decl; + $self->SUPER::resolve_entity; + $self->SUPER::start_dtd; + $self->SUPER::end_dtd; + $self->SUPER::start_entity; + $self->SUPER::end_entity; + $self->SUPER::warning; + $self->SUPER::error; + $self->SUPER::fatal_error; + $self->SUPER::end_element; + return $self->SUPER::end_document; +} +1; + +# basic single class SAX Handler +package SAXIterator; +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{_cnt} = 0; + return bless \%options, $class; +} + +sub start_document { + my ($self, $document) = @_; + $self->{_cnt}++; +} + +sub start_element { + my ($self, $element) = @_; + $self->{_cnt}++; +} + +sub characters { + my ($self, $chars) = @_; + $self->{_cnt}++; +} + +sub end_element { + my ($self, $element) = @_; + $self->{_cnt}++; +} + +sub end_document { + my ($self, $document) = @_; + $self->{_cnt}++; + return $self->{_cnt}; +} + +sub processing_instruction { + my ($self, $pi) = @_; + $self->{_cnt}++; +} + +sub end_prefix_mapping { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub start_prefix_mapping { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub set_document_locator { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + + +sub xml_decl { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub ignorable_whitespace { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub skipped_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_cdata { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_cdata { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub comment { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub entity_reference { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub unparsed_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub element_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub attlist_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub doctype_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub attribute_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub internal_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub external_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub resolve_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_dtd { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_dtd { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub warning { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub error { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub fatal_error { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +1; + diff --git a/t/02simplefilter.t b/t/02simplefilter.t new file mode 100644 index 0000000..d317412 --- /dev/null +++ b/t/02simplefilter.t @@ -0,0 +1,235 @@ +use Test; +BEGIN { plan tests => 1 } +use XML::SAX::Base; + +my $sax_it = SAXIterator->new(); +my $filter = EmptyFilter->new(Handler => $sax_it); +my $driver = Driver->new(Handler => $filter); + +my $retval = $driver->parse(); + +ok ($retval == 32); +# end main + +package EmptyFilter; +use base qw(XML::SAX::Base); +# DAAAAAHUUUT!!!!!! +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + + $self->SUPER::start_document; + $self->SUPER::start_element; + $self->SUPER::characters; + $self->SUPER::processing_instruction; + $self->SUPER::end_prefix_mapping; + $self->SUPER::start_prefix_mapping; + $self->SUPER::set_document_locator; + $self->SUPER::xml_decl; + $self->SUPER::ignorable_whitespace; + $self->SUPER::skipped_entity; + $self->SUPER::start_cdata; + $self->SUPER::end_cdata; + $self->SUPER::comment; + $self->SUPER::entity_reference; + $self->SUPER::unparsed_entity_decl; + $self->SUPER::element_decl; + $self->SUPER::attlist_decl; + $self->SUPER::doctype_decl; + $self->SUPER::entity_decl; + $self->SUPER::attribute_decl; + $self->SUPER::internal_entity_decl; + $self->SUPER::external_entity_decl; + $self->SUPER::resolve_entity; + $self->SUPER::start_dtd; + $self->SUPER::end_dtd; + $self->SUPER::start_entity; + $self->SUPER::end_entity; + $self->SUPER::warning; + $self->SUPER::error; + $self->SUPER::fatal_error; + $self->SUPER::end_element; + return $self->SUPER::end_document; +} +1; + +# basic single class SAX Handler +package SAXIterator; +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{_cnt} = 0; + return bless \%options, $class; +} + +sub start_document { + my ($self, $document) = @_; + $self->{_cnt}++; +} + +sub start_element { + my ($self, $element) = @_; + $self->{_cnt}++; +} + +sub characters { + my ($self, $chars) = @_; + $self->{_cnt}++; +} + +sub end_element { + my ($self, $element) = @_; + $self->{_cnt}++; +} + +sub end_document { + my ($self, $document) = @_; + $self->{_cnt}++; + return $self->{_cnt}; +} + +sub processing_instruction { + my ($self, $pi) = @_; + $self->{_cnt}++; +} + +sub end_prefix_mapping { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub start_prefix_mapping { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub set_document_locator { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + + +sub xml_decl { + my ($self, $mapping) = @_; + $self->{_cnt}++; +} + +sub ignorable_whitespace { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub skipped_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_cdata { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_cdata { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub comment { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub entity_reference { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub unparsed_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub element_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub attlist_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub doctype_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub attribute_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub internal_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub external_entity_decl { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub resolve_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_dtd { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_dtd { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub start_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub end_entity { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub warning { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub error { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +sub fatal_error { + my ($self, $wtf) = @_; + $self->{_cnt}++; +} + +1; + diff --git a/t/03chdriver.t b/t/03chdriver.t new file mode 100644 index 0000000..221c1e1 --- /dev/null +++ b/t/03chdriver.t @@ -0,0 +1,76 @@ +use Test; +BEGIN { plan tests => 12 } +use XML::SAX::Base; +use vars qw/%events/; +require "./t/events.pl"; + +# Tests for ContentHandler classes + +my $sax_it = SAXAutoload->new(); +my $driver = Driver->new(ContentHandler => $sax_it); +my %ret = $driver->parse(); + +ok (scalar(keys(%ret)) == 11); + +foreach my $meth (keys(%ret)){ + my $ok_cnt = 0; + foreach my $key (keys (%{ $ret{$meth} })){ + $ok_cnt++ if $ret{$meth}->{$key} eq $events{$meth}->{$key}; + } + ok( + $ok_cnt == scalar(keys(%{$ret{$meth}})) && + $ok_cnt == scalar(keys(%{$events{$meth}})) + ) || warn "failed for $meth\n"; +} +# end main + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_document($events{start_document}); + $self->SUPER::processing_instruction($events{processing_instruction}); + $self->SUPER::set_document_locator($events{set_document_locator}); + $self->SUPER::start_prefix_mapping($events{start_prefix_mapping}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::characters($events{characters}); + $self->SUPER::ignorable_whitespace($events{ignorable_whitespace}); + $self->SUPER::skipped_entity($events{skipped_entity}); + $self->SUPER::end_element($events{end_element}); + $self->SUPER::end_prefix_mapping($events{end_prefix_mapping}); + return $self->SUPER::end_document($events{end_document}); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{Methods} = {}; + return bless \%options, $class; +} +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + $self->{Methods}->{$name} = $data ; +} + +sub end_document { + my $self = shift; + my $data = shift; + $self->{Methods}->{end_document} = $data; + return %{$self->{Methods}}; +} + +1; diff --git a/t/04chfilter.t b/t/04chfilter.t new file mode 100644 index 0000000..7eb2458 --- /dev/null +++ b/t/04chfilter.t @@ -0,0 +1,83 @@ +use Test; +BEGIN { plan tests => 12 } +use XML::SAX::Base; +use vars qw/%events/; +require "./t/events.pl"; + +# Tests for ContentHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(ContentHandler => $sax_it); +my $driver = Driver->new(ContentHandler => $filter); +my %ret = $driver->parse(); + +ok (scalar(keys(%ret)) == 11); + +foreach my $meth (keys(%ret)){ + my $ok_cnt = 0; + foreach my $key (keys (%{ $ret{$meth} })){ + $ok_cnt++ if $ret{$meth}->{$key} eq $events{$meth}->{$key}; + } + ok( + $ok_cnt == scalar(keys(%{$ret{$meth}})) && + $ok_cnt == scalar(keys(%{$events{$meth}})) + ) || warn "failed for $meth\n"; +} +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_document($events{start_document}); + $self->SUPER::processing_instruction($events{processing_instruction}); + $self->SUPER::set_document_locator($events{set_document_locator}); + $self->SUPER::start_prefix_mapping($events{start_prefix_mapping}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::characters($events{characters}); + $self->SUPER::ignorable_whitespace($events{ignorable_whitespace}); + $self->SUPER::skipped_entity($events{skipped_entity}); + $self->SUPER::end_element($events{end_element}); + $self->SUPER::end_prefix_mapping($events{end_prefix_mapping}); + return $self->SUPER::end_document($events{end_document}); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{Methods} = {}; + return bless \%options, $class; +} +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + $self->{Methods}->{$name} = $data ; +} + +sub end_document { + my $self = shift; + my $data = shift; + $self->{Methods}->{end_document} = $data; + return %{$self->{Methods}}; +} + +1; diff --git a/t/05dtdhdriver.t b/t/05dtdhdriver.t new file mode 100644 index 0000000..dcfb662 --- /dev/null +++ b/t/05dtdhdriver.t @@ -0,0 +1,72 @@ +use Test; +BEGIN { plan tests => 7 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for ContentHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(DTDHandler => $sax_it); +my $driver = Driver->new(DTDHandler => $filter); +$driver->_parse(); + +ok($meth_count == 6); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub _parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::notation_decl($events{notation_decl}); + $self->SUPER::unparsed_entity_decl($events{unparsed_entity_decl}); + $self->SUPER::xml_decl($events{xml_decl}); + $self->SUPER::attlist_decl($events{attlist_decl}); + $self->SUPER::doctype_decl($events{doctype_decl}); + $self->SUPER::entity_decl($events{entity_decl}); + +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} + + +1; diff --git a/t/06lexhdriver.t b/t/06lexhdriver.t new file mode 100644 index 0000000..4bad740 --- /dev/null +++ b/t/06lexhdriver.t @@ -0,0 +1,72 @@ +use Test; +BEGIN { plan tests => 8 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for ContentHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(LexicalHandler => $sax_it); +my $driver = Driver->new(LexicalHandler => $filter); +$driver->parse(); + +ok($meth_count == 7); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::comment($events{comment}); + $self->SUPER::start_dtd($events{start_dtd}); + $self->SUPER::end_dtd($events{end_dtd}); + $self->SUPER::start_cdata($events{start_cdata}); + $self->SUPER::end_cdata($events{end_cdata}); + $self->SUPER::start_entity($events{start_entity}); + $self->SUPER::end_entity($events{end_entity}); + +# return $self->SUPER::result(1); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/07declhdriver.t b/t/07declhdriver.t new file mode 100644 index 0000000..4354717 --- /dev/null +++ b/t/07declhdriver.t @@ -0,0 +1,69 @@ +use Test; +BEGIN { plan tests => 5 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for ContentHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(DeclHandler => $sax_it); +my $driver = Driver->new(DeclHandler => $filter); +$driver->parse(); + +ok($meth_count == 4); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::element_decl($events{element_decl}); + $self->SUPER::attribute_decl($events{attribute_decl}); + $self->SUPER::internal_entity_decl($events{internal_entity_decl}); + $self->SUPER::external_entity_decl($events{external_entity_decl}); + +# return $self->SUPER::result(1); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/08errorhdriver.t b/t/08errorhdriver.t new file mode 100644 index 0000000..66d0df9 --- /dev/null +++ b/t/08errorhdriver.t @@ -0,0 +1,67 @@ +use Test; +BEGIN { plan tests => 4 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for ErrorHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(ErrorHandler => $sax_it); +my $driver = Driver->new(ErrorHandler => $filter); +$driver->parse(); + +ok($meth_count == 3); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::warning($events{warning}); + $self->SUPER::error($events{error}); + $self->SUPER::fatal_error($events{fatal_error}); + +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/09resoldriver.t b/t/09resoldriver.t new file mode 100644 index 0000000..9193e3a --- /dev/null +++ b/t/09resoldriver.t @@ -0,0 +1,65 @@ +use Test; +BEGIN { plan tests => 2 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for EntityResolver classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(EntityResolver => $sax_it); +my $driver = Driver->new(EntityResolver => $filter); +$driver->parse(); + +ok($meth_count == 1); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::resolve_entity($events{resolve_entity}); + +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/10dochdriver.t b/t/10dochdriver.t new file mode 100644 index 0000000..cbcefad --- /dev/null +++ b/t/10dochdriver.t @@ -0,0 +1,73 @@ +use Test; +BEGIN { plan tests => 10 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Tests for DocumentHandler classes using a filter + +my $sax_it = SAXAutoload->new(); +my $filter = Filter->new(DocumentHandler => $sax_it); +my $driver = Driver->new(DocumentHandler => $filter); +$driver->parse(); + +ok($meth_count == 9); + +# end main + +package Filter; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_document($events{start_document}); + $self->SUPER::processing_instruction($events{processing_instruction}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::characters($events{characters}); + $self->SUPER::ignorable_whitespace($events{ignorable_whitespace}); + $self->SUPER::set_document_locator($events{set_document_locator}); + $self->SUPER::end_element($events{end_element}); + $self->SUPER::entity_reference($events{entity_reference}); + $self->SUPER::end_document($events{end_document}); + +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/11sax1multiclass.t b/t/11sax1multiclass.t new file mode 100644 index 0000000..c6de99e --- /dev/null +++ b/t/11sax1multiclass.t @@ -0,0 +1,87 @@ +use Test; +BEGIN { plan tests => 16 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Multiclass SAX1 filter + +my $terminus = SAXAutoload->new(); +my $doc_handler = MyDocHandler->new(Handler => $terminus); +my $dtd_handler = MyDTDHandler->new(Handler => $terminus); +my $driver = Driver->new(DocumentHandler => $doc_handler, + DTDHandler => $dtd_handler); + +$driver->parse(); + +ok($meth_count == 15); + +# end main + +package MyDocHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyDTDHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_document($events{start_document}); + $self->SUPER::processing_instruction($events{processing_instruction}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::characters($events{characters}); + $self->SUPER::ignorable_whitespace($events{ignorable_whitespace}); + $self->SUPER::set_document_locator($events{set_document_locator}); + $self->SUPER::end_element($events{end_element}); + $self->SUPER::entity_reference($events{entity_reference}); + $self->SUPER::end_document($events{end_document}); + $self->SUPER::notation_decl($events{notation_decl}); + $self->SUPER::unparsed_entity_decl($events{unparsed_entity_decl}); + $self->SUPER::xml_decl($events{xml_decl}); + $self->SUPER::attlist_decl($events{attlist_decl}); + $self->SUPER::doctype_decl($events{doctype_decl}); + $self->SUPER::entity_decl($events{entity_decl}); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/12sax2multiclass.t b/t/12sax2multiclass.t new file mode 100644 index 0000000..2c4e0aa --- /dev/null +++ b/t/12sax2multiclass.t @@ -0,0 +1,137 @@ +use Test; +BEGIN { plan tests => 33 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count/; +require "./t/events.pl"; + +# Multiclass SAX1 filter + +my $terminus = SAXAutoload->new(); +my $content_handler = MyContentHandler->new(Handler => $terminus); +my $lexical_handler = MyLexicalHandler->new(Handler => $terminus); +my $decl_handler = MyDeclHandler->new(Handler => $terminus); +my $error_handler = MyErrorHandler->new(Handler => $terminus); +my $entity_resolver = MyEntityResolver->new(Handler => $terminus); +my $dtd_handler = MyDTDHandler->new(Handler => $terminus); + +my $driver = Driver->new(ContentHandler => $content_handler, + LexicalHandler => $lexical_handler, + DeclHandler => $decl_handler, + ErrorHandler => $error_handler, + EntityResolver => $entity_resolver, + DTDHandler => $dtd_handler); + +$driver->parse(); + +ok($meth_count == 32); + +# end main + +package MyContentHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyLexicalHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyDeclHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyErrorHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyEntityResolver; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package MyDTDHandler; +use base qw(XML::SAX::Base); +# this space intentionally blank + +1; + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_document($events{start_document}); + $self->SUPER::processing_instruction($events{processing_instruction}); + $self->SUPER::set_document_locator($events{set_document_locator}); + $self->SUPER::start_prefix_mapping($events{start_prefix_mapping}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::characters($events{characters}); + $self->SUPER::ignorable_whitespace($events{ignorable_whitespace}); + $self->SUPER::skipped_entity($events{skipped_entity}); + $self->SUPER::end_element($events{end_element}); + $self->SUPER::end_prefix_mapping($events{end_prefix_mapping}); + $self->SUPER::end_document($events{end_document}); + $self->SUPER::notation_decl($events{notation_decl}); + $self->SUPER::unparsed_entity_decl($events{unparsed_entity_decl}); + $self->SUPER::xml_decl($events{xml_decl}); + $self->SUPER::attlist_decl($events{attlist_decl}); + $self->SUPER::doctype_decl($events{doctype_decl}); + $self->SUPER::entity_decl($events{entity_decl}); + $self->SUPER::comment($events{comment}); + $self->SUPER::start_dtd($events{start_dtd}); + $self->SUPER::end_dtd($events{end_dtd}); + $self->SUPER::start_cdata($events{start_cdata}); + $self->SUPER::end_cdata($events{end_cdata}); + $self->SUPER::start_entity($events{start_entity}); + $self->SUPER::end_entity($events{end_entity}); + $self->SUPER::element_decl($events{element_decl}); + $self->SUPER::attribute_decl($events{attribute_decl}); + $self->SUPER::internal_entity_decl($events{internal_entity_decl}); + $self->SUPER::external_entity_decl($events{external_entity_decl}); + $self->SUPER::warning($events{warning}); + $self->SUPER::error($events{error}); + $self->SUPER::fatal_error($events{fatal_error}); + $self->SUPER::resolve_entity($events{resolve_entity}); +} +1; + +# basic single class SAX Handler +package SAXAutoload; +use vars qw($AUTOLOAD); +use strict; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my %options = @_; + $options{methods} = {}; + return bless \%options, $class; +} + +sub AUTOLOAD { + my $self = shift; + my $data = shift; + my $name = $AUTOLOAD; + $name =~ s/.*://; # strip fully-qualified portion + return if $name eq 'DESTROY'; + #warn "name is $name \ndata is $data\n"; + my $okay_count = 0; + foreach my $key (keys (%{$data})) { + $okay_count++ if defined $main::events{$name}->{$key}; + } + #warn "count $okay_count \n"; + main::ok($okay_count == scalar (keys (%{$data}))); + $main::meth_count++; +} +1; diff --git a/t/13handlerswitch.t b/t/13handlerswitch.t new file mode 100644 index 0000000..0b98eaa --- /dev/null +++ b/t/13handlerswitch.t @@ -0,0 +1,63 @@ +use Test; +BEGIN { plan tests => 3 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count $one_count $two_count/; +require "./t/events.pl"; + +# Tests for in-stream switch of Handler classes. + +my $handler = HandlerOne->new(); +my $driver = Driver->new(DocumentHandler => $handler); +$driver->parse(); + + +ok($one_count == 3); +ok($two_count == 3); +ok($meth_count == 6); + +# end main + +package HandlerOne; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::one_count++; + +} + + +1; + +package HandlerTwo; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::two_count++; +} + +1; + + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->set_handler('ContentHandler', HandlerTwo->new()); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + +} +1; + diff --git a/t/14downstreamswitch.t b/t/14downstreamswitch.t new file mode 100644 index 0000000..591fce4 --- /dev/null +++ b/t/14downstreamswitch.t @@ -0,0 +1,78 @@ +use Test; +BEGIN { plan tests => 3 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count $one_count $two_count/; +require "./t/events.pl"; + +$meth_count = 0; +# Tests for in-stream switch of Handler classes. + +my $handler = HandlerOne->new(); +my $filter = Filter->new(DocumentHandler => $handler); +my $driver = Driver->new(DocumentHandler => $filter); +$driver->parse(); + + +ok($one_count == 3); +ok($two_count == 3); +ok($meth_count == 6); + +# end main + +package Filter; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + if ($main::meth_count == 3) { + $self->set_content_handler(HandlerTwo->new()); + } + $self->SUPER::start_element($element); +} + + +1; + +package HandlerOne; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::one_count++; + +} + + +1; + +package HandlerTwo; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::two_count++; +} + +1; + + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + +} +1; + diff --git a/t/15parentswitch.t b/t/15parentswitch.t new file mode 100644 index 0000000..cecd2b1 --- /dev/null +++ b/t/15parentswitch.t @@ -0,0 +1,66 @@ +use Test; +BEGIN { plan tests => 3 } +use XML::SAX::Base; +use strict; +use vars qw/%events $meth_count $one_count $two_count/; +require "./t/events.pl"; + +# Tests for in-stream switch of Handler classes. +my $driver = Driver->new(); +my $handler = HandlerOne->new(Parent => $driver); +$driver->set_document_handler($handler); + +$driver->parse(); + + +ok($one_count == 3); +ok($two_count == 3); +ok($meth_count == 6); + +# end main + +package HandlerOne; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::one_count++; + if ($main::meth_count == 3) { + $self->{Parent}->set_content_handler(HandlerTwo->new(Parent => $self->{Parent})); + } + +} + + +1; + +package HandlerTwo; +use base qw(XML::SAX::Base); + +sub start_element { + my ($self, $element) = @_; + $main::meth_count++; + $main::two_count++; +} + +1; + + +package Driver; +use base qw(XML::SAX::Base); + +sub parse { + my $self = shift; + my %events = %main::events; + + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + $self->SUPER::start_element($events{start_element}); + +} +1; + diff --git a/t/16gethandlers.t b/t/16gethandlers.t new file mode 100644 index 0000000..13dd048 --- /dev/null +++ b/t/16gethandlers.t @@ -0,0 +1,31 @@ +use Test; +BEGIN { plan tests => 2 } +use XML::SAX::Base; +use strict; + +# Tests for in-stream switch of Handler classes. +my $handler = HandlerOne->new(); +my $filter = FilterOne->new( ContentHandler => $handler ); +my $driver = Driver->new( Handler => $filter); + +ok( $filter->get_handler('ContentHandler') =~ /HandlerOne/ ); +ok( $filter->get_content_handler() =~ /HandlerOne/ ); + +# end main + +package HandlerOne; +use base qw(XML::SAX::Base); + +1; + +package FilterOne; +use base qw(XML::SAX::Base); + +1; + + +package Driver; +use base qw(XML::SAX::Base); + +1; + diff --git a/t/events.pl b/t/events.pl new file mode 100644 index 0000000..f345ff7 --- /dev/null +++ b/t/events.pl @@ -0,0 +1,65 @@ +%events = ( + start_document => {}, + processing_instruction => {Target => 'xml-stylesheet', + Data => 'href="style.xml" type="text/xsl"' + }, + + start_prefix_mapping => {Prefix => 'foo', + NamespaceURI => 'http://localhost/foo' + }, + + start_element => {Name => 'foo:root', + LocalName => 'root', + Prefix => 'foo', + Attributes => {} + }, + + characters => {Data => 'i am some text'}, + ignorable_whitespace => {Data => ' '}, + skipped_entity => {Name => 'huh'}, + set_document_locator => {Name => 'huh'}, + end_element => {Name => 'foo:root', + LocalName => 'root', + Prefix => 'foo' + }, + + end_prefix_mapping => {Prefix => 'foo', + NamespaceURI => 'http://localhost/foo' + }, + xml_decl => {Version => '1.0'}, + start_cdata => {}, + end_cdata => {}, + comment => {Data => 'i am a comment'}, + entity_reference => {Bogus => 1}, + notation_decl => {Name => 'entname', + PublicID => 'huh?' + }, + unparsed_entity_decl => {Name => 'entname', + PublicID => 'huh?', + NotationName => 'notname' + }, + element_decl => {Name => 'elname', + Model => 'huh?', + }, + attlist_decl => {}, + doctype_decl => {}, + entity_decl => {}, + attribute_decl => {ElementName => 'elname', + AttrName => 'attr', + }, + internal_entity_decl => {Name => 'entname', + Value => 'entavl' + }, + external_entity_decl => {Name => 'entname', + PublicID => 'huh?' + }, + resolve_entity => {}, + start_dtd => {}, + end_dtd => {}, + start_entity => {Name => 'entname'}, + end_entity => {Name => 'entname'}, + warning => {Message => 'i warned ye!'}, + error => {Message => 'bad things'}, + fatal_error => {Message => 'et tu brute?'}, + end_document => {msg => 'parse complete'} +); diff --git a/t/release-pod-syntax.t b/t/release-pod-syntax.t new file mode 100644 index 0000000..cdd6a6c --- /dev/null +++ b/t/release-pod-syntax.t @@ -0,0 +1,14 @@ +#!perl + +BEGIN { + unless ($ENV{RELEASE_TESTING}) { + require Test::More; + Test::More::plan(skip_all => 'these tests are for release candidate testing'); + } +} + +# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. +use Test::More; +use Test::Pod 1.41; + +all_pod_files_ok();