Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Node.pm @ 250:129e48bb5afb
DOM refactoring
ObjectToDOM methods are virtual
QueryToDOM uses inflators
Fixed transform for the complex values in the ObjectToDOM
QueryToDOM doesn't allow to use complex values (HASHes) as values for nodes (overpost problem)
author | sergey |
---|---|
date | Wed, 07 Nov 2012 04:17:53 +0400 |
parents | a8db61d0ed33 |
children | 6253872024a4 |
rev | line source |
---|---|
49 | 1 package IMPL::DOM::Node; |
2 use strict; | |
3 use warnings; | |
4 | |
165 | 5 use parent qw(IMPL::Object); |
49 | 6 |
7 use IMPL::Object::List; | |
8 use IMPL::Class::Property; | |
9 use IMPL::Class::Property::Direct; | |
10 use Scalar::Util qw(weaken); | |
11 | |
12 use IMPL::Exception; | |
13 | |
14 BEGIN { | |
15 public _direct property nodeName => prop_get; | |
16 public _direct property document => prop_get; | |
17 public _direct property isComplex => { get => \&_getIsComplex } ; | |
18 public _direct property nodeValue => prop_all; | |
102 | 19 public _direct property childNodes => { get => \&_getChildNodes }; # prop_list |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
20 public _direct property parentNode => prop_get | owner_set; |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
21 public _direct property schema => prop_get | owner_set; |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
22 public _direct property schemaSource => prop_get | owner_set; |
49 | 23 private _direct property _propertyMap => prop_all ; |
116 | 24 |
49 | 25 } |
26 | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
27 our %Axes = ( |
194 | 28 parent => \&selectParent, |
29 siblings => \&selectSiblings, | |
30 child => \&childNodes, | |
31 document => \&selectDocument, | |
32 ancestor => \&selectAncestors, | |
33 descendant => \&selectDescendant | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
34 ); |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
35 |
49 | 36 sub CTOR { |
37 my ($this,%args) = @_; | |
38 | |
39 $this->{$nodeName} = delete $args{nodeName} or die new IMPL::InvalidArgumentException("A name is required"); | |
40 $this->{$nodeValue} = delete $args{nodeValue} if exists $args{nodeValue}; | |
41 if ( exists $args{document} ) { | |
42 $this->{$document} = delete $args{document}; | |
43 weaken($this->{$document}); | |
44 } | |
45 | |
124 | 46 while ( my ($key,$value) = each %args ) { |
194 | 47 $this->nodeProperty($key,$value); |
124 | 48 } |
49 | 49 } |
50 | |
51 sub insertNode { | |
52 my ($this,$node,$pos) = @_; | |
53 | |
54 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
55 | |
56 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
57 | |
58 $this->childNodes->InsertAt($pos,$node); | |
59 | |
60 $node->_setParent( $this ); | |
61 | |
62 return $node; | |
63 } | |
64 | |
65 sub appendChild { | |
66 my ($this,$node) = @_; | |
67 | |
68 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
69 | |
70 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
71 | |
72 my $children = $this->childNodes; | |
73 $children->Append($node); | |
74 | |
75 $node->_setParent( $this ); | |
76 | |
77 return $node; | |
78 } | |
79 | |
80 sub appendNode { | |
81 goto &appendChild; | |
82 } | |
83 | |
84 sub appendRange { | |
85 my ($this,@range) = @_; | |
86 | |
87 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if grep $_ == $this, @range; | |
88 | |
89 foreach my $node (@range) { | |
90 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
91 $node->_setParent( $this ); | |
92 } | |
93 | |
94 $this->childNodes->Append(@range); | |
95 | |
96 return $this; | |
97 } | |
98 | |
99 sub _getChildNodes { | |
100 my ($this) = @_; | |
101 | |
102 $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes}; | |
102 | 103 return wantarray ? @{ $this->{$childNodes} } : $this->{$childNodes}; |
49 | 104 } |
105 | |
109
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
106 sub childNodesRef { |
194 | 107 my ($this) = @_; |
108 return scalar $this->_getChildNodes; | |
109
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
109 } |
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
110 |
49 | 111 sub removeNode { |
112 my ($this,$node) = @_; | |
113 | |
114 if ($this == $node->{$parentNode}) { | |
115 $this->childNodes->RemoveItem($node); | |
116 $node->_setParent(undef); | |
117 return $node; | |
118 } else { | |
119 die new IMPL::InvalidOperationException("The specified node isn't belong to this node"); | |
120 } | |
121 } | |
122 | |
123 sub replaceNodeAt { | |
124 my ($this,$index,$node) = @_; | |
125 | |
126 my $nodeOld = $this->childNodes->[$index]; | |
127 | |
128 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
129 | |
130 # unlink node from previous parent | |
131 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
132 | |
133 # replace (or set) old node | |
134 $this->childNodes->[$index] = $node; | |
135 | |
136 # set new parent | |
137 $node->_setParent( $this ); | |
138 | |
139 # unlink old node if we have one | |
140 $nodeOld->_setParent(undef) if $nodeOld; | |
141 | |
142 # return old node | |
143 return $nodeOld; | |
144 } | |
145 | |
146 sub removeAt { | |
147 my ($this,$pos) = @_; | |
148 | |
149 if ( my $node = $this->childNodes->RemoveAt($pos) ) { | |
150 $node->_setParent(undef); | |
151 return $node; | |
152 } else { | |
153 return undef; | |
154 } | |
155 } | |
156 | |
157 sub removeLast { | |
158 my ($this) = @_; | |
159 | |
160 if ( my $node = $this->{$childNodes} ? $this->{$childNodes}->RemoveLast() : undef) { | |
161 $node->_setParent(undef); | |
162 return $node; | |
163 } else { | |
164 return undef; | |
165 } | |
166 } | |
167 | |
168 sub removeSelected { | |
169 my ($this,$query) = @_; | |
170 | |
171 my @newSet; | |
172 my @result; | |
173 | |
174 if (ref $query eq 'CODE') { | |
175 &$query($_) ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes}; | |
176 } elsif (defined $query) { | |
177 $_->nodeName eq $query ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes}; | |
178 } else { | |
179 my $children = $this->childNodes; | |
180 $_->_setParent(undef) foreach @$children; | |
181 delete $this->{$childNodes}; | |
182 return wantarray ? @$children : $children; | |
183 } | |
184 | |
185 $_->_setParent(undef) foreach @result; | |
186 | |
187 $this->{$childNodes} = @newSet ? bless \@newSet ,'IMPL::Object::List' : undef; | |
188 | |
189 return wantarray ? @result : \@result; | |
190 } | |
191 | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
192 sub resolveAxis { |
194 | 193 my ($this,$axis) = @_; |
194 return $Axes{$axis}->($this) | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
195 } |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
196 |
49 | 197 sub selectNodes { |
194 | 198 my $this = shift; |
199 my $path; | |
200 | |
201 if (@_ == 1) { | |
202 $path = $this->translatePath($_[0]); | |
203 } else { | |
204 $path = [@_]; | |
205 } | |
206 | |
207 my @set = ($this); | |
208 | |
209 while (@$path) { | |
210 my $query = shift @$path; | |
211 @set = map $_->selectNodesAxis($query), @set; | |
212 } | |
213 | |
214 return wantarray ? @set : \@set; | |
108 | 215 } |
216 | |
113 | 217 sub selectSingleNode { |
194 | 218 my $this = shift; |
219 my @result = $this->selectNodes(@_); | |
220 return $result[0]; | |
113 | 221 } |
222 | |
109
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
223 sub selectNodesRef { |
194 | 224 my $this = shift; |
225 | |
226 my @result = $this->selectNodes(@_); | |
227 return \@result; | |
109
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
228 } |
ddf0f037d460
IMPL::DOM::Node updated to support TT, (added childNodesRef and selectNodesRef for using from TT)
wizard
parents:
108
diff
changeset
|
229 |
108 | 230 sub translatePath { |
194 | 231 my ($this,$path) = @_; |
232 | |
233 # TODO: Move path compilation here from IMPL::DOM::Schema::Validator::Compare | |
234 return [$path]; | |
108 | 235 } |
236 | |
237 sub selectNodesAxis { | |
194 | 238 my ($this,$query,$axis) = @_; |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
239 |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
240 $axis ||= 'child'; |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
241 |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
242 die new IMPL::InvalidOperationException('Unknown axis',$axis) unless exists $Axes{$axis}; |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
243 |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
244 my $nodes = $this->resolveAxis($axis); |
49 | 245 |
246 my @result; | |
247 | |
248 if (ref $query eq 'CODE') { | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
249 @result = grep &$query($_), @{$nodes}; |
49 | 250 } elsif (ref $query eq 'ARRAY' ) { |
251 my %keys = map (($_,1),@$query); | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
252 @result = grep $keys{$_->nodeName}, @{$nodes}; |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
253 } elsif (ref $query eq 'HASH') { |
194 | 254 while( my ($axis,$filter) = each %$query ) { |
255 push @result, $this->selectNodesAxis($filter,$axis); | |
256 } | |
49 | 257 } elsif (defined $query) { |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
258 @result = grep $_->nodeName eq $query, @{$nodes}; |
49 | 259 } else { |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
260 return wantarray ? @{$nodes} : $nodes; |
49 | 261 } |
262 | |
263 return wantarray ? @result : \@result; | |
264 } | |
265 | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
266 sub selectParent { |
194 | 267 my ($this) = @_; |
268 | |
269 if ($this->parentNode) { | |
270 return wantarray ? $this->parentNode : [$this->parentNode]; | |
271 } else { | |
272 return wantarray ? () : []; | |
273 } | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
274 } |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
275 |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
276 sub selectSiblings { |
194 | 277 my ($this) = @_; |
278 | |
279 if ($this->parentNode) { | |
280 return $this->parentNode->selectNodes( sub { $_ != $this } ); | |
281 } else { | |
282 return wantarray ? () : []; | |
283 } | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
284 } |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
285 |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
286 sub selectDocument { |
194 | 287 my ($this) = @_; |
288 | |
289 if ($this->document) { | |
290 return wantarray ? $this->document : [$this->document]; | |
291 } else { | |
292 return wantarray ? () : []; | |
293 } | |
104
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
294 } |
196bf443b5e1
DOM::Schema RC0 inflators support, validation and some other things,
wizard
parents:
102
diff
changeset
|
295 |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
296 sub selectDescendant { |
194 | 297 wantarray ? |
298 map $_->selectAll(), $_[0]->childNodes : | |
299 [map $_->selectAll(), $_[0]->childNodes] | |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
300 } |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
301 |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
302 sub selectAll { |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
303 map(selectAll($_),@{$_[0]->childNodes}) , $_[0] |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
304 } |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
305 |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
306 sub selectAncestors { |
194 | 307 my $parent = $_[0]->parentNode; |
308 | |
309 wantarray ? | |
310 ($parent ? ($parent->selectAncestors,$parent) : ()) : | |
311 [$parent ? ($parent->selectAncestors,$parent) : ()] | |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
312 } |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
313 |
49 | 314 sub firstChild { |
315 @_ >=2 ? $_[0]->replaceNodeAt(0,$_[1]) : $_[0]->childNodes->[0]; | |
316 } | |
317 | |
318 sub _getIsComplex { | |
152 | 319 ($_[0]->{$childNodes} and $_[0]->{$childNodes}->Count) ? 1 : 0; |
49 | 320 } |
321 | |
322 sub _updateDocRefs { | |
323 my ($this) = @_; | |
324 | |
325 # this method is called by the parent node on his children, so we need no to check parent | |
326 $this->{$document} = $this->{$parentNode}->document; | |
327 | |
328 # prevent cyclic | |
329 weaken($this->{$document}) if $this->{$document}; | |
330 | |
173 | 331 map $_->_updateDocRefs, @{$this->{$childNodes}} if $this->{$childNodes}; |
49 | 332 } |
333 | |
334 sub _setParent { | |
335 my ($this,$node) = @_; | |
336 | |
337 | |
338 if (($node || 0) != ($this->{$parentNode} || 0)) { | |
339 my $newOwner; | |
340 if ($node) { | |
341 $this->{$parentNode} = $node; | |
342 $newOwner = $node->document || 0; | |
343 | |
344 # prevent from creating cyclicreferences | |
345 weaken($this->{$parentNode}); | |
346 | |
347 } else { | |
348 delete $this->{$parentNode}; | |
75 | 349 |
350 #keep document | |
351 $newOwner = $this->{$document}; | |
49 | 352 } |
353 | |
354 if (($this->{$document}||0) != $newOwner) { | |
355 $this->{$document} = $newOwner; | |
356 weaken($this->{$document}) if $newOwner; | |
357 $_->_updateDocRefs foreach @{$this->childNodes}; | |
358 } | |
359 } | |
360 } | |
361 | |
362 sub text { | |
363 my ($this) = @_; | |
364 | |
365 join ('', $this->nodeValue || '', map ($_->text || '', @{$this->childNodes})); | |
366 } | |
367 | |
368 sub nodeProperty { | |
369 my $this = shift; | |
370 my $name = shift; | |
371 | |
188 | 372 return unless defined $name; |
373 | |
122 | 374 if (my $method = $this->can($name)) { |
194 | 375 unshift @_,$this; |
376 # use goto to preserve calling context | |
377 goto &$method; | |
122 | 378 } |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
379 # dynamic property |
49 | 380 if (@_) { |
194 | 381 # set |
382 return $this->{$_propertyMap}{$name} = shift; | |
383 } else { | |
384 return $this->{$_propertyMap}{$name}; | |
49 | 385 } |
386 } | |
387 | |
122 | 388 sub listProperties { |
194 | 389 my ($this) = @_; |
390 | |
391 my %props = map {$_->Name, 1} $this->get_meta(typeof IMPL::Class::PropertyInfo, sub { $_->Attributes->{domProperty}},1); | |
392 | |
393 return (keys %props,keys %{$this->{$_propertyMap}}); | |
122 | 394 } |
395 | |
152 | 396 sub save { |
194 | 397 my ($this,$writer) = @_; |
398 | |
399 if ( not ( $this->isComplex or defined $this->{$nodeValue} ) ) { | |
400 $writer->emptyTag( | |
401 $this->{$nodeName}, | |
402 map { | |
403 $_, | |
404 $this->nodeProperty($_) | |
405 } grep defined $this->nodeProperty($_), $this->listProperties | |
406 ); | |
407 } else { | |
408 $writer->startTag( | |
409 $this->{$nodeName}, | |
410 map { | |
411 $_, | |
412 $this->nodeProperty($_) | |
413 } grep defined $this->nodeProperty($_), $this->listProperties | |
414 ); | |
415 $writer->characters($this->{$nodeValue}) if $this->{$nodeValue}; | |
416 | |
417 $_->save($writer) foreach $this->childNodes; | |
418 | |
419 $writer->endTag($this->{$nodeName}); | |
420 } | |
152 | 421 } |
422 | |
49 | 423 sub qname { |
424 $_[0]->{$nodeName}; | |
425 } | |
426 | |
427 sub path { | |
428 my ($this) = @_; | |
429 | |
430 if ($this->parentNode) { | |
431 return $this->parentNode->path.'.'.$this->qname; | |
432 } else { | |
433 return $this->qname; | |
434 } | |
435 } | |
436 | |
437 1; | |
75 | 438 |
439 __END__ | |
440 | |
441 =pod | |
442 | |
443 =head1 NAME | |
444 | |
180 | 445 C<IMPL::DOM::Node> Элемент DOM модели |
75 | 446 |
447 =head1 DESCRIPTION | |
448 | |
180 | 449 Базовый узел DOM модели. От него можно наследовать другие элементы DOM модели. |
75 | 450 |
451 =head1 MEMBERS | |
452 | |
453 =head2 PROPERTIES | |
454 | |
455 =over | |
456 | |
457 =item C<[get] nodeName> | |
458 | |
180 | 459 Имя узла. Задается при создании. |
75 | 460 |
461 =item C<[get] document> | |
462 | |
180 | 463 Документ к которому принадлежит узел. Задается при поздании узла. |
75 | 464 |
465 =item C<[get] isComplex> | |
466 | |
180 | 467 Определяет является ли узел сложным (тоесть есть ли дети). |
75 | 468 |
180 | 469 C<true> - есть, C<false> - нет. |
75 | 470 |
471 =item C<[get,set] nodeValue> | |
472 | |
180 | 473 Значение узла, обычно простой скаляр, но ничто не мешает туда |
474 устанавливать любое значение. | |
75 | 475 |
476 =item C<[get,list] childNodes> | |
477 | |
180 | 478 Список детей, является списокм C<IMPL::Object::List>. |
75 | 479 |
480 =item C<[get] parentNode> | |
481 | |
180 | 482 Ссылка на родительский элемент, если таковой имеется. |
75 | 483 |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
484 =item C<[get] schema> |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
485 |
180 | 486 Ссылка на узел из C<IMPL::DOM::Schema>, представляющий схему данных текущего узла. Может быть C<undef>. |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
487 |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
488 =item C<[get] schema> |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
489 |
180 | 490 Ссылка на узел из C<IMPL::DOM::Schema>, представляющий элемент схемы, объявляющий данный узел. Может быть C<undef>. |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
491 |
180 | 492 Отличается от свойства C<schema> тем, что узел в случае ссылки на тип узла, данной свойство будет содержать |
493 описание ссылки C<IMPL::DOM::Schema::Node>, а свойство C<schema> например будет ссылаться на | |
148
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
494 C<IMPL::DOM::Schema::ComplexType>. |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
495 |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
496 =back |
e6447ad85cb4
DOM objects now have a schema and schemaSource properties
wizard
parents:
124
diff
changeset
|
497 |
75 | 498 =head2 METHODS |
499 | |
180 | 500 =cut |