11
     5�Ã¿Ä      5File not found.
  /   7ˆl–Ãa¾”Je¶¥ ¾ q·n6ò˜´oÈƒq¶[_‹uÐb&=LV[(ÁÆ ‡    7# $Id$

package XML::SAX::ParserFactory;

use strict;
use vars qw($VERSION);

$VERSION = '1.02';

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";
    }

    if (!$parser_class->can('new')) {
        eval "require $parser_class $version;";
        die $@ if $@;
    }

    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 