Mercurial > pub > Impl
diff lib/IMPL/DOM/Navigator/Builder.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
author | cin |
---|---|
date | Fri, 04 Sep 2015 19:40:23 +0300 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/IMPL/DOM/Navigator/Builder.pm Fri Sep 04 19:40:23 2015 +0300 @@ -0,0 +1,167 @@ +package IMPL::DOM::Navigator::Builder; +use strict; +use warnings; + +use IMPL::Const qw(:prop); + +use parent qw(IMPL::DOM::Navigator); +use IMPL::Class::Property; +require IMPL::DOM::Navigator::SchemaNavigator; +require IMPL::DOM::Schema::ValidationError; +use IMPL::DOM::Document; + +BEGIN { + private _direct property _schemaNavi => PROP_RW; + private _direct property _docClass => PROP_RW; + public _direct property Document => PROP_RO; + public _direct property ignoreUndefined => PROP_RO; +} + +our %CTOR = ( + 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document->Empty; } +); + +sub CTOR { + my ($this,$docClass,$schema,%opts) = @_; + + $this->{$_docClass} = $docClass; + $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef; + + $this->{$ignoreUndefined} = $opts{ignoreUndefined} if $opts{ignoreUndefined}; +} + +sub NavigateCreate { + my ($this,$nodeName,%props) = @_; + + if (my $schemaType = $this->{$_schemaNavi}->NavigateName($nodeName)) { + my $class = $schemaType->can('nativeType') ? $schemaType->nativeType || 'IMPL::DOM::Node' : 'IMPL::DOM::Node'; + + my $schemaNode = $this->{$_schemaNavi}->SourceSchemaNode; + + $props{schemaType} = $schemaType; + $props{schemaNode} = $schemaNode; + + my $node; + if (! $this->{$Document}) { + # keep reference to the schema document + $props{schemaDocument} = $this->{$_schemaNavi}->schema; + $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props); + $this->_initNavigator($node); + } else { + die new IMPL::InvalidOperationException('Can\'t create a second top level element') unless $this->Current; + $node = $this->{$Document}->Create($nodeName,$class,\%props); + $this->Current->appendChild($node); + $this->internalNavigateNodeSet($node); + } + + return $node; + } else { + die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName) + if !$this->ignoreUndefined; + return; + } +} + +sub Back { + my ($this) = @_; + + $this->{$_schemaNavi}->SchemaBack(); + $this->SUPER::Back(); +} + +sub saveState { + my ($this) = @_; + + $this->{$_schemaNavi}->saveState; + $this->SUPER::saveState; +} + +sub restoreState { + my ($this) = @_; + + $this->{$_schemaNavi}->restoreState; + $this->SUPER::restoreState; +} + +sub document { + goto &Document; +} + +1; + +__END__ + +=pod + +=head1 NAME + +C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме. + +=head1 SYNOPSIS + +=begin code + +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); + +=end code + +=head1 DESCRIPTION + +Построитель DOM документов по указанной схеме. Обычно используется в связке +с объектами для чтения такими как C<IMPL::DOM::XMLReader>. + +=head1 MEMBERS + +=head2 C< CTOR($classDocument,$schema, %opts) > + +Создает новый объект, принимает на вход класс документа (или фабрику, например +L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа +будет создан объект документа. + +Необязательные именованные параметры + +=over + +=item C<ignoreUndefined> + +C<NavigateCreate> не будет вызывать исключение, если запрашиваемый узел не +найден в схеме, но будет возвращать C<undef>. + +=back + +=head2 C< NavigateCreate($nodeName,%props) > + +Создает новый узел с указанным именем и переходит в него. В случае если в схеме +подходящий узел не найден, то вызывается исключение или будет возвращено +C<undef> см. C<ignoreUndefined>. + +При этом по имени узла ищется его схема, после чего определяется класс для +создания экземпляра узла и созданный узел доавляется в документ. При создании +нового узла используется метод документа C<< IMPL::DOM::Document->Create >> + +Свойства узла передаются при создании через параметр C<%props>, но имя +создаваемого узла НЕ может быть переопределено свойством C<nodeName>, оно будет +проигнорировано. + +Свойства узла будут преобразованы при помощи заданных в схеме заполнителей +C<inflator>. + +=head2 C<[get]document > + +Свойство, которое содержит документ по окончании процедуры построения. + +=head2 C<[get]buildErrors> + +Ошибки, возникшие в процессе построения документа. + +=head2 C<[get]ignoreUndefined> + +Опция, заданная при создании построителя, отвечающая за обработку узлов +не найденных в схеме. + +=cut