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