Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Navigator/Builder.pm @ 359:833e663796c4
TTView: added view variable to pass rendering context between controls
TTView: display function renamed to display_for
WebResource: resources now marked with roles for searching a desired resource by a role in the resource chain
| author | sergey |
|---|---|
| date | Mon, 25 Nov 2013 02:19:31 +0400 |
| parents | 4ddb27ff4a0b |
| children | 010ceafd0c5a |
| rev | line source |
|---|---|
| 49 | 1 package IMPL::DOM::Navigator::Builder; |
| 2 use strict; | |
| 3 use warnings; | |
| 4 | |
| 236 | 5 use IMPL::Const qw(:prop); |
| 6 | |
| 165 | 7 use parent qw(IMPL::DOM::Navigator); |
| 49 | 8 use IMPL::Class::Property; |
| 9 require IMPL::DOM::Navigator::SchemaNavigator; | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
10 require IMPL::DOM::Schema::ValidationError; |
| 106 | 11 use IMPL::DOM::Document; |
| 49 | 12 |
| 13 BEGIN { | |
| 236 | 14 private _direct property _schemaNavi => PROP_RW; |
| 15 private _direct property _docClass => PROP_RW; | |
| 16 public _direct property BuildErrors => PROP_RO | PROP_LIST; | |
| 17 public _direct property Document => PROP_RO; | |
| 18 public _direct property ignoreUndefined => PROP_RO; | |
| 49 | 19 } |
| 20 | |
| 106 | 21 our %CTOR = ( |
| 112 | 22 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document->Empty; } |
| 106 | 23 ); |
| 24 | |
| 49 | 25 sub CTOR { |
| 236 | 26 my ($this,$docClass,$schema,%opts) = @_; |
| 49 | 27 |
| 28 $this->{$_docClass} = $docClass; | |
| 29 $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef; | |
| 236 | 30 |
| 31 $this->{$ignoreUndefined} = $opts{ignoreUndefined} if $opts{ignoreUndefined}; | |
| 49 | 32 } |
| 33 | |
| 34 sub NavigateCreate { | |
| 35 my ($this,$nodeName,%props) = @_; | |
| 36 | |
| 37 if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) { | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
38 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
|
39 |
|
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
40 my $schemaSource = $this->{$_schemaNavi}->SourceSchemaNode; |
|
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
41 |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
42 my @errors = $this->inflateProperties($schemaNode,\%props); |
| 250 | 43 |
|
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
44 $props{schema} = $schemaNode; |
|
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
45 $props{schemaSource} = $schemaSource; |
| 49 | 46 |
| 47 my $node; | |
| 48 if (! $this->{$Document}) { | |
| 49 $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props); | |
| 106 | 50 $this->_initNavigator($node); |
| 49 | 51 } else { |
| 250 | 52 die new IMPL::InvalidOperationException('Can\'t create a second top level element') unless $this->Current; |
| 49 | 53 $node = $this->{$Document}->Create($nodeName,$class,\%props); |
| 106 | 54 $this->Current->appendChild($node); |
| 55 $this->internalNavigateNodeSet($node); | |
| 49 | 56 } |
| 57 | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
58 if (@errors) { |
| 194 | 59 $this->BuildErrors->Append( |
| 60 map { | |
| 61 IMPL::DOM::Schema::ValidationError->new( | |
| 236 | 62 node => $node, |
| 63 source => $schemaSource, | |
| 64 schema => $schemaNode, | |
| 65 message => $schemaNode->messageInflateError, | |
| 66 error => $_ | |
| 194 | 67 ) |
| 68 } @errors | |
| 69 ); | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
70 } |
|
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
71 |
| 49 | 72 return $node; |
| 73 } else { | |
| 236 | 74 die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName) |
| 238 | 75 if !$this->ignoreUndefined; |
| 236 | 76 return; |
| 49 | 77 } |
| 78 } | |
| 79 | |
| 103 | 80 sub inflateProperties { |
| 194 | 81 my ($this,$schemaNode,$refProps) = @_; |
| 82 my @errors; | |
| 83 foreach my $schemaProp ( $schemaNode->selectNodes('Property') ) { | |
| 84 next if not exists $refProps->{$schemaProp->name}; | |
| 85 my $result = eval {$schemaProp->inflateValue($refProps->{$schemaProp->name}) }; | |
| 86 if (my $e = $@) { | |
| 87 push @errors, $e; | |
| 88 } else { | |
| 89 $refProps->{$schemaProp->name} = $result; | |
| 90 } | |
| 91 } | |
| 92 return @errors; | |
| 103 | 93 } |
| 94 | |
| 95 sub inflateValue { | |
| 250 | 96 my ($this,$value,$node,$strict) = @_; |
| 194 | 97 |
| 250 | 98 $strict ||= 0; |
| 194 | 99 $node ||= $this->Current; |
| 100 | |
| 101 my $nodeSchema = $this->{$_schemaNavi}->Current; | |
| 102 | |
| 103 my $result = eval { $nodeSchema->inflateValue($value) }; | |
| 104 if (my $e=$@) { | |
| 105 $this->BuildErrors->Append(new IMPL::DOM::Schema::ValidationError( | |
| 246 | 106 schema => $nodeSchema, |
| 107 node => $node, | |
| 108 error => $e, | |
| 109 message => $nodeSchema->messageInflateError, | |
| 110 source => $this->{$_schemaNavi}->SourceSchemaNode | |
| 194 | 111 )); |
| 250 | 112 return $strict ? undef : $value ; |
| 194 | 113 } else { |
| 114 return $result; | |
| 115 } | |
| 103 | 116 } |
| 117 | |
| 49 | 118 sub Back { |
| 119 my ($this) = @_; | |
| 120 | |
| 121 $this->{$_schemaNavi}->SchemaBack(); | |
| 106 | 122 $this->SUPER::Back(); |
| 49 | 123 } |
| 124 | |
| 112 | 125 sub saveState { |
| 194 | 126 my ($this) = @_; |
| 127 | |
| 128 $this->{$_schemaNavi}->saveState; | |
| 129 $this->SUPER::saveState; | |
| 112 | 130 } |
| 131 | |
| 132 sub restoreState { | |
| 194 | 133 my ($this) = @_; |
| 134 | |
| 135 $this->{$_schemaNavi}->restoreState; | |
| 136 $this->SUPER::restoreState; | |
| 112 | 137 } |
| 138 | |
| 236 | 139 #compatibility |
| 140 sub buildErrors { | |
| 141 goto &BuildErrors; | |
| 142 } | |
| 143 | |
| 250 | 144 sub document { |
| 145 goto &Document; | |
| 146 } | |
| 147 | |
| 49 | 148 1; |
| 149 | |
| 150 __END__ | |
| 64 | 151 |
| 49 | 152 =pod |
| 153 | |
| 64 | 154 =head1 NAME |
| 155 | |
| 180 | 156 C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме. |
| 64 | 157 |
| 49 | 158 =head1 SYNOPSIS |
| 159 | |
| 64 | 160 =begin code |
| 161 | |
| 49 | 162 my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema); |
| 163 my $reader = new IMPL::DOM::XMLReader(Navigator => $builder); | |
| 164 | |
| 165 $reader->ParseFile("document.xml"); | |
| 166 | |
| 167 my @errors = $schema->Validate($builder->Document); | |
| 168 | |
| 64 | 169 =end code |
| 170 | |
| 49 | 171 =head1 DESCRIPTION |
| 172 | |
| 180 | 173 Построитель DOM документов по указанной схеме. Обычно используется в связке |
| 174 с объектами для чтения такими как C<IMPL::DOM::XMLReader>. | |
| 49 | 175 |
| 250 | 176 =head1 MEMBERS |
| 49 | 177 |
| 250 | 178 =head2 C< CTOR($classDocument,$schema, %opts) > |
| 49 | 179 |
| 180 | 180 Создает новый объект, принимает на вход класс документа (или фабрику, например |
| 181 L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа | |
| 182 будет создан объект документа. | |
| 49 | 183 |
| 250 | 184 Необязательные именованные параметры |
| 185 | |
| 186 =over | |
| 187 | |
| 188 =item C<ignoreUndefined> | |
| 189 | |
| 190 C<NavigateCreate> не будет вызывать исключение, если запрашиваемый узел не | |
| 191 найден в схеме, но будет возвращать C<undef>. | |
| 192 | |
| 193 =back | |
| 194 | |
| 195 =head2 C< NavigateCreate($nodeName,%props) > | |
| 49 | 196 |
| 180 | 197 Создает новый узел с указанным именем и переходит в него. В случае если в схеме |
| 250 | 198 подходящий узел не найден, то вызывается исключение или будет возвращено |
| 199 C<undef> см. C<ignoreUndefined>. | |
| 49 | 200 |
| 180 | 201 При этом по имени узла ищется его схема, после чего определяется класс для |
| 250 | 202 создания экземпляра узла и созданный узел доавляется в документ. При создании |
| 180 | 203 нового узла используется метод документа C<< IMPL::DOM::Document->Create >> |
| 49 | 204 |
| 250 | 205 Свойства узла передаются при создании через параметр C<%props>, но имя |
| 206 создаваемого узла НЕ может быть переопределено свойством C<nodeName>, оно будет | |
| 207 проигнорировано. | |
| 64 | 208 |
| 250 | 209 Свойства узла будут преобразованы при помощи заданных в схеме заполнителей |
| 210 C<inflator>. | |
| 211 | |
| 212 =head2 C<[get]document > | |
| 64 | 213 |
| 180 | 214 Свойство, которое содержит документ по окончании процедуры построения. |
| 49 | 215 |
| 250 | 216 =head2 C<[get]buildErrors> |
| 217 | |
| 218 Ошибки, возникшие в процессе построения документа. | |
| 219 | |
| 220 =head2 C<[get]ignoreUndefined> | |
| 221 | |
| 222 Опция, заданная при создании построителя, отвечающая за обработку узлов | |
| 223 не найденных в схеме. | |
| 49 | 224 |
| 225 =cut |
