common/tools/raptor/XML/SAX/ParserFactory.pm
changeset 307 989c70555820
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/tools/raptor/XML/SAX/ParserFactory.pm	Tue Aug 04 14:40:11 2009 +0100
@@ -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
+