Mercurial > pub > Impl
view Lib/IMPL/DOM/Transform/ObjectToDOM.pm @ 251:9f394b27dccf
require can handle recursive module references
author | sergey |
---|---|
date | Fri, 16 Nov 2012 16:44:16 +0400 |
parents | 129e48bb5afb |
children | 299af584c05f |
line wrap: on
line source
package IMPL::DOM::Transform::ObjectToDOM; use strict; use IMPL::Const qw(:prop :access); use IMPL::declare { require => { PropertyInfo => 'IMPL::Class::PropertyInfo', Builder => 'IMPL::DOM::Navigator::Builder', Exception => 'IMPL::Exception', ArgumentException => '-IMPL::InvalidArgumentException', OperationException => '-IMPL::InvalidOperationException' }, base => [ 'IMPL::Transform' => sub { -plain => 'TransformPlain', HASH => 'TransformHash', -default => 'TransformDefault' } ], props => [ documentSchema => PROP_RO, _schema => PROP_RW, _navi => PROP_RW ] }; use constant { SchemaNode => 'IMPL::DOM::Schema::Node', ComplexNode => 'IMPL::DOM::Schema::ComplexNode' }; sub CTOR { my ($this,$docName,$docSchema,$transforms) = @_; my $docNodeSchema = $docSchema->selectSingleNode(sub { $_->isa(SchemaNode) and $_->name eq $docName } ) or die OperationException->new("Can't find a node schema for the document '$docName'"); my $docClass = ($docNodeSchema->can('nativeType') ? $docNodeSchema->nativeType : undef) || 'IMPL::DOM::Document'; $this->documentSchema($docNodeSchema); $this->_navi( Builder->new( $docClass, $docSchema, ignoreUndefined => 1 ) ); $this->_schema($docSchema); $this->_navi->NavigateCreate($docName); } sub TransformPlain { my ($this,$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}; 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->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->restoreState(); next KEYLOOP; } $this->_navi->applyState(); warn "$key = $value"; $this->Transform($value); $this->_navi->Back(); } } 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 } $data->GetMeta(PropertyInfo, sub { $_->access == ACCESS_PUBLIC }, 1 ); my %values = map { $_, $data->$_(); } keys %props; return $this->Transform(\%values); } else { die OperationException->new("Don't know how to transform $data"); } return $this->_navi->Current; } sub buildErrors { my ($this) = @_; return $this->_navi->buildErrors; } 1; __END__ =pod =head1 NAME C<IMPL::DOM::Transform::ObjectToDOM> -преобразование объекта =head1 SYNOPSIS =cut