407
|
1 package IMPL::DOM::Navigator::Builder;
|
|
2 use strict;
|
|
3 use warnings;
|
|
4
|
|
5 use IMPL::Const qw(:prop);
|
|
6
|
|
7 use parent qw(IMPL::DOM::Navigator);
|
|
8 use IMPL::Class::Property;
|
|
9 require IMPL::DOM::Navigator::SchemaNavigator;
|
|
10 require IMPL::DOM::Schema::ValidationError;
|
|
11 use IMPL::DOM::Document;
|
|
12
|
|
13 BEGIN {
|
|
14 private _direct property _schemaNavi => PROP_RW;
|
|
15 private _direct property _docClass => PROP_RW;
|
|
16 public _direct property Document => PROP_RO;
|
|
17 public _direct property ignoreUndefined => PROP_RO;
|
|
18 }
|
|
19
|
|
20 our %CTOR = (
|
|
21 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document->Empty; }
|
|
22 );
|
|
23
|
|
24 sub CTOR {
|
|
25 my ($this,$docClass,$schema,%opts) = @_;
|
|
26
|
|
27 $this->{$_docClass} = $docClass;
|
|
28 $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef;
|
|
29
|
|
30 $this->{$ignoreUndefined} = $opts{ignoreUndefined} if $opts{ignoreUndefined};
|
|
31 }
|
|
32
|
|
33 sub NavigateCreate {
|
|
34 my ($this,$nodeName,%props) = @_;
|
|
35
|
|
36 if (my $schemaType = $this->{$_schemaNavi}->NavigateName($nodeName)) {
|
|
37 my $class = $schemaType->can('nativeType') ? $schemaType->nativeType || 'IMPL::DOM::Node' : 'IMPL::DOM::Node';
|
|
38
|
|
39 my $schemaNode = $this->{$_schemaNavi}->SourceSchemaNode;
|
|
40
|
|
41 $props{schemaType} = $schemaType;
|
|
42 $props{schemaNode} = $schemaNode;
|
|
43
|
|
44 my $node;
|
|
45 if (! $this->{$Document}) {
|
|
46 # keep reference to the schema document
|
|
47 $props{schemaDocument} = $this->{$_schemaNavi}->schema;
|
|
48 $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props);
|
|
49 $this->_initNavigator($node);
|
|
50 } else {
|
|
51 die new IMPL::InvalidOperationException('Can\'t create a second top level element') unless $this->Current;
|
|
52 $node = $this->{$Document}->Create($nodeName,$class,\%props);
|
|
53 $this->Current->appendChild($node);
|
|
54 $this->internalNavigateNodeSet($node);
|
|
55 }
|
|
56
|
|
57 return $node;
|
|
58 } else {
|
|
59 die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName)
|
|
60 if !$this->ignoreUndefined;
|
|
61 return;
|
|
62 }
|
|
63 }
|
|
64
|
|
65 sub Back {
|
|
66 my ($this) = @_;
|
|
67
|
|
68 $this->{$_schemaNavi}->SchemaBack();
|
|
69 $this->SUPER::Back();
|
|
70 }
|
|
71
|
|
72 sub saveState {
|
|
73 my ($this) = @_;
|
|
74
|
|
75 $this->{$_schemaNavi}->saveState;
|
|
76 $this->SUPER::saveState;
|
|
77 }
|
|
78
|
|
79 sub restoreState {
|
|
80 my ($this) = @_;
|
|
81
|
|
82 $this->{$_schemaNavi}->restoreState;
|
|
83 $this->SUPER::restoreState;
|
|
84 }
|
|
85
|
|
86 sub document {
|
|
87 goto &Document;
|
|
88 }
|
|
89
|
|
90 1;
|
|
91
|
|
92 __END__
|
|
93
|
|
94 =pod
|
|
95
|
|
96 =head1 NAME
|
|
97
|
|
98 C< IMPL::DOM::Navigator::Builder > - Навигатор, строящий документ по указанной схеме.
|
|
99
|
|
100 =head1 SYNOPSIS
|
|
101
|
|
102 =begin code
|
|
103
|
|
104 my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema);
|
|
105 my $reader = new IMPL::DOM::XMLReader(Navigator => $builder);
|
|
106
|
|
107 $reader->ParseFile("document.xml");
|
|
108
|
|
109 my @errors = $schema->Validate($builder->Document);
|
|
110
|
|
111 =end code
|
|
112
|
|
113 =head1 DESCRIPTION
|
|
114
|
|
115 Построитель DOM документов по указанной схеме. Обычно используется в связке
|
|
116 с объектами для чтения такими как C<IMPL::DOM::XMLReader>.
|
|
117
|
|
118 =head1 MEMBERS
|
|
119
|
|
120 =head2 C< CTOR($classDocument,$schema, %opts) >
|
|
121
|
|
122 Создает новый объект, принимает на вход класс документа (или фабрику, например
|
|
123 L<IMPL::Object::Factory>) и схему. В процессе процедуры построения документа
|
|
124 будет создан объект документа.
|
|
125
|
|
126 Необязательные именованные параметры
|
|
127
|
|
128 =over
|
|
129
|
|
130 =item C<ignoreUndefined>
|
|
131
|
|
132 C<NavigateCreate> не будет вызывать исключение, если запрашиваемый узел не
|
|
133 найден в схеме, но будет возвращать C<undef>.
|
|
134
|
|
135 =back
|
|
136
|
|
137 =head2 C< NavigateCreate($nodeName,%props) >
|
|
138
|
|
139 Создает новый узел с указанным именем и переходит в него. В случае если в схеме
|
|
140 подходящий узел не найден, то вызывается исключение или будет возвращено
|
|
141 C<undef> см. C<ignoreUndefined>.
|
|
142
|
|
143 При этом по имени узла ищется его схема, после чего определяется класс для
|
|
144 создания экземпляра узла и созданный узел доавляется в документ. При создании
|
|
145 нового узла используется метод документа C<< IMPL::DOM::Document->Create >>
|
|
146
|
|
147 Свойства узла передаются при создании через параметр C<%props>, но имя
|
|
148 создаваемого узла НЕ может быть переопределено свойством C<nodeName>, оно будет
|
|
149 проигнорировано.
|
|
150
|
|
151 Свойства узла будут преобразованы при помощи заданных в схеме заполнителей
|
|
152 C<inflator>.
|
|
153
|
|
154 =head2 C<[get]document >
|
|
155
|
|
156 Свойство, которое содержит документ по окончании процедуры построения.
|
|
157
|
|
158 =head2 C<[get]buildErrors>
|
|
159
|
|
160 Ошибки, возникшие в процессе построения документа.
|
|
161
|
|
162 =head2 C<[get]ignoreUndefined>
|
|
163
|
|
164 Опция, заданная при создании построителя, отвечающая за обработку узлов
|
|
165 не найденных в схеме.
|
|
166
|
|
167 =cut
|