XML::Elemental::SAXHandler - the SAX2 handler that drives


XML-Elemental documentation Contained in the XML-Elemental distribution.

Index


Code Index:


XML-Elemental documentation Contained in the XML-Elemental distribution.

package XML::Elemental::SAXHandler;
use strict;
use warnings;

use vars qw($VERSION);
$VERSION = '0.11';

use base qw( XML::SAX::Base );

use Scalar::Util qw(weaken);

my %defaults = (
    Document   => 'XML::Elemental::Document',
    Element    => 'XML::Elemental::Element',
    Characters => 'XML::Elemental::Characters'
);

# We work with direct references to the underlying HASH data
# rather then the methods for better parsing performance.
# Dangerous? Perhaps.

sub new {
    my $self = shift->SUPER::new(@_);
    for (keys %defaults) {
        $self->{$_} ||= $defaults{$_};
        eval "require " . $self->{$_} or die $@;
    }
    $self;
}

sub start_document {
    my ($self, $doc) = @_;
    $self->{__doc} = $self->{Document}->new;
    push(@{$self->{__stack}}, $self->{__doc});
}

sub start_element {
    my ($self, $e) = @_;
    my $ns = $e->{NamespaceURI} || '';
    my $node = $self->{Element}->new;
    $node->{name}   = "{$ns}" . $e->{LocalName};
    $node->{parent} = $self->{__stack}->[-1];
    if ($e->{Attributes}) {
        my %attr;
        map { $attr{$_} = $e->{Attributes}->{$_}->{Value} }
          keys %{$e->{Attributes}};
        $node->{attributes} = \%attr;
    }
    push(@{$node->{parent}->{contents}}, $node);
    push(@{$self->{__stack}},            $node);
}

sub characters {
    my ($self, $data) = @_;
    my $parent   = $self->{__stack}->[-1];
    my $contents = $parent->{contents};
    my $class    = $self->{Characters};
    unless ($contents && ref($contents->[-1]) eq $class) {
        my $node = $class->new;
        $node->{parent} = $parent;
        $node->{data}   = $data->{Data};
        push(@{$contents}, $node);
    }
    else {
        my $d = $contents->[-1]->data || '';
        $contents->[-1]->data($d . $data->{Data});
    }
}

sub end_element { pop(@{$_[0]->{__stack}}) }

sub end_document {
    delete $_[0]->{__stack};
    $_[0]->{__doc}->{contents} = $_[0]->{__doc}->{contents}->[0];
    weaken($_[0]->{__doc}->{contents}->{parent} = $_[0]->{__doc});
    $_[0]->{__doc};
}

1;

__END__