changeset 250:129e48bb5afb

DOM refactoring ObjectToDOM methods are virtual QueryToDOM uses inflators Fixed transform for the complex values in the ObjectToDOM QueryToDOM doesn't allow to use complex values (HASHes) as values for nodes (overpost problem)
author sergey
date Wed, 07 Nov 2012 04:17:53 +0400
parents 0057f48f7945
children 9f394b27dccf
files Lib/IMPL/DOM/Navigator/Builder.pm Lib/IMPL/DOM/Schema.pm Lib/IMPL/DOM/Transform/ObjectToDOM.pm Lib/IMPL/DOM/Transform/QueryToDOM.pm
diffstat 4 files changed, 109 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/DOM/Navigator/Builder.pm	Tue Nov 06 20:00:57 2012 +0400
+++ b/Lib/IMPL/DOM/Navigator/Builder.pm	Wed Nov 07 04:17:53 2012 +0400
@@ -41,6 +41,7 @@
         my $schemaSource = $this->{$_schemaNavi}->SourceSchemaNode;
         
         my @errors = $this->inflateProperties($schemaNode,\%props);
+
         $props{schema} = $schemaNode;
         $props{schemaSource} = $schemaSource;
         
@@ -49,7 +50,7 @@
             $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props);
             $this->_initNavigator($node);
         } else {
-            die new IMPL::InvalidOperationException('Can     create a second top level element') unless $this->Current;
+            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);
@@ -93,8 +94,9 @@
 }
 
 sub inflateValue {
-    my ($this,$value,$node) = @_;
+    my ($this,$value,$node,$strict) = @_;
     
+    $strict ||= 0;
     $node ||= $this->Current;
     
     my $nodeSchema = $this->{$_schemaNavi}->Current;
@@ -108,7 +110,7 @@
             message => $nodeSchema->messageInflateError,
             source => $this->{$_schemaNavi}->SourceSchemaNode
         ));
-        return $value;
+        return $strict ? undef : $value ;
     } else {
         return $result;
     }
@@ -140,6 +142,10 @@
     goto &BuildErrors;
 }
 
+sub document {
+    goto &Document;
+}
+
 1;
 
 __END__
@@ -168,32 +174,53 @@
 Построитель DOM документов по указанной схеме. Обычно используется в связке
 с объектами для чтения такими как C<IMPL::DOM::XMLReader>.
 
-=head1 METHODS
+=head1 MEMBERS
 
-=over
-
-=item C< CTOR($classDocument,$schema) >
+=head2 C< CTOR($classDocument,$schema, %opts) >
 
 Создает новый объект, принимает на вход класс документа (или фабрику, например
 L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа
 будет создан объект документа.
 
-=item C< NavigateCreate($nodeName,\%props) >
+Необязательные именованные параметры
+
+=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<%props>, но имя
+создаваемого узла НЕ может быть переопределено свойством C<nodeName>, оно будет
+проигнорировано.
 
-=item C< Document >
+Свойства узла будут преобразованы при помощи заданных в схеме заполнителей
+C<inflator>.
+
+=head2 C<[get]document >
 
 Свойство, которое содержит документ по окончании процедуры построения.
 
-=back
+=head2 C<[get]buildErrors>
+
+Ошибки, возникшие в процессе построения документа.
+
+=head2 C<[get]ignoreUndefined>
+
+Опция, заданная при создании построителя, отвечающая за обработку узлов
+не найденных в схеме.
 
 =cut
--- a/Lib/IMPL/DOM/Schema.pm	Tue Nov 06 20:00:57 2012 +0400
+++ b/Lib/IMPL/DOM/Schema.pm	Wed Nov 07 04:17:53 2012 +0400
@@ -37,6 +37,7 @@
 
 my $validatorLoader = Loader->new(prefix => Validator, verifyNames => 1);
 
+#TODO rename and remove
 sub resolveType {
     $_[0]->{$_TypesMap}->{$_[1]} or die IMPL::KeyNotFoundException->new($_[1]);
 }
@@ -47,6 +48,11 @@
     $this->{$baseDir} = ($args{baseDir} || '.');
 }
 
+# compat
+sub ResolveType {
+    goto &resolveType
+}
+
 sub Create {
     my ($this,$nodeName,$class,$refArgs) = @_;
     
--- a/Lib/IMPL/DOM/Transform/ObjectToDOM.pm	Tue Nov 06 20:00:57 2012 +0400
+++ b/Lib/IMPL/DOM/Transform/ObjectToDOM.pm	Wed Nov 07 04:17:53 2012 +0400
@@ -12,9 +12,9 @@
     },
     base => [
         'IMPL::Transform' => sub {
-            -plain => \&TransformPlain,
-            HASH => \&TransformHash,
-            -default => \&TransformDefault
+            -plain => 'TransformPlain',
+            HASH => 'TransformHash',
+            -default => 'TransformDefault'
         }
     ],
     props => [
@@ -25,7 +25,8 @@
 };
 
 use constant {
-    SchemaNode => 'IMPL::DOM::Schema::Node'
+    SchemaNode => 'IMPL::DOM::Schema::Node',
+    ComplexNode => 'IMPL::DOM::Schema::ComplexNode'
 };
 
 sub CTOR {
@@ -53,15 +54,26 @@
 sub TransformPlain {
     my ($this,$data) = @_;
     
-    $this->_navi->Current->nodeValue( $this->_navi->inflateValue($data) );
+    $this->_navi->Current->nodeValue( $data );
     return $this->_navi->Current;
 }
 
+sub currentNode {
+    shift->_navi->Current;
+}
+
+sub inflateNodeValue {
+    shift->_navi->inflateValue(shift);
+}
+
 sub TransformHash {
     my ($this,$data) = @_;
     
     die ArgumentException->new(data => 'A HASH reference is required')
         unless ref $data eq 'HASH';
+        
+    return $this->StoreObject($this->currentNode,$data)
+        if !$this->currentNode->schema->isa(ComplexNode);
 
     KEYLOOP: foreach my $key (keys %$data) {
         my $value = $data->{$key};
@@ -69,25 +81,36 @@
         if (ref $value eq 'ARRAY') {
             foreach my $subval (@$value) {
                 
+                $this->_navi->saveState();
+                
                 my $node = $this->_navi->NavigateCreate($key);
                 
                 unless(defined $node) {
-                    $this->_navi->Back();
+                    #$this->_navi->Back();
+                    $this->_navi->restoreState();
                     next KEYLOOP;
                 }
                 
+                $this->_navi->applyState();
+                
                 $this->Transform($subval);
                 
                 $this->_navi->Back();
             }
         } else {
+            $this->_navi->saveState();
             my $node = $this->_navi->NavigateCreate($key);
-                
+
             unless(defined $node) {
-                $this->_navi->Back();
+                #$this->_navi->Back();
+                $this->_navi->restoreState();
                 next KEYLOOP;
             }
             
+            $this->_navi->applyState();
+            
+            warn "$key = $value";
+            
             $this->Transform($value);
             
             $this->_navi->Back();            
@@ -96,9 +119,24 @@
     return $this->_navi->Current;
 }
 
+# this method handles situatuions when a complex object must be stored in a
+# simple node.
+sub StoreObject {
+    my ($this,$node,$data) = @_;
+    
+    $node->nodeValue($data);
+    
+    warn "Stored value for", $node->nodeName;
+    
+    return $node;
+}
+
 sub TransformDefault {
     my ($this,$data) = @_;
     
+    return $this->StoreObject($this->currentNode,$data)
+        if !$this->currentNode->schema->isa(ComplexNode);
+    
     if ( ref $data and eval { $data->can('GetMeta') } ) {
         my %props = map {
             $_->name, 1
--- a/Lib/IMPL/DOM/Transform/QueryToDOM.pm	Tue Nov 06 20:00:57 2012 +0400
+++ b/Lib/IMPL/DOM/Transform/QueryToDOM.pm	Wed Nov 07 04:17:53 2012 +0400
@@ -21,6 +21,22 @@
 	$this->prefix('');
 }
 
+# inflate simple properties
+sub TransformPlain {
+    my ($this,$data) = @_;
+    
+    $this->currentNode->nodeProperty( rawValue => $data );
+    $this->currentNode->nodeValue( $this->inflateNodeValue($data) );
+    return $this->currentNode;
+}
+
+# do not store complex data as node values
+sub StoreObject {
+    my ($this,$node,$data) = @_;
+    
+    return $node;
+}
+
 sub TransformCGI {
 	my ($this,$query) = @_;