Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Navigator/Builder.pm @ 211:2b9b55cfb79b
Completed IMPL::Web::AutoLocator, added tests
author | cin |
---|---|
date | Tue, 05 Jun 2012 07:45:21 +0400 |
parents | c8fe3f84feba |
children | 2904da230022 |
rev | line source |
---|---|
49 | 1 package IMPL::DOM::Navigator::Builder; |
2 use strict; | |
3 use warnings; | |
4 | |
165 | 5 use parent qw(IMPL::DOM::Navigator); |
49 | 6 use IMPL::Class::Property; |
7 use IMPL::Class::Property::Direct; | |
8 require IMPL::DOM::Navigator::SchemaNavigator; | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
9 require IMPL::DOM::Schema::ValidationError; |
106 | 10 use IMPL::DOM::Document; |
49 | 11 |
12 BEGIN { | |
13 private _direct property _schemaNavi => prop_all; | |
103 | 14 private _direct property _docClass => prop_all; |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
15 public _direct property BuildErrors => prop_get | prop_list; |
49 | 16 public _direct property Document => prop_get | owner_set; |
17 } | |
18 | |
106 | 19 our %CTOR = ( |
112 | 20 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document->Empty; } |
106 | 21 ); |
22 | |
49 | 23 sub CTOR { |
24 my ($this,$docClass,$schema) = @_; | |
25 | |
26 $this->{$_docClass} = $docClass; | |
27 $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef; | |
28 } | |
29 | |
30 sub NavigateCreate { | |
31 my ($this,$nodeName,%props) = @_; | |
32 | |
33 if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) { | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
34 my $class = $schemaNode->can('nativeType') ? $schemaNode->nativeType || 'IMPL::DOM::Node' : 'IMPL::DOM::Node'; |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
35 |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
36 my $schemaSource = $this->{$_schemaNavi}->SourceSchemaNode; |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
37 |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
38 my @errors = $this->inflateProperties($schemaNode,\%props); |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
39 $props{schema} = $schemaNode; |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
40 $props{schemaSource} = $schemaSource; |
49 | 41 |
42 my $node; | |
43 if (! $this->{$Document}) { | |
44 $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props); | |
106 | 45 $this->_initNavigator($node); |
49 | 46 } else { |
206 | 47 die new IMPL::InvalidOperationException('Can create a second top level element') unless $this->Current; |
49 | 48 $node = $this->{$Document}->Create($nodeName,$class,\%props); |
106 | 49 $this->Current->appendChild($node); |
50 $this->internalNavigateNodeSet($node); | |
49 | 51 } |
52 | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
53 if (@errors) { |
194 | 54 $this->BuildErrors->Append( |
55 map { | |
56 IMPL::DOM::Schema::ValidationError->new( | |
57 Node => $node, | |
58 Source => $schemaSource, | |
59 Schema => $schemaNode, | |
60 Message => $schemaNode->messageInflateError, | |
61 Error => $_ | |
62 ) | |
63 } @errors | |
64 ); | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
65 } |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
66 |
49 | 67 return $node; |
68 } else { | |
69 die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName); | |
70 } | |
71 } | |
72 | |
103 | 73 sub inflateProperties { |
194 | 74 my ($this,$schemaNode,$refProps) = @_; |
75 my @errors; | |
76 foreach my $schemaProp ( $schemaNode->selectNodes('Property') ) { | |
77 next if not exists $refProps->{$schemaProp->name}; | |
78 my $result = eval {$schemaProp->inflateValue($refProps->{$schemaProp->name}) }; | |
79 if (my $e = $@) { | |
80 push @errors, $e; | |
81 } else { | |
82 $refProps->{$schemaProp->name} = $result; | |
83 } | |
84 } | |
85 return @errors; | |
103 | 86 } |
87 | |
88 sub inflateValue { | |
194 | 89 my ($this,$value,$node) = @_; |
90 | |
91 $node ||= $this->Current; | |
92 | |
93 my $nodeSchema = $this->{$_schemaNavi}->Current; | |
94 | |
95 my $result = eval { $nodeSchema->inflateValue($value) }; | |
96 if (my $e=$@) { | |
97 $this->BuildErrors->Append(new IMPL::DOM::Schema::ValidationError( | |
98 Schema => $nodeSchema, | |
99 Node => $node, | |
100 Error => $e, | |
101 Message => $nodeSchema->messageInflateError, | |
102 Source => $this->{$_schemaNavi}->SourceSchemaNode | |
103 )); | |
104 return $value; | |
105 } else { | |
106 return $result; | |
107 } | |
103 | 108 } |
109 | |
49 | 110 sub Back { |
111 my ($this) = @_; | |
112 | |
113 $this->{$_schemaNavi}->SchemaBack(); | |
106 | 114 $this->SUPER::Back(); |
49 | 115 } |
116 | |
112 | 117 sub saveState { |
194 | 118 my ($this) = @_; |
119 | |
120 $this->{$_schemaNavi}->saveState; | |
121 $this->SUPER::saveState; | |
112 | 122 } |
123 | |
124 sub restoreState { | |
194 | 125 my ($this) = @_; |
126 | |
127 $this->{$_schemaNavi}->restoreState; | |
128 $this->SUPER::restoreState; | |
112 | 129 } |
130 | |
49 | 131 1; |
132 | |
133 __END__ | |
64 | 134 |
49 | 135 =pod |
136 | |
64 | 137 =head1 NAME |
138 | |
180 | 139 C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме. |
64 | 140 |
49 | 141 =head1 SYNOPSIS |
142 | |
64 | 143 =begin code |
144 | |
49 | 145 my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema); |
146 my $reader = new IMPL::DOM::XMLReader(Navigator => $builder); | |
147 | |
148 $reader->ParseFile("document.xml"); | |
149 | |
150 my @errors = $schema->Validate($builder->Document); | |
151 | |
64 | 152 =end code |
153 | |
49 | 154 =head1 DESCRIPTION |
155 | |
180 | 156 Построитель DOM документов по указанной схеме. Обычно используется в связке |
157 с объектами для чтения такими как C<IMPL::DOM::XMLReader>. | |
49 | 158 |
159 =head1 METHODS | |
160 | |
161 =over | |
162 | |
64 | 163 =item C< CTOR($classDocument,$schema) > |
49 | 164 |
180 | 165 Создает новый объект, принимает на вход класс документа (или фабрику, например |
166 L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа | |
167 будет создан объект документа. | |
49 | 168 |
64 | 169 =item C< NavigateCreate($nodeName,\%props) > |
49 | 170 |
180 | 171 Создает новый узел с указанным именем и переходит в него. В случае если в схеме |
172 подходящий узел не найден, то вызывается исключение. | |
49 | 173 |
180 | 174 При этом по имени узла ищется его схема, после чего определяется класс для |
175 создания экземпляра и созданный узел доавляется в документ. При создании | |
176 нового узла используется метод документа C<< IMPL::DOM::Document->Create >> | |
49 | 177 |
180 | 178 Свойства узла передаются при создании через параметр C<%props>, но имя создаваемого |
179 узла НЕ может быть переопределено свойством C<nodeName>, оно будет проигнорировано. | |
64 | 180 |
181 =item C< Document > | |
182 | |
180 | 183 Свойство, которое содержит документ по окончании процедуры построения. |
49 | 184 |
185 =back | |
186 | |
187 =cut |