236
|
1 package IMPL::DOM::Transform::ObjectToDOM;
|
|
2 use strict;
|
|
3
|
|
4 use IMPL::Const qw(:prop :access);
|
|
5 use IMPL::declare {
|
|
6 require => {
|
|
7 PropertyInfo => 'IMPL::Class::PropertyInfo',
|
|
8 Builder => 'IMPL::DOM::Navigator::Builder',
|
|
9 Exception => 'IMPL::Exception',
|
|
10 ArgumentException => '-IMPL::InvalidArgumentException',
|
|
11 OperationException => '-IMPL::InvalidOperationException'
|
|
12 },
|
|
13 base => [
|
|
14 'IMPL::Transform' => sub {
|
250
|
15 -plain => 'TransformPlain',
|
|
16 HASH => 'TransformHash',
|
|
17 -default => 'TransformDefault'
|
236
|
18 }
|
|
19 ],
|
|
20 props => [
|
|
21 documentSchema => PROP_RO,
|
|
22 _schema => PROP_RW,
|
|
23 _navi => PROP_RW
|
|
24 ]
|
|
25 };
|
|
26
|
246
|
27 use constant {
|
250
|
28 SchemaNode => 'IMPL::DOM::Schema::Node',
|
|
29 ComplexNode => 'IMPL::DOM::Schema::ComplexNode'
|
246
|
30 };
|
|
31
|
236
|
32 sub CTOR {
|
237
|
33 my ($this,$docName,$docSchema,$transforms) = @_;
|
236
|
34
|
246
|
35 my $docNodeSchema = $docSchema->selectSingleNode(sub { $_->isa(SchemaNode) and $_->name eq $docName } )
|
236
|
36 or die OperationException->new("Can't find a node schema for the document '$docName'");
|
|
37
|
|
38 my $docClass = ($docNodeSchema->can('nativeType') ? $docNodeSchema->nativeType : undef) || 'IMPL::DOM::Document';
|
|
39
|
|
40 $this->documentSchema($docNodeSchema);
|
|
41
|
|
42 $this->_navi(
|
|
43 Builder->new(
|
|
44 $docClass,
|
|
45 $docSchema,
|
|
46 ignoreUndefined => 1
|
|
47 )
|
|
48 );
|
|
49 $this->_schema($docSchema);
|
|
50
|
|
51 $this->_navi->NavigateCreate($docName);
|
|
52 }
|
|
53
|
|
54 sub TransformPlain {
|
|
55 my ($this,$data) = @_;
|
|
56
|
250
|
57 $this->_navi->Current->nodeValue( $data );
|
236
|
58 return $this->_navi->Current;
|
|
59 }
|
|
60
|
250
|
61 sub currentNode {
|
|
62 shift->_navi->Current;
|
|
63 }
|
|
64
|
|
65 sub inflateNodeValue {
|
|
66 shift->_navi->inflateValue(shift);
|
|
67 }
|
|
68
|
236
|
69 sub TransformHash {
|
|
70 my ($this,$data) = @_;
|
|
71
|
|
72 die ArgumentException->new(data => 'A HASH reference is required')
|
|
73 unless ref $data eq 'HASH';
|
250
|
74
|
|
75 return $this->StoreObject($this->currentNode,$data)
|
|
76 if !$this->currentNode->schema->isa(ComplexNode);
|
236
|
77
|
|
78 KEYLOOP: foreach my $key (keys %$data) {
|
|
79 my $value = $data->{$key};
|
|
80
|
|
81 if (ref $value eq 'ARRAY') {
|
257
|
82 #TODO: collapse empty values only if needed
|
|
83 foreach my $subval (grep $_, @$value) {
|
236
|
84
|
250
|
85 $this->_navi->saveState();
|
|
86
|
236
|
87 my $node = $this->_navi->NavigateCreate($key);
|
|
88
|
|
89 unless(defined $node) {
|
250
|
90 #$this->_navi->Back();
|
|
91 $this->_navi->restoreState();
|
236
|
92 next KEYLOOP;
|
|
93 }
|
|
94
|
250
|
95 $this->_navi->applyState();
|
|
96
|
236
|
97 $this->Transform($subval);
|
|
98
|
|
99 $this->_navi->Back();
|
|
100 }
|
|
101 } else {
|
250
|
102 $this->_navi->saveState();
|
236
|
103 my $node = $this->_navi->NavigateCreate($key);
|
250
|
104
|
236
|
105 unless(defined $node) {
|
250
|
106 #$this->_navi->Back();
|
|
107 $this->_navi->restoreState();
|
236
|
108 next KEYLOOP;
|
|
109 }
|
|
110
|
250
|
111 $this->_navi->applyState();
|
|
112
|
236
|
113 $this->Transform($value);
|
|
114
|
|
115 $this->_navi->Back();
|
|
116 }
|
|
117 }
|
|
118 return $this->_navi->Current;
|
|
119 }
|
|
120
|
250
|
121 # this method handles situatuions when a complex object must be stored in a
|
|
122 # simple node.
|
|
123 sub StoreObject {
|
|
124 my ($this,$node,$data) = @_;
|
|
125
|
|
126 $node->nodeValue($data);
|
|
127
|
|
128 return $node;
|
|
129 }
|
|
130
|
236
|
131 sub TransformDefault {
|
|
132 my ($this,$data) = @_;
|
|
133
|
250
|
134 return $this->StoreObject($this->currentNode,$data)
|
|
135 if !$this->currentNode->schema->isa(ComplexNode);
|
|
136
|
236
|
137 if ( ref $data and eval { $data->can('GetMeta') } ) {
|
|
138 my %props = map {
|
|
139 $_->name, 1
|
|
140 } $data->GetMeta(PropertyInfo, sub { $_->access == ACCESS_PUBLIC }, 1 );
|
|
141
|
|
142 my %values = map {
|
|
143 $_,
|
|
144 $data->$_();
|
|
145 } keys %props;
|
|
146
|
|
147 return $this->Transform(\%values);
|
|
148 } else {
|
|
149 die OperationException->new("Don't know how to transform $data");
|
|
150 }
|
|
151
|
|
152 return $this->_navi->Current;
|
|
153 }
|
|
154
|
|
155 sub buildErrors {
|
|
156 my ($this) = @_;
|
|
157
|
|
158 return $this->_navi->buildErrors;
|
|
159 }
|
|
160
|
|
161 1;
|
|
162
|
|
163 __END__
|
|
164
|
|
165 =pod
|
|
166
|
|
167 =head1 NAME
|
|
168
|
|
169 C<IMPL::DOM::Transform::ObjectToDOM> -преобразование объекта
|
|
170
|
|
171 =head1 SYNOPSIS
|
|
172
|
|
173 =cut |