view Lib/IMPL/DOM/Transform/ObjectToDOM.pm @ 246:2746a8e5a6c4

Fixed regressions in DOM due previous refactorings Fixed ObjectToDOM transformation to handle a schema with mixed node types
author sergey
date Tue, 30 Oct 2012 01:17:31 +0400
parents 61db68166c37
children 129e48bb5afb
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'
};

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( $this->_navi->inflateValue($data) );
    return $this->_navi->Current;
}

sub TransformHash {
    my ($this,$data) = @_;
    
    die ArgumentException->new(data => 'A HASH reference is required')
        unless ref $data eq 'HASH';

    KEYLOOP: foreach my $key (keys %$data) {
        my $value = $data->{$key};
        
        if (ref $value eq 'ARRAY') {
            foreach my $subval (@$value) {
                
                my $node = $this->_navi->NavigateCreate($key);
                
                unless(defined $node) {
                    $this->_navi->Back();
                    next KEYLOOP;
                }
                
                $this->Transform($subval);
                
                $this->_navi->Back();
            }
        } else {
            my $node = $this->_navi->NavigateCreate($key);
                
            unless(defined $node) {
                $this->_navi->Back();
                next KEYLOOP;
            }
            
            $this->Transform($value);
            
            $this->_navi->Back();            
        }
    }
    return $this->_navi->Current;
}

sub TransformDefault {
    my ($this,$data) = @_;
    
    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