package SVG::Parser::Expat;
use strict;

require 5.004;

use base qw(XML::Parser SVG::Parser::Base);
use SVG 2.0;

use vars qw($VERSION @ISA);
$VERSION="1.02";

#---------------------------------------------------------------------------------------

=head1 NAME

SVG::Parser::Expat - XML Expat Parser for SVG documents

=head1 SYNOPSIS

  #!/usr/bin/perl -w
  use strict;
  use SVG::Parser::Expat;

  die "Usage: $0 <file>\n" unless @ARGV;

  my $xml;
  {
      local $/=undef;
      $xml=<>;
  }

  my $parser=new SVG::Parser::Expat;

  my $svg=$parser->parse($xml);

  print $svg->xmlify;

=head1 DESCRIPTION

SVG::Parser::Expat is the Expat-specific parser module used by SVG::Parser when an
underlying XML::Parser-based parser is selected. It may also be used directly, as shown
in the synopsis above.

Use SVG::Parser to retain maximum flexibility as to which underlying parser is chosen.
Use SVG::Parser::Expat to supply Expat-specific parser options or where the presence
of XML::Parser is known and/or preferred.

=head2 EXPORTS

None. However, an alternative parent class (other than XML::Parser) can be specified by
passing the package name to SVG::Parser::Expat in the import list. For example:

    use SVG::Parser::Expat qw(My::XML::Parser::Subclass);

Where My::XML::Parser::Subclass is a subclass like:

    package My::XML::Parser::Subclass;
    use strict;
    use vars qw(@ISA);
    use XML::Parser;
    @ISA=qw(XML::Parser);

    ...custom methods...

    1;

When loaded via SVG::Parser, this parent class may be specified by placing it after
the '=' in a parser specification:

    use SVG::Parser qw(Expat=My::XML::Parser::Subclass);

See L<SVG::Parser> for more details.

=head2 EXAMPLES

See C<svgexpatparse> in the examples directory of the distribution.

=head1 AUTHOR

Peter Wainwright, peter.wainwright@cybrid.net

=head1 SEE ALSO

L<SVG>, L<SVG::Parser>, L<SVG::Parser::SAX>, L<XML::Parser>

=cut

#---------------------------------------------------------------------------------------
# SVG::Parser::Expat constructor. Attributes with no minus prefix are passed to
# the parent parser class. Attributes with a minus are set locally.

sub new {
    my $proto=shift;
    my $class=ref($proto) || $proto;
    my %attrs=@_;

    # pass on non-minus-prefixed attributes to XML::Parser
    my %parser_attrs;
    foreach (keys %attrs) {
        $parser_attrs{$_}=delete $attrs{$_} unless /^-/;
    }

    my $parser=$class->SUPER::new(%parser_attrs);
    $parser->setHandlers(
        XMLDecl    => sub { XMLDecl($parser, @_) },
        Doctype    => sub { Doctype($parser, @_) },
        Init       => sub { StartDocument($parser, @_) },
        Final      => sub { FinishDocument($parser, @_) },

        Start      => sub { StartTag($parser, @_) },
        End        => sub { EndTag($parser, @_) },
        Char       => sub { Text($parser, @_) },
        CdataStart => sub { $parser->SVG::Parser::Base::CdataStart(@_) },
        CdataEnd   => sub { $parser->SVG::Parser::Base::CdataEnd(@_) },
        Proc       => sub { PI($parser, @_) },
        Comment    => sub { Comment($parser, @_) },

	Unparsed   => sub { Unparsed($parser, @_) },
        Notation   => sub { Notation($parser,@_) },
        Entity     => sub { Entity($parser, @_) },
	Element    => sub { Element($parser,@_) },
        Attlist    => sub { Attlist($parser,@_) },
    );

    # minus-prefixed attributes stay here, double-minus to SVG object
    foreach (keys %attrs) {
        if (/^-(-.+)$/) {
            $parser->{__svg_attr}{$1}=$attrs{$_};
        } else {
            $parser->{$_}=$attrs{$_};
        }
    }

    return $parser;
}

