--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uh_parser/XML/SAX/ParserFactory.pm Wed Mar 03 16:51:26 2010 +0000
@@ -0,0 +1,232 @@
+# $Id: ParserFactory.pm,v 1.13 2002/11/19 18:25:47 matt Exp $
+
+package XML::SAX::ParserFactory;
+
+use strict;
+use vars qw($VERSION);
+
+$VERSION = '1.01';
+
+use Symbol qw(gensym);
+use XML::SAX;
+use XML::SAX::Exception;
+
+sub new {
+ my $class = shift;
+ my %params = @_; # TODO : Fix this in spec.
+ my $self = bless \%params, $class;
+ $self->{KnownParsers} = XML::SAX->parsers();
+ return $self;
+}
+
+sub parser {
+ my $self = shift;
+ my @parser_params = @_;
+ if (!ref($self)) {
+ $self = $self->new();
+ }
+
+ my $parser_class = $self->_parser_class();
+
+ my $version = '';
+ if ($parser_class =~ s/\s*\(([\d\.]+)\)\s*$//) {
+ $version = " $1";
+ }
+
+ {
+ no strict 'refs';
+ if (!keys %{"${parser_class}::"}) {
+ eval "use $parser_class $version;";
+ }
+ }
+
+ return $parser_class->new(@parser_params);
+}
+
+sub require_feature {
+ my $self = shift;
+ my ($feature) = @_;
+ $self->{RequiredFeatures}{$feature}++;
+ return $self;
+}
+
+sub _parser_class {
+ my $self = shift;
+
+ # First try ParserPackage
+ if ($XML::SAX::ParserPackage) {
+ return $XML::SAX::ParserPackage;
+ }
+
+ # Now check if required/preferred is there
+ if ($self->{RequiredFeatures}) {
+ my %required = %{$self->{RequiredFeatures}};
+ # note - we never go onto the next try (ParserDetails.ini),
+ # because if we can't provide the requested feature
+ # we need to throw an exception.
+ PARSER:
+ foreach my $parser (reverse @{$self->{KnownParsers}}) {
+ foreach my $feature (keys %required) {
+ if (!exists $parser->{Features}{$feature}) {
+ next PARSER;
+ }
+ }
+ # got here - all features must exist!
+ return $parser->{Name};
+ }
+ # TODO : should this be NotSupported() ?
+ throw XML::SAX::Exception (
+ Message => "Unable to provide required features",
+ );
+ }
+
+ # Next try SAX.ini
+ for my $dir (@INC) {
+ my $fh = gensym();
+ if (open($fh, "$dir/SAX.ini")) {
+ my $param_list = XML::SAX->_parse_ini_file($fh);
+ my $params = $param_list->[0]->{Features};
+ if ($params->{ParserPackage}) {
+ return $params->{ParserPackage};
+ }
+ else {
+ # we have required features (or nothing?)
+ PARSER:
+ foreach my $parser (reverse @{$self->{KnownParsers}}) {
+ foreach my $feature (keys %$params) {
+ if (!exists $parser->{Features}{$feature}) {
+ next PARSER;
+ }
+ }
+ return $parser->{Name};
+ }
+ XML::SAX->do_warn("Unable to provide SAX.ini required features. Using fallback\n");
+ }
+ last; # stop after first INI found
+ }
+ }
+
+ if (@{$self->{KnownParsers}}) {
+ return $self->{KnownParsers}[-1]{Name};
+ }
+ else {
+ return "XML::SAX::PurePerl"; # backup plan!
+ }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::SAX::ParserFactory - Obtain a SAX parser
+
+=head1 SYNOPSIS
+
+ use XML::SAX::ParserFactory;
+ use XML::SAX::XYZHandler;
+ my $handler = XML::SAX::XYZHandler->new();
+ my $p = XML::SAX::ParserFactory->parser(Handler => $handler);
+ $p->parse_uri("foo.xml");
+ # or $p->parse_string("<foo/>") or $p->parse_file($fh);
+
+=head1 DESCRIPTION
+
+XML::SAX::ParserFactory is a factory class for providing an application
+with a Perl SAX2 XML parser. It is akin to DBI - a front end for other
+parser classes. Each new SAX2 parser installed will register itself
+with XML::SAX, and then it will become available to all applications
+that use XML::SAX::ParserFactory to obtain a SAX parser.
+
+Unlike DBI however, XML/SAX parsers almost all work alike (especially
+if they subclass XML::SAX::Base, as they should), so rather than
+specifying the parser you want in the call to C<parser()>, XML::SAX
+has several ways to automatically choose which parser to use:
+
+=over 4
+
+=item * $XML::SAX::ParserPackage
+
+If this package variable is set, then this package is C<require()>d
+and an instance of this package is returned by calling the C<new()>
+class method in that package. If it cannot be loaded or there is
+an error, an exception will be thrown. The variable can also contain
+a version number:
+
+ $XML::SAX::ParserPackage = "XML::SAX::Expat (0.72)";
+
+And the number will be treated as a minimum version number.
+
+=item * Required features
+
+It is possible to require features from the parsers. For example, you
+may wish for a parser that supports validation via a DTD. To do that,
+use the following code:
+
+ use XML::SAX::ParserFactory;
+ my $factory = XML::SAX::ParserFactory->new();
+ $factory->require_feature('http://xml.org/sax/features/validation');
+ my $parser = $factory->parser(...);
+
+Alternatively, specify the required features in the call to the
+ParserFactory constructor:
+
+ my $factory = XML::SAX::ParserFactory->new(
+ RequiredFeatures => {
+ 'http://xml.org/sax/features/validation' => 1,
+ }
+ );
+
+If the features you have asked for are unavailable (for example the
+user might not have a validating parser installed), then an
+exception will be thrown.
+
+The list of known parsers is searched in reverse order, so it will
+always return the last installed parser that supports all of your
+requested features (Note: this is subject to change if someone
+comes up with a better way of making this work).
+
+=item * SAX.ini
+
+ParserFactory will search @INC for a file called SAX.ini, which
+is in a simple format:
+
+ # a comment looks like this,
+ ; or like this, and are stripped anywhere in the file
+ key = value # SAX.in contains key/value pairs.
+
+All whitespace is non-significant.
+
+This file can contain either a line:
+
+ ParserPackage = MyParserModule (1.02)
+
+Where MyParserModule is the module to load and use for the parser,
+and the number in brackets is a minimum version to load.
+
+Or you can list required features:
+
+ http://xml.org/sax/features/validation = 1
+
+And each feature with a true value will be required.
+
+=item * Fallback
+
+If none of the above works, the last parser installed on the user's
+system will be used. The XML::SAX package ships with a pure perl
+XML parser, XML::SAX::PurePerl, so that there will always be a
+fallback parser.
+
+=back
+
+=head1 AUTHOR
+
+Matt Sergeant, matt@sergeant.org
+
+=head1 LICENSE
+
+This is free software, you may use it and distribute it under the same
+terms as Perl itself.
+
+=cut
+