Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Navigator/Builder.pm @ 247:2270de2469ff
sync
| author | sergey |
|---|---|
| date | Wed, 31 Oct 2012 04:18:35 +0400 |
| parents | 2746a8e5a6c4 |
| children | 129e48bb5afb |
| 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 use IMPL::Class::Property::Direct; | |
| 10 require IMPL::DOM::Navigator::SchemaNavigator; | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
11 require IMPL::DOM::Schema::ValidationError; |
| 106 | 12 use IMPL::DOM::Document; |
| 49 | 13 |
| 14 BEGIN { | |
| 236 | 15 private _direct property _schemaNavi => PROP_RW; |
| 16 private _direct property _docClass => PROP_RW; | |
| 17 public _direct property BuildErrors => PROP_RO | PROP_LIST; | |
| 18 public _direct property Document => PROP_RO; | |
| 19 public _direct property ignoreUndefined => PROP_RO; | |
| 49 | 20 } |
| 21 | |
| 106 | 22 our %CTOR = ( |
| 112 | 23 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document->Empty; } |
| 106 | 24 ); |
| 25 | |
| 49 | 26 sub CTOR { |
| 236 | 27 my ($this,$docClass,$schema,%opts) = @_; |
| 49 | 28 |
| 29 $this->{$_docClass} = $docClass; | |
| 30 $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef; | |
| 236 | 31 |
| 32 $this->{$ignoreUndefined} = $opts{ignoreUndefined} if $opts{ignoreUndefined}; | |
| 49 | 33 } |
| 34 | |
| 35 sub NavigateCreate { | |
| 36 my ($this,$nodeName,%props) = @_; | |
| 37 | |
| 38 if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) { | |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
39 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
|
40 |
|
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
41 my $schemaSource = $this->{$_schemaNavi}->SourceSchemaNode; |
|
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
113
diff
changeset
|
42 |
|
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
103
diff
changeset
|
43 my @errors = $this->inflateProperties($schemaNode,\%props); |
|
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 { |
| 206 | 52 die new IMPL::InvalidOperationException('Can 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 { | |
| 194 | 96 my ($this,$value,$node) = @_; |
| 97 | |
| 98 $node ||= $this->Current; | |
| 99 | |
| 100 my $nodeSchema = $this->{$_schemaNavi}->Current; | |
| 101 | |
| 102 my $result = eval { $nodeSchema->inflateValue($value) }; | |
| 103 if (my $e=$@) { | |
| 104 $this->BuildErrors->Append(new IMPL::DOM::Schema::ValidationError( | |
| 246 | 105 schema => $nodeSchema, |
| 106 node => $node, | |
| 107 error => $e, | |
| 108 message => $nodeSchema->messageInflateError, | |
| 109 source => $this->{$_schemaNavi}->SourceSchemaNode | |
| 194 | 110 )); |
| 111 return $value; | |
| 112 } else { | |
| 113 return $result; | |
| 114 } | |
| 103 | 115 } |
| 116 | |
| 49 | 117 sub Back { |
| 118 my ($this) = @_; | |
| 119 | |
| 120 $this->{$_schemaNavi}->SchemaBack(); | |
| 106 | 121 $this->SUPER::Back(); |
| 49 | 122 } |
| 123 | |
| 112 | 124 sub saveState { |
| 194 | 125 my ($this) = @_; |
| 126 | |
| 127 $this->{$_schemaNavi}->saveState; | |
| 128 $this->SUPER::saveState; | |
| 112 | 129 } |
| 130 | |
| 131 sub restoreState { | |
| 194 | 132 my ($this) = @_; |
| 133 | |
| 134 $this->{$_schemaNavi}->restoreState; | |
| 135 $this->SUPER::restoreState; | |
| 112 | 136 } |
| 137 | |
| 236 | 138 #compatibility |
| 139 sub buildErrors { | |
| 140 goto &BuildErrors; | |
| 141 } | |
| 142 | |
| 49 | 143 1; |
| 144 | |
| 145 __END__ | |
| 64 | 146 |
| 49 | 147 =pod |
| 148 | |
| 64 | 149 =head1 NAME |
| 150 | |
| 180 | 151 C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме. |
| 64 | 152 |
| 49 | 153 =head1 SYNOPSIS |
| 154 | |
| 64 | 155 =begin code |
| 156 | |
| 49 | 157 my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema); |
| 158 my $reader = new IMPL::DOM::XMLReader(Navigator => $builder); | |
| 159 | |
| 160 $reader->ParseFile("document.xml"); | |
| 161 | |
| 162 my @errors = $schema->Validate($builder->Document); | |
| 163 | |
| 64 | 164 =end code |
| 165 | |
| 49 | 166 =head1 DESCRIPTION |
| 167 | |
| 180 | 168 Построитель DOM документов по указанной схеме. Обычно используется в связке |
| 169 с объектами для чтения такими как C<IMPL::DOM::XMLReader>. | |
| 49 | 170 |
| 171 =head1 METHODS | |
| 172 | |
| 173 =over | |
| 174 | |
| 64 | 175 =item C< CTOR($classDocument,$schema) > |
| 49 | 176 |
| 180 | 177 Создает новый объект, принимает на вход класс документа (или фабрику, например |
| 178 L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа | |
| 179 будет создан объект документа. | |
| 49 | 180 |
| 64 | 181 =item C< NavigateCreate($nodeName,\%props) > |
| 49 | 182 |
| 180 | 183 Создает новый узел с указанным именем и переходит в него. В случае если в схеме |
| 184 подходящий узел не найден, то вызывается исключение. | |
| 49 | 185 |
| 180 | 186 При этом по имени узла ищется его схема, после чего определяется класс для |
| 187 создания экземпляра и созданный узел доавляется в документ. При создании | |
| 188 нового узла используется метод документа C<< IMPL::DOM::Document->Create >> | |
| 49 | 189 |
| 180 | 190 Свойства узла передаются при создании через параметр C<%props>, но имя создаваемого |
| 191 узла НЕ может быть переопределено свойством C<nodeName>, оно будет проигнорировано. | |
| 64 | 192 |
| 193 =item C< Document > | |
| 194 | |
| 180 | 195 Свойство, которое содержит документ по окончании процедуры построения. |
| 49 | 196 |
| 197 =back | |
| 198 | |
| 199 =cut |
