Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Navigator/Builder.pm @ 214:4683002758aa
sync
| author | sergey |
|---|---|
| date | Mon, 06 Aug 2012 17:27:47 +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 |