#---------------------------------------------------------------------------------------
# Import method to change default inheritance, if required

sub import {
    my $package=shift;

    # permit an alternative XML::Parser subclass to be our parent class
    if (@_) {
        my $superclass=shift;

        $ISA[0]=$superclass,return if eval qq[
            use $superclass qw(@_);
            1;
        ];

        die "Parent parser class $superclass not found: $@\n";
    }
}

#---------------------------------------------------------------------------------------
# Handlers

# create and set SVG document object as root element
sub StartDocument {
    my ($parser,$expat)=@_;
    return $parser->SVG::Parser::Base::StartDocument();
}

# handle start of element - extend chain by one
sub StartTag {
    my ($parser,$expat,$type,%attrs)=@_;
    return $parser->SVG::Parser::Base::StartTag($type,%attrs);
}

# handle end of element - shorten chain by one
sub EndTag {
    my ($parser,$expat,$type)=@_;
    return $parser->SVG::Parser::Base::EndTag($type);
}

# handle cannonical data (text)
sub Text {
    my ($parser,$expat,$text)=@_;
    return $parser->SVG::Parser::Base::Text($text);
}

# handle processing instructions
sub PI {
    my ($parser,$expat,$target,$data)=@_;
    return $parser->SVG::Parser::Base::PI($target,$data);
}

# handle XML Comments
sub Comment {
    my ($parser,$expat,$data)=@_;
    return $parser->SVG::Parser::Base::Comment($data);
}

# return root SVG document object as result of parse()
sub FinishDocument {
    my ($parser,$expat)=@_;
    return $parser->SVG::Parser::Base::FinishDocument();
}

#---------------------------------------------------------------------------------------

# handle XML declaration, if present
sub XMLDecl {
    my ($parser,$expat,$version,$encoding,$standalone)=@_;
    return $parser->SVG::Parser::Base::XMLDecl($version,$encoding,$standalone);
}

# handle Doctype declaration, if present
sub Doctype {
    my ($parser,$expat,$name,$sysid,$pubid,$internal)=@_;
    return $parser->SVG::Parser::Base::Doctype($name,$sysid,$pubid,$internal);
}

#---------------------------------------------------------------------------------------

# Unparsed (Expat, Entity, Base, Sysid, Pubid, Notation)
sub Unparsed {
    my ($parser,$expat,$name,$base,$sysid,$pubid,$notation)=@_;
    return $parser->SVG::Parser::Base::Unparsed($name,$base,$sysid,$pubid,$notation);
}

# Notation (Expat, Notation, Base, Sysid, Pubid)
sub Notation {
    my ($parser,$expat,$name,$base,$sysid,$pubid)=@_;
    return $parser->SVG::Parser::Base::Notation($name,$base,$sysid,$pubid);
}

# Entity (Expat, Name, Val, Sysid, Pubid, Ndata, IsParam)
sub Entity {
    my ($parser,$expat,$name,$val,$sysid,$pubid,$data,$isp)=@_;
    return $parser->SVG::Parser::Base::Entity($name,$val,$sysid,$pubid,$data,$isp);
}

# Element (Expat, Name, Model)
sub Element {
    my ($parser,$expat,$name,$model)=@_;
    return $parser->SVG::Parser::Base::Element($name,$model);
}

# Attlist (Expat, Elname, Attname, Type, Default, Fixed)
sub Attlist {
    my ($parser,$expat,$name,$attr,$type,$default,$fixed)=@_;
    return $parser->SVG::Parser::Base::Attlist($name,$attr,$type,$default,$fixed);
}

#---------------------------------------------------------------------------------------
# SAX -> Expat compatability

sub parse_file {
    shift->parsefile(@_);
}

#---------------------------------------------------------------------------------------

1;
