view Lib/IMPL/DOM/Navigator/Builder.pm @ 23:716b287d4795

merge
author Sergey
date Wed, 30 Sep 2009 17:43:52 +0400
parents 75d55f4ee263
children 7f00786f8210
line wrap: on
line source

package IMPL::DOM::Navigator::Builder;
use strict;
use warnings;

use base qw(IMPL::DOM::Navigator);
use IMPL::Class::Property;
use IMPL::Class::Property::Direct;

BEGIN {
    protected _direct property _navigatorSchema => prop_all;
    public _direct property Document => prop_get | owner_set;
}

our %CTOR = (
    'IMPL::DOM::Navigator' => sub { $_[0] } # IMPL::DOM::Navigator($domDocument)
);

sub CTOR {
    my ($this,$domDocument,$schema) = @_;
    
    $this->{$Document} = $domDocument;
    $this->{$_navigatorSchema} = new IMPL::DOM::Navigator($schema);
}

sub NavigateCreate {
    my ($this,$nodeName,%props) = @_;
    
    if ( my $nodeSchema = $this->{$_navigatorSchema}->Navigate(sub { $_[0]->nodeName eq $nodeName or $_[0]->isa('IMPL::DOM::Schema::AnyNode') }) ) {
        my $class = delete $props{type} || $nodeSchema->type || $nodeName;
        
        my $node = $this->{$Document}->Create(delete $props{nodeName} || $nodeName, $class, \%props);
        
        $this->Current()->appendNode($node);
        $this->Current($node);
        
    } else {
        die new IMPL::InvalidOperationException("Requested elemnt not found in the schema");
    }
}

sub Back {
    my ($this) = @_;
    
    $this->{$_navigatorSchema}->Back;
    return $this->SUPER::Back();
}

1;

__END__
=pod

=head1 SYNOPSIS

my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema);
my $reader = new IMPL::DOM::XMLReader(Navigator => $builder);

$reader->ParseFile("document.xml");

my @errors = $schema->Validate($builder->Document);

=head1 DESCRIPTION

Построитель DOM документов по указанной схеме. Обычно используется в связке
с объектами для чтения такими как C<IMPL::DOM::XMLReader>.

=head1 METHODS

=over

=item C<CTOR($domDocument,$schema)>

Создает новый объект, принимает на вход пустой (но не обязательно) документ и
схему.

=item C<< $obj->NavigateCreate($nodeName) >>

Создает новый узел с указанным именем и переходит в него. В случае если в схеме
подходящий узел не найден, то вызывается исключение.

При этом схема узла производится по имени, после чего определяется класс для
создания узла, по алгоритму

=over

=item Проверяется свойство C<type> и если оно есть, то используется оно

=item Проверяется свойство C<type> самого элемента схемы, если оно есть, то
используется оно.

=item В качестве класса берется имя узла

=back

Также имя создаваемого узла может быть переопределено свойством C<nodeName>.

Т.о. узел вида C<< <ComplexNode nodeName="Box" type="Container"> >> приведет
к созданию C<< Container->new(nodeName => 'Box') >>.

=back

=cut