# # $Id: XMLParser.pm,v 1.3 2000/10/05 20:54:10 kmacleod Exp $ # use strict; package SAXDriver::XMLParser; use XML::Parser; use XML::Orchard; use vars qw{ $xmlns_ns $VERSION }; $VERSION = "0.00"; # this should probably be a global somewhere $xmlns_ns = "http://www.w3.org/2000/xmlns/"; sub new { my ($type, %self) = @_; return bless \%self, $type; } sub parse { my ($self, $file) = @_; my $parser = XML::Parser->new( Handlers => { Init => sub { $self->_handle_init(@_) }, Final => sub { $self->_handle_final(@_) }, Start => sub { $self->_handle_start(@_) }, End => sub { $self->_handle_end(@_) }, Char => sub { $self->_handle_char(@_) }, Comment => sub { $self->_handle_comment(@_) }, Proc => sub { $self->_handle_proc(@_) }, } ); $self->{InScopeNamespaceStack} = [ { '_Default' => undef, 'xmlns' => $xmlns_ns } ]; $self->{NodeStack} = [ ]; return $parser->parsefile($file); } sub parse_string { my ($self, $string) = @_; my $parser = XML::Parser->new( Handlers => { Init => sub { $self->_handle_init(@_) }, Final => sub { $self->_handle_final(@_) }, Start => sub { $self->_handle_start(@_) }, End => sub { $self->_handle_end(@_) }, Char => sub { $self->_handle_char(@_) }, Comment => sub { $self->_handle_comment(@_) }, Proc => sub { $self->_handle_proc(@_) }, } ); $self->{InScopeNamespaceStack} = [ { '_Default' => undef, 'xmlns' => $xmlns_ns } ]; $self->{NodeStack} = [ ]; return $parser->parse($string); } sub _handle_init { my ($self, $expat) = @_; my $document = XML::Orchard::Document->new( ); push @{ $self->{NodeStack} }, $document; $self->{Handler}->start_document( $document ); } sub _handle_final { my ($self, $expat) = @_; my $document = pop @{ $self->{NodeStack} }; return $self->{Handler}->end_document( $document ); } sub _handle_start { my $self = shift; my $expat = shift; my $element_name = shift; push @{ $self->{InScopeNamespaceStack} }, { %{ $self->{InScopeNamespaceStack}[-1] } }; $self->_scan_namespaces(@_); my @attributes; for (my $ii = 0; $ii < $#_; $ii += 2) { my ($name, $value) = ($_[$ii], $_[$ii+1]); my $namespace = $self->_namespace($name); push @attributes, XML::Orchard::Attribute->new( Name => $name, Value => $value, NamespaceURI => $namespace ); } my $namespace = $self->_namespace($element_name); my $element = XML::Orchard::Element->new( Name => $element_name, NamespaceURI => $namespace, Attributes => [ @attributes ] ); push @{ $self->{NodeStack} }, $element; $self->{Handler}->start_element( $element ); } sub _handle_end { my $self = shift; pop @{ $self->{InScopeNamespaceStack} }; my $element = pop @{ $self->{NodeStack} }; $self->{Handler}->end_element( $element ); } sub _handle_char { my ($self, $expat, $string) = @_; my $characters = XML::Orchard::Characters->new( Data => $string ); $self->{Handler}->characters( $characters ); } sub _handle_comment { my ($self, $expat, $data) = @_; my $comment = XML::Orchard::Comment->new( Data => $data ); $self->{Handler}->comment( $comment ); } sub _handle_proc { my ($self, $expat, $target, $data) = @_; my $pi = XML::Orchard::ProcessingInstruction->new( Target => $target, Data => $data ); $self->{Handler}->processing_instruction( $pi ); } sub _scan_namespaces { my ($self, %attributes) = @_; while (my ($attr_name, $value) = each %attributes) { if ($attr_name eq 'xmlns') { $self->{InScopeNamespaceStack}[-1]{'_Default'} = $value; } elsif ($attr_name =~ /^xmlns:(.*)$/) { my $prefix = $1; $self->{InScopeNamespaceStack}[-1]{$prefix} = $value; } } } sub _namespace { my ($self, $name) = @_; my ($prefix, $localname) = split(/:/, $name); if (!defined($localname)) { if ($prefix eq 'xmlns') { return undef; } else { return $self->{InScopeNamespaceStack}[-1]{'_Default'}; } } else { return $self->{InScopeNamespaceStack}[-1]{$prefix}; } } 1;