Mercurial > pub > Impl
view Lib/IMPL/XML/SaxParser.pm @ 377:a0d342ac9a36
sync
author | cin |
---|---|
date | Tue, 14 Jan 2014 20:06:36 +0400 |
parents | 248f95c1762a |
children |
line wrap: on
line source
package IMPL::XML::SaxParser; use strict; use IMPL::Const qw(:prop); use IMPL::declare { require => { XMLReader => 'XML::LibXML::Reader', Exception => 'IMPL::Exception', ArgException => '-IMPL::InvalidArgumentException' }, base => [ 'IMPL::Object' => undef ], props => [ _reader => PROP_RW ] }; BEGIN { XMLReader->import; } sub Parse { my ( $this, $options ) = @_; my $reader = $this->_reader( XMLReader->new($options) ); if ( $reader->read() > 0) { $this->ProcessRootNode($reader); } } sub ProcessRootNode { my ( $this, $reader ) = @_; warn "not implemented"; } sub ReadChildren { my ( $this, $handler ) = @_; my $reader = $this->_reader; # содержимое можеть быть только у не пустых элементов if($reader->nodeType == XML_READER_TYPE_ELEMENT && !$reader->isEmptyElement) { # нужно прочитать все, что ниже, для этого запоминаем текущий уровень my $currentLevel = $reader->depth; # при чтении и проверке данного условия "съедается" закрывающий теэг текущего узла while($reader->read && $reader->depth > $currentLevel) { # при обходе дочерних узлов нужно пропустить закрывающие узлы $this->$handler($reader) if $handler and $reader->nodeType != XML_READER_TYPE_END_ELEMENT; } } } sub ReadTextNode { my ($this) = @_; my $text = ""; my $handler; $handler = sub { my ( $me, $reader ) = @_; if ( $reader->nodeType == XML_READER_TYPE_TEXT ) { $text .= $reader->value; } else { $this->ReadChildren($handler); } }; $this->ReadChildren($handler); return $text; } sub ReadComplexContent { goto &ReadComplexNode; } sub ReadComplexNode { my ( $this, $schema ) = @_; if ( ref $schema eq 'HASH' ) { my %data; my ($handlers,$aliases); while(my ($selector,$handler) = each %$schema) { my ($alias,$node) = split /:/, $selector; $node ||= $alias; $handlers->{$node} = $handler; $aliases->{$node} = $alias; } $this->ReadChildren( sub { my ( $me, $node ) = @_; my $name = $node->localName; my $alias = $aliases->{$name}; if ( my $handler = $handlers->{$name} ) { if (ref $handler eq 'ARRAY') { push @{$data{$alias}}, $me->ReadComplexNode($$handler[0]); } else { $data{$alias} = $me->ReadComplexNode($handler); } } else { $me->ReadChildren(); } } ); return \%data; } elsif ( ref $schema eq 'CODE' or not ref $schema ) { return $this->$schema($this->_reader); } else { die ArgException->new( schema => 'An invalid schema is supplied' ); } } sub attribute { shift->_reader->getAttribute(shift); } 1; __END__ =pod =head1 NAME =head1 DESCRIPTION =head1 MEMBERS =head2 ReadComplexNode($schema) =begin code { comments => sub { shift->ReadTextNode }, data => [ { location => sub { $_[1]->getAttribute('href')} , timestamp => 'ReadTextNode' } ] } =end code =cut