/[suikacvs]/messaging/manakai/lib/Message/DOM/Element.pm
Suika

Contents of /messaging/manakai/lib/Message/DOM/Element.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (show annotations) (download)
Sat Apr 12 15:58:41 2008 UTC (16 years, 7 months ago) by wakaba
Branch: MAIN
Changes since 1.29: +10 -8 lines
++ manakai/lib/Message/DOM/ChangeLog	12 Apr 2008 14:24:10 -0000
2008-04-12  Wakaba  <wakaba@suika.fam.cx>

	* Element.pm (create_element, create_element_ns): Inputs
	were not normalized into a string.

1 ## NOTE: This module will be renamed as Element.pm.
2
3 package Message::DOM::Element;
4 use strict;
5 our $VERSION=do{my @r=(q$Revision: 1.29 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
6 push our @ISA, 'Message::DOM::Node', 'Message::IF::Element',
7 'Message::IF::ElementSelector', # MUST in Selectors API spec.
8 'Message::IF::ElementCSSInlineStyle';
9 require Message::DOM::Document;
10
11 sub ____new ($$$$$) {
12 my $self = shift->SUPER::____new (shift);
13 ($$self->{namespace_uri},
14 $$self->{prefix},
15 $$self->{local_name}) = @_;
16 $$self->{attributes} = {};
17 $$self->{child_nodes} = [];
18 return $self;
19 } # ____new
20
21 sub AUTOLOAD {
22 my $method_name = our $AUTOLOAD;
23 $method_name =~ s/.*:://;
24 return if $method_name eq 'DESTROY';
25
26 if ({
27 ## Read-only attributes (trivial accessors)
28 namespace_uri => 1,
29 }->{$method_name}) {
30 no strict 'refs';
31 eval qq{
32 sub $method_name (\$) {
33 return \${\$_[0]}->{$method_name};
34 }
35 };
36 goto &{ $AUTOLOAD };
37 } elsif ({
38 ## Read-write attributes (DOMString, trivial accessors)
39 manakai_base_uri => 1,
40 }->{$method_name}) {
41 no strict 'refs';
42 eval qq{
43 sub $method_name (\$;\$) {
44 if (\@_ > 1) {
45 if (\${\${\$_[0]}->{owner_document}}->{strict_error_checking} and
46 \${\$_[0]}->{manakai_read_only}) {
47 report Message::DOM::DOMException
48 -object => \$_[0],
49 -type => 'NO_MODIFICATION_ALLOWED_ERR',
50 -subtype => 'READ_ONLY_NODE_ERR';
51 }
52 if (defined \$_[1]) {
53 \${\$_[0]}->{$method_name} = ''.\$_[1];
54 } else {
55 delete \${\$_[0]}->{$method_name};
56 }
57 }
58 return \${\$_[0]}->{$method_name};
59 }
60 };
61 goto &{ $AUTOLOAD };
62 } elsif (my $module_name = {
63 query_selector => 'Message::DOM::SelectorsAPI',
64 query_selector_all => 'Message::DOM::SelectorsAPI',
65 }->{$method_name}) {
66 eval qq{ require $module_name } or die $@;
67 goto &{ $AUTOLOAD };
68 } else {
69 require Carp;
70 Carp::croak (qq<Can't locate method "$AUTOLOAD">);
71 }
72 } # AUTOLOAD
73
74 ## TODO: Test for create_element_ns ('', ...)
75
76 ## |Node| attributes
77
78 sub attributes ($) {
79 require Message::DOM::NamedNodeMap;
80 return bless \\($_[0]), 'Message::DOM::NamedNodeMap::AttrMap';
81 } # attributes
82
83 sub base_uri ($) {
84 my $self = $_[0];
85 return $$self->{manakai_base_uri} if defined $$self->{manakai_base_uri};
86
87 local $Error::Depth = $Error::Depth + 1;
88 my $xb = $self->get_attribute_node_ns
89 ('http://www.w3.org/XML/1998/namespace', 'base');
90 unless (defined $xb) {
91 $xb = $self->get_attribute_node_ns (undef, 'xml:base');
92 }
93
94 if ($xb) {
95 my $v = $self->owner_document->implementation->create_uri_reference
96 ($xb->value);
97 if (not defined $v->uri_scheme) { # Relative reference
98 my $xbbase = $xb->base_uri;
99 if (defined $xbbase) {
100 return $v->get_absolute_reference ($xbbase)->uri_reference;
101 }
102 }
103 return $v->uri_reference;
104 }
105
106 my $pe = $$self->{parent_node};
107 while (defined $pe) {
108 my $nt = $pe->node_type;
109 if ($nt == 1 or $nt == 6 or $nt == 9 or $nt == 11) {
110 ## Element, Entity, Document, or DocumentFragment
111 return $pe->base_uri;
112 } elsif ($nt == 5) {
113 ## EntityReference
114 if ($pe->manakai_external) {
115 return $pe->manakai_entity_base_uri;
116 }
117 }
118 $pe = $$pe->{parent_node};
119 }
120 return $pe->base_uri if $pe;
121 return $$self->{owner_document}->base_uri;
122 } # base_uri
123
124 sub local_name ($) { # TODO: HTML5 case
125 return ${$_[0]}->{local_name};
126 } # local_name
127
128 sub manakai_local_name ($) {
129 return ${$_[0]}->{local_name};
130 } # manakai_local_name
131
132 sub namespace_uri ($);
133
134 ## The tag name of the element [DOM1, DOM2].
135 ## Same as |Element.tagName| [DOM3].
136
137 *node_name = \&tag_name;
138
139 sub node_type () { 1 } # ELEMENT_NODE
140
141 sub prefix ($;$) {
142 ## NOTE: No check for new value as Firefox doesn't do.
143 ## See <http://suika.fam.cx/gate/2005/sw/prefix>.
144
145 ## NOTE: Same as trivial setter except "" -> undef
146
147 ## NOTE: Same as |Attr|'s |prefix|.
148
149 if (@_ > 1) {
150 if (${$_[0]}->{manakai_read_only}) {
151 report Message::DOM::DOMException
152 -object => $_[0],
153 -type => 'NO_MODIFICATION_ALLOWED_ERR',
154 -subtype => 'READ_ONLY_NODE_ERR';
155 }
156 if (defined $_[1] and $_[1] ne '') {
157 ${$_[0]}->{prefix} = ''.$_[1];
158 } else {
159 delete ${$_[0]}->{prefix};
160 }
161 }
162 return ${$_[0]}->{prefix};
163 } # prefix
164
165 ## |Element| attributes
166
167 sub manakai_base_uri ($;$);
168
169 ## Defined in |HTMLElement| interface of HTML5
170 sub inner_html ($;$) {
171 my $self = $_[0];
172
173 ## TODO: Setter
174
175 if (${$$self->{owner_document}}->{manakai_is_html}) {
176 require Whatpm::HTML::Serializer;
177 return ${ Whatpm::HTML::Serializer->get_inner_html ($self) };
178 } else {
179 ## TODO: This serializer is not currenly conformant to HTML5.
180 require Whatpm::XMLSerializer;
181 my $r = '';
182 for (@{$self->child_nodes}) {
183 $r .= ${ Whatpm::XMLSerializer->get_outer_xml ($_) };
184 }
185 return $r;
186 }
187 } # inner_html
188
189 sub schema_type_info ($) {
190 require Message::DOM::TypeInfo;
191 my $v = 0;
192 return bless \$v, 'Message::DOM::TypeInfo';
193 ## NOTE: Currently manakai does not support XML Schema, so it is
194 ## always a no-type |TypeInfo|. It is expected that
195 ## a future version of the implementation will return an
196 ## element type definition node that also implement the
197 ## |TypeInfo| interface when the schema language is XML DTD.
198 } # schema_type_info
199
200 ## TODO: HTML5 capitalization
201 sub tag_name ($) {
202 my $self = shift;
203 if (defined $$self->{prefix}) {
204 return $$self->{prefix} . ':' . $$self->{local_name};
205 } else {
206 return $$self->{local_name};
207 }
208 } # tag_name
209
210 ## TODO: Documentation
211 sub manakai_tag_name ($) {
212 my $self = shift;
213 if (defined $$self->{prefix}) {
214 return $$self->{prefix} . ':' . $$self->{local_name};
215 } else {
216 return $$self->{local_name};
217 }
218 } # manakai_tag_name
219
220 ## The |Element| interface - methods
221
222 sub manakai_element_type_match ($$$) {
223 my ($self, $nsuri, $ln) = @_;
224 if (defined $nsuri) {
225 if (defined $$self->{namespace_uri} and $nsuri eq $$self->{namespace_uri}) {
226 return ($ln eq $$self->{local_name});
227 } else {
228 return 0;
229 }
230 } else {
231 if (not defined $$self->{namespace_uri}) {
232 return ($ln eq $$self->{local_name});
233 } else {
234 return 0;
235 }
236 }
237 } # manakai_element_type_match
238
239 sub get_attribute ($$) {
240 my $attr = ${$_[0]}->{attributes};
241 my $name = ''.$_[1];
242
243 ## NOTE: |sort|ing is required so that every |getAttribute|, |setAttribute|,
244 ## |hasAttribute|, |removeAttribute|, or any other namespace unaware
245 ## methods operates on the same node even if there is
246 ## multiple nodes with the same qualified name.
247
248 ## NOTE: Same as |get_attribute_node|, except what is returned.
249
250 for my $ns (sort {$a cmp $b} keys %$attr) {
251 for my $ln (sort {$a cmp $b} keys %{$attr->{$ns}}) {
252 my $node = $attr->{$ns}->{$ln};
253 if ($node->manakai_name eq $name) {
254 return $node->value;
255 }
256 }
257 }
258
259 return undef;
260 } # get_attribute
261
262 sub get_attribute_node ($$) {
263 my $attr = ${$_[0]}->{attributes};
264 my $name = ''.$_[1];
265
266 ## NOTE: Same as |get_attribute|, except what is returned.
267
268 for my $ns (sort {$a cmp $b} keys %$attr) {
269 for my $ln (sort {$a cmp $b} keys %{$attr->{$ns}}) {
270 my $node = $attr->{$ns}->{$ln};
271 if ($node->manakai_name eq $name) {
272 return $node;
273 }
274 }
275 }
276
277 return undef;
278 } # get_attribute_node
279
280 sub get_attribute_ns ($$$) {
281 my $nsuri = defined $_[1] ? ''.$_[1] : '';
282 my $ln = ''.$_[2];
283 if (my $attr = ${$_[0]}->{attributes}->{$nsuri}->{$ln}) {
284 return $attr->value;
285 } else {
286 return undef;
287 }
288 } # get_attribute_ns
289
290 sub get_attribute_node_ns ($$$) {
291 return ${$_[0]}->{attributes}->{defined $_[1] ? ''.$_[1] : ''}->{''.$_[2]};
292 } # get_attribute_node_ns
293
294 *get_elements_by_tag_name = \&Message::DOM::Document::get_elements_by_tag_name;
295
296 *get_elements_by_tag_name_ns
297 = \&Message::DOM::Document::get_elements_by_tag_name_ns;
298
299 sub has_attribute ($$) {
300 my $attr = ${$_[0]}->{attributes};
301 my $name = ''.$_[1];
302
303 for my $ns (keys %$attr) {
304 for my $ln (keys %{$attr->{$ns}}) {
305 my $node = $attr->{$ns}->{$ln};
306 if ($node->manakai_name eq $name) {
307 return 1;
308 }
309 }
310 }
311
312 return 0;
313 } # has_attribute
314
315 sub has_attribute_ns ($$$) {
316 return ${$_[0]}->{attributes}->{defined $_[1] ? ''.$_[1] : ''}->{''.$_[2]}?1:0;
317 } # has_attribute_ns
318
319 sub remove_attribute ($$) {
320 my $attr = ${$_[0]}->{attributes};
321 my $name = ''.$_[1];
322
323 my $list;
324 my $key;
325 my $attr_node;
326 ATTR: {
327 for my $ns (keys %$attr) {
328 $list = $attr->{$ns};
329 for my $ln (keys %$list) {
330 $attr_node = $list->{$ln};
331 if ($attr_node->manakai_name eq $name) {
332 $key = $ln;
333 last ATTR;
334 }
335 }
336 }
337
338 return undef; # not found
339 } # ATTR
340
341 my $od = ${$_[0]}->{owner_document};
342 if ($$od->{strict_error_checking} and ${$_[0]}->{manakai_read_only}) {
343 report Message::DOM::DOMException
344 -object => $_[0],
345 -type => 'NO_MODIFICATION_ALLOWED_ERR',
346 -subtype => 'READ_ONLY_NODE_ERR';
347 }
348
349 delete $list->{$key};
350 delete $$attr_node->{owner_element};
351 $$attr_node->{specified} = 1;
352 delete ${$_[0]}->{manakai_content_attribute_list};
353
354 ## Default attribute
355 local $Error::Depth = $Error::Depth + 1;
356 my $cfg = $od->dom_config;
357 if ($cfg->get_parameter
358 (q<http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute>)) {
359 my $doctype = $od->doctype;
360 if ($doctype) {
361 my $et = $doctype->get_element_type_definition_node
362 ($_[0]->manakai_tag_name);
363 if ($et) {
364 my $at = $et->get_attribute_definition_node ($name);
365 if ($at) {
366 local $$od->{strict_error_checking} = 0;
367 my $copy_asis = $cfg->get_parameter
368 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree>);
369 $cfg->set_parameter
370 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => 1);
371 ADD: {
372 my $def_attr_node;
373 my $def_prefix = $attr_node->prefix;
374 my $def_nsuri = '';
375 my $def_ln;
376 if (defined $def_prefix) {
377 $def_nsuri =
378 $def_prefix eq 'xml' ? q<http://www.w3.org/XML/1998/namespace>:
379 $def_prefix eq 'xmlns' ? q<http://www.w3.org/2000/xmlns/>:
380 $_[0]->lookup_namespace_uri ($def_prefix);
381 unless (defined $def_nsuri) {
382 ## TODO: Namespace well-formedness error...
383 }
384 $def_ln = $attr_node->manakai_local_name;
385 } else {
386 $def_nsuri = $name eq 'xmlns'
387 ? q<http://www.w3.org/2000/xmlns/> : undef;
388 $def_ln = $name;
389 }
390 if ($attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}) {
391 ## TODO: Namespace well-formedness warning?
392 last ADD;
393 }
394 $def_attr_node = $od->create_attribute_ns
395 ($def_nsuri, [$def_prefix, $def_ln]);
396
397 for my $child (@{$at->child_nodes}) {
398 $def_attr_node->append_child ($child->clone_node (1));
399 }
400 $def_attr_node->manakai_attribute_type ($at->declared_type);
401 $attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}
402 = $def_attr_node;
403 $$def_attr_node->{owner_element} = $_[0];
404 Scalar::Util::weaken ($$def_attr_node->{owner_element});
405 delete $$def_attr_node->{specified};
406 } # ADD
407 $cfg->set_parameter
408 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => $copy_asis);
409 }
410 }
411 }
412 }
413
414 return undef;
415 } # remove_attribute
416
417 sub remove_attribute_node ($$) {
418 my $od = ${$_[0]}->{owner_document};
419 if ($$od->{strict_error_checking} and ${$_[0]}->{manakai_read_only}) {
420 report Message::DOM::DOMException
421 -object => $_[0],
422 -type => 'NO_MODIFICATION_ALLOWED_ERR',
423 -subtype => 'READ_ONLY_NODE_ERR';
424 }
425
426 my $attr_node = $_[1];
427 my $ln = $attr_node->manakai_local_name;
428 my $attr = ${$_[0]}->{attributes};
429 FIND: {
430 my $nsuri = $attr_node->namespace_uri;
431 my $list = $attr->{defined $nsuri ? $nsuri : ''};
432 my $list_node = $list->{$ln};
433 if (defined $list_node and $list_node eq $attr_node) {
434 delete $list->{$ln};
435 last FIND;
436 }
437
438 report Message::DOM::DOMException
439 -object => $_[0],
440 -type => 'NOT_FOUND_ERR',
441 -subtype => 'NOT_CHILD_ERR';
442 } # FIND
443
444 delete ${$_[0]}->{manakai_content_attribute_list};
445 delete $$attr_node->{owner_element};
446 $$attr_node->{specified} = 1;
447
448 ## Default attribute
449 ## Same as |remove_attribute|'s, except where marked as "***".
450 local $Error::Depth = $Error::Depth + 1;
451 my $cfg = $od->dom_config;
452 if ($cfg->get_parameter
453 (q<http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute>)) {
454 my $doctype = $od->doctype;
455 if ($doctype) {
456 my $et = $doctype->get_element_type_definition_node
457 ($_[0]->manakai_tag_name);
458 if ($et) {
459 my $at = $et->get_attribute_definition_node ($_[1]->manakai_name); # ***
460 if ($at) {
461 local $$od->{strict_error_checking} = 0;
462 my $copy_asis = $cfg->get_parameter
463 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree>);
464 $cfg->set_parameter
465 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => 1);
466 ADD: {
467 my $def_attr_node;
468 my $def_prefix = $attr_node->prefix;
469 my $def_nsuri = '';
470 my $def_ln;
471 if (defined $def_prefix) {
472 $def_nsuri =
473 $def_prefix eq 'xml' ? q<http://www.w3.org/XML/1998/namespace>:
474 $def_prefix eq 'xmlns' ? q<http://www.w3.org/2000/xmlns/>:
475 $_[0]->lookup_namespace_uri ($def_prefix);
476 unless (defined $def_nsuri) {
477 ## TODO: Namespace well-formedness error...
478 }
479 $def_ln = $attr_node->manakai_local_name;
480 } else {
481 $def_nsuri = $attr_node->manakai_name eq 'xmlns'
482 ? q<http://www.w3.org/2000/xmlns/> : undef;
483 $def_ln = $attr_node->manakai_local_name; ## ***
484 }
485 if ($attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}) {
486 ## TODO: Namespace well-formedness warning?
487 last ADD;
488 }
489 $def_attr_node = $od->create_attribute_ns
490 ($def_nsuri, [$def_prefix, $def_ln]);
491
492 for my $child (@{$at->child_nodes}) {
493 $def_attr_node->append_child ($child->clone_node (1));
494 }
495 $def_attr_node->manakai_attribute_type ($at->declared_type);
496 $attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}
497 = $def_attr_node;
498 $$def_attr_node->{owner_element} = $_[0];
499 Scalar::Util::weaken ($$def_attr_node->{owner_element});
500 delete $$def_attr_node->{specified};
501 } # ADD
502 $cfg->set_parameter
503 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => $copy_asis);
504 }
505 }
506 }
507 }
508
509 return $_[1];
510 } # remove_attribute_node
511
512 sub remove_attribute_ns ($$$) {
513 my $attr = ${$_[0]}->{attributes};
514
515 my $list = $attr->{defined $_[1] ? $_[1] : ''};
516 my $key = ''.$_[2];
517 my $attr_node = $list->{$key};
518 return undef unless defined $attr_node;
519
520 ## NOTE: Anything below is same as |remove_attribute|'s except "***"
521
522 my $od = ${$_[0]}->{owner_document};
523 if ($$od->{strict_error_checking} and ${$_[0]}->{manakai_read_only}) {
524 report Message::DOM::DOMException
525 -object => $_[0],
526 -type => 'NO_MODIFICATION_ALLOWED_ERR',
527 -subtype => 'READ_ONLY_NODE_ERR';
528 }
529
530 delete $list->{$key};
531 delete $$attr_node->{owner_element};
532 $$attr_node->{specified} = 1;
533 delete ${$_[0]}->{manakai_content_attribute_list};
534
535 ## Default attribute
536 local $Error::Depth = $Error::Depth + 1;
537 my $cfg = $od->dom_config;
538 if ($cfg->get_parameter
539 (q<http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute>)) {
540 my $doctype = $od->doctype;
541 if ($doctype) {
542 my $et = $doctype->get_element_type_definition_node
543 ($_[0]->manakai_tag_name);
544 if ($et) {
545 my $at = $et->get_attribute_definition_node
546 ($attr_node->manakai_name); # ***
547 if ($at) {
548 local $$od->{strict_error_checking} = 0;
549 my $copy_asis = $cfg->get_parameter
550 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree>);
551 $cfg->set_parameter
552 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => 1);
553 ADD: {
554 my $def_attr_node;
555 my $def_prefix = $attr_node->prefix;
556 my $def_nsuri = '';
557 my $def_ln;
558 if (defined $def_prefix) {
559 $def_nsuri =
560 $def_prefix eq 'xml' ? q<http://www.w3.org/XML/1998/namespace>:
561 $def_prefix eq 'xmlns' ? q<http://www.w3.org/2000/xmlns/>:
562 $_[0]->lookup_namespace_uri ($def_prefix);
563 unless (defined $def_nsuri) {
564 ## TODO: Namespace well-formedness error...
565 }
566 } else {
567 $def_nsuri = $attr_node->manakai_name eq 'xmlns'
568 ? q<http://www.w3.org/2000/xmlns/> : undef;
569 }
570 $def_ln = $attr_node->manakai_local_name; # ***
571 if ($attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}) {
572 ## TODO: Namespace well-formedness warning?
573 last ADD;
574 }
575 $def_attr_node = $od->create_attribute_ns
576 ($def_nsuri, [$def_prefix, $def_ln]);
577
578 for my $child (@{$at->child_nodes}) {
579 $def_attr_node->append_child ($child->clone_node (1));
580 }
581 $def_attr_node->manakai_attribute_type ($at->declared_type);
582 $attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}
583 = $def_attr_node;
584 $$def_attr_node->{owner_element} = $_[0];
585 Scalar::Util::weaken ($$def_attr_node->{owner_element});
586 delete $$def_attr_node->{specified};
587 } # ADD
588 $cfg->set_parameter
589 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => $copy_asis);
590 }
591 }
592 }
593 }
594
595 return undef;
596 } # remove_attribute_ns
597
598 sub set_attribute ($$$) {
599 my $od = ${$_[0]}->{owner_document};
600 if ($$od->{strict_error_checking}) {
601 if (${$_[0]}->{manakai_read_only}) {
602 report Message::DOM::DOMException
603 -object => $_[0],
604 -type => 'NO_MODIFICATION_ALLOWED_ERR',
605 -subtype => 'READ_ONLY_NODE_ERR';
606 }
607 }
608
609 my $name = ''.$_[1];
610 my $attr = ${$_[0]}->{attributes};
611 my $attr_node;
612 NS: for my $ns (keys %$attr) {
613 for my $ln (keys %{$attr->{$ns}}) {
614 my $node = $attr->{$ns}->{$ln};
615 if ($node->manakai_name eq $name) {
616 $attr_node = $node;
617 last NS;
618 }
619 }
620 }
621
622 local $Error::Depth = $Error::Depth + 1;
623 if (defined $attr_node) {
624 if ($$od->{strict_error_checking}) {
625 $od->create_attribute ($name); # or exception
626 }
627 } else {
628 $attr_node = $od->create_attribute ($name); # return or exception
629 delete ${$_[0]}->{manakai_content_attribute_list};
630 $attr->{''}->{$name} = $attr_node;
631 $$attr_node->{owner_element} = $_[0];
632 Scalar::Util::weaken ($$attr_node->{owner_element});
633
634 if ($od->dom_config->get_parameter
635 (q<http://suika.fam.cx/www/2006/dom-config/dtd-attribute-type>)) {
636 my $doctype = $od->doctype;
637 if (defined $doctype) {
638 my $et = $doctype->get_element_type_definition_node
639 ($_[0]->manakai_tag_name);
640 if (defined $et) {
641 my $at = $et->get_attribute_definition_node ($attr_node->manakai_name);
642 if (defined $at) {
643 $attr_node->manakai_attribute_type ($at->declared_type);
644 }
645 }
646 }
647 }
648 }
649
650 $attr_node->value ($_[2]); # set or exception
651 $attr_node->specified (1);
652 return undef;
653 } # set_attribute
654
655 sub set_attribute_node ($$) {
656 my ($self, $new_attr) = @_;
657 local $Error::Depth = $Error::Depth + 1;
658 my $check = ${$$self->{owner_document}}->{strict_error_checking};
659 if ($check and $$self->{owner_document} ne $new_attr->owner_document) {
660 local $Error::Depth = $Error::Depth - 1;
661 report Message::DOM::DOMException
662 -object => $self,
663 -type => 'WRONG_DOCUMENT_ERR';
664 }
665
666 my $nsuri = $$new_attr->{namespace_uri};
667 $nsuri = '' unless defined $nsuri;
668 my $ln = $$new_attr->{local_name};
669
670 delete $$self->{manakai_content_attribute_list};
671 my $attrs = $$self->{attributes};
672 my $current = $attrs->{$nsuri}->{$ln};
673
674 if (defined $$new_attr->{owner_element}) {
675 if (defined $current and $current eq $new_attr) {
676 ## No effect
677 return undef; # no return value
678 } else {
679 local $Error::Depth = $Error::Depth - 1;
680 report Message::DOM::DOMException
681 -object => $self,
682 -type => 'INUSE_ATTRIBUTE_ERR';
683 }
684 } elsif ($check and $$self->{manakai_read_only}) {
685 report Message::DOM::DOMException
686 -object => $self,
687 -type => 'NO_MODIFICATION_ALLOWED_ERR',
688 -subtype => 'READ_ONLY_NODE_ERR';
689 }
690
691 $attrs->{$nsuri}->{$ln} = $new_attr;
692 $$new_attr->{owner_element} = $self;
693 Scalar::Util::weaken ($$new_attr->{owner_element});
694 $$new_attr->{specified} = 1;
695
696 if (defined $current) {
697 delete $$current->{owner_element};
698 $$current->{specified} = 1;
699 }
700 return $current;
701 } # set_attribute_node
702
703 *set_attribute_node_ns = \&set_attribute_node;
704
705 ## The second parameter only supports manakai extended way
706 ## to specify qualified name - "[$prefix, $local_name]" ## TODO: Document
707 sub set_attribute_ns ($$$$) {
708 my $prefix;
709 my $lname;
710 if (ref $_[2] eq 'ARRAY') {
711 ($prefix, $lname) = @{$_[2]};
712 } else {
713 ($prefix, $lname) = split /:/, $_[2], 2;
714 ($prefix, $lname) = (undef, $prefix) unless defined $lname;
715 }
716
717 my $od = ${$_[0]}->{owner_document};
718 if ($$od->{strict_error_checking}) {
719 if (${$_[0]}->{manakai_read_only}) {
720 report Message::DOM::DOMException
721 -object => $_[0],
722 -type => 'NO_MODIFICATION_ALLOWED_ERR',
723 -subtype => 'READ_ONLY_NODE_ERR';
724 }
725 }
726
727 my $attr = ${$_[0]}->{attributes};
728 my $attr_node = $attr->{defined $_[1] ? ''.$_[1] : ''}->{$lname};
729
730 local $Error::Depth = $Error::Depth + 1;
731 if (defined $attr_node) {
732 if ($$od->{strict_error_checking}) {
733 $od->create_attribute_ns ($_[1], [$prefix, $lname]); # name exception
734 }
735 } else {
736 $attr_node = $od->create_attribute_ns
737 ($_[1], [$prefix, $lname]); # or exception
738 delete ${$_[0]}->{manakai_content_attribute_list};
739 $attr->{defined $_[1] ? ''.$_[1] : ''}->{$lname} = $attr_node;
740 $$attr_node->{owner_element} = $_[0];
741 Scalar::Util::weaken ($$attr_node->{owner_element});
742
743 if ($od->dom_config->get_parameter
744 (q<http://suika.fam.cx/www/2006/dom-config/dtd-attribute-type>)) {
745 my $doctype = $od->doctype;
746 if (defined $doctype) {
747 my $et = $doctype->get_element_type_definition_node
748 ($_[0]->manakai_tag_name);
749 if (defined $et) {
750 my $at = $et->get_attribute_definition_node ($attr_node->manakai_name);
751 if (defined $at) {
752 $attr_node->manakai_attribute_type ($at->declared_type);
753 }
754 }
755 }
756 }
757 }
758
759 $attr_node->value ($_[3]); # set or exception
760 $attr_node->prefix ($prefix);
761 $attr_node->specified (1);
762 return undef;
763 } # set_attribute_ns
764
765 sub set_id_attribute ($$$) {
766 if (${${$_[0]}->{owner_document}}->{strict_error_checking} and
767 ${$_[0]}->{manakai_read_only}) {
768 report Message::DOM::DOMException
769 -object => $_[0],
770 -type => 'NO_MODIFICATION_ALLOWED_ERR',
771 -subtype => 'READ_ONLY_NODE_ERR';
772 }
773
774 my $attr = $_[0]->get_attribute_node ($_[1]);
775 if (not defined $attr) {
776 report Message::DOM::DOMException
777 -object => $_[0],
778 -type => 'NOT_FOUND_ERR',
779 -subtype => 'NOT_CHILD_ERR';
780 } else {
781 local $Error::Depth = $Error::Depth + 1;
782 $attr->is_id ($_[2]); # or exception
783 }
784 return;
785 } # set_id_attribute
786
787 sub set_id_attribute_ns ($$$$) {
788 if (${${$_[0]}->{owner_document}}->{strict_error_checking} and
789 ${$_[0]}->{manakai_read_only}) {
790 report Message::DOM::DOMException
791 -object => $_[0],
792 -type => 'NO_MODIFICATION_ALLOWED_ERR',
793 -subtype => 'READ_ONLY_NODE_ERR';
794 }
795
796 my $attr = $_[0]->get_attribute_node_ns ($_[1], $_[2]);
797 if (not defined $attr) {
798 report Message::DOM::DOMException
799 -object => $_[0],
800 -type => 'NOT_FOUND_ERR',
801 -subtype => 'NOT_CHILD_ERR';
802 } else {
803 local $Error::Depth = $Error::Depth + 1;
804 $attr->is_id ($_[2]);
805 }
806 return;
807 } # set_id_attribute_ns
808
809 sub set_id_attribute_node ($$$$) {
810 if (${${$_[0]}->{owner_document}}->{strict_error_checking} and
811 ${$_[0]}->{manakai_read_only}) {
812 report Message::DOM::DOMException
813 -object => $_[0],
814 -type => 'NO_MODIFICATION_ALLOWED_ERR',
815 -subtype => 'READ_ONLY_NODE_ERR';
816 }
817
818 my $oe = $_[1]->owner_element;
819 if ($oe ne $_[0]) {
820 report Message::DOM::DOMException
821 -object => $_[0],
822 -type => 'NOT_FOUND_ERR',
823 -subtype => 'NOT_CHILD_ERR';
824 } else {
825 local $Error::Depth = $Error::Depth + 1;
826 $_[1]->is_id ($_[2]);
827 }
828 return;
829 } # set_id_attribute_node
830
831 ## |ElementSelector| methods
832
833 sub query_selector ($$;$);
834
835 sub query_selector_all ($$;$);
836
837 ## |ElementCSSInlineStyle| attributes
838
839 ## TODO: documentation
840 sub manakai_computed_style ($) {
841 ## TODO: If not part of document tree
842
843 ## ISSUE: Neither |getComputedStyle| nor |currentStyle| represent
844 ## the set of computed values in the real world (in fact what is
845 ## represented by them disagree in browsers and even |getComputedStyle|
846 ## and |currentStyle| are different in the same Opera browser).
847
848 local $Error::Depth = $Error::Depth + 1;
849 my $self = shift;
850 my $view = $self->owner_document->default_view;
851 return undef unless defined $view; ## ISSUE: Not defined in the spec yet.
852
853 return $view->manakai_get_computed_style ($self);
854 } # manakai_computed_style
855
856 ## TODO: |current_style|, |style|, |runtime_style|
857
858 package Message::IF::Element;
859 package Message::IF::ElementSelector;
860 package Message::IF::ElementCSSInlineStyle;
861
862 package Message::DOM::Document;
863
864 sub create_element ($$) {
865 my $self = $_[0];
866 my $eln = ''.$_[1]; ## TODO: Need testing against DOM Perl binding.
867 if ($$self->{strict_error_checking}) {
868 my $xv = $self->xml_version;
869 ## TODO: HTML Document ??
870 if (defined $xv) {
871 if ($xv eq '1.0' and
872 $eln =~ /\A\p{InXML_NameStartChar10}\p{InXMLNameChar10}*\z/) {
873 #
874 } elsif ($xv eq '1.1' and
875 $eln =~ /\A\p{InXMLNameStartChar11}\p{InXMLNameChar11}*\z/) {
876 #
877 } else {
878 report Message::DOM::DOMException
879 -object => $self,
880 -type => 'INVALID_CHARACTER_ERR',
881 -subtype => 'MALFORMED_NAME_ERR';
882 }
883 }
884 }
885 ## TODO: HTML5
886
887 my $r = Message::DOM::Element->____new ($self, undef, undef, $eln);
888
889 ## -- Default attributes
890 {
891 local $Error::Depth = $Error::Depth + 1;
892 my $cfg = $self->dom_config;
893 return $r
894 unless $cfg->get_parameter
895 (q<http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute>);
896
897 my $doctype = $self->doctype;
898 return $r unless defined $doctype;
899
900 my $et = $doctype->get_element_type_definition_node ($eln);
901 return $r unless defined $et;
902
903 my $orig_strict = $self->strict_error_checking;
904 $self->strict_error_checking (0);
905
906 my %gattr;
907 my %has_attr;
908 my %pfx_to_uri;
909 my $copy_asis = $cfg->get_parameter
910 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree>);
911 $cfg->set_parameter
912 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => 1);
913
914 for my $at (@{$et->attribute_definitions}) {
915 my $at_default = $at->default_type;
916 if ($at_default == 4 or $at_default == 1) {
917 # EXPLICIT_DEFAULT, FIXED_DEFAULT
918 my ($nn1, $nn2) = split /:/, $at->node_name;
919 if (defined $nn2) { # prefixed
920 if ($nn1 eq 'xmlns') {
921 ## TODO: NCName check, prefix check and NSURI check
922 my $attr = $self->create_attribute_ns
923 (q<http://www.w3.org/2000/xmlns/>, [$nn1, $nn2]);
924 for my $at_child (@{$at->child_nodes}) {
925 $attr->append_child ($at_child->clone_node (1));
926 }
927 $attr->manakai_attribute_type ($at->declared_type);
928 my $nsuri = $attr->value;
929 ## TODO: Namespace well-formedness check (NSURI), v1.1 chk
930 $pfx_to_uri{$nn2} = $nsuri;
931 $r->set_attribute_node_ns ($attr);
932 ## NOTE: This method changes |specified| flag
933 $attr->specified (0);
934 $has_attr{q<http://www.w3.org/2000/xmlns/>}->{$nn2} = 1;
935 } else {
936 ## TODO: NCName check
937 $gattr{$nn1}->{$nn2} = $at;
938 }
939 } else { # no prefixed
940 my $attr;
941 if ($nn1 eq 'xmlns') {
942 $attr = $self->create_attribute_ns
943 (q<http://www.w3.org/2000/xmlns/>, 'xmlns');
944 $has_attr{q<http://www.w3.org/2000/xmlns/>}->{xmlns} = 1;
945 } else {
946 $attr = $self->create_attribute_ns (undef, $nn1);
947 ## TODO: NCName check
948 }
949 for my $at_child (@{$at->child_nodes}) {
950 $attr->append_child ($at_child->clone_node (1));
951 }
952 $attr->manakai_attribute_type ($at->declared_type);
953 ## TODO: Namespace well-formedness check (NSURI)
954 $r->set_attribute_node_ns ($attr);
955 ## NOTE: This method changes |specified| flag
956 $attr->specified (0);
957 }
958 }
959 } # attrdefs
960 for my $pfx (keys %gattr) {
961 my $nsuri = $pfx_to_uri{$pfx};
962 unless (defined $nsuri) {
963 ## TODO: Namespace well-formedness error
964 }
965 LN: for my $ln (keys %{$gattr{$pfx}}) {
966 if ($has_attr{defined $nsuri ? $nsuri : ''}->{$ln}) {
967 ## TODO: Namespace well-formedness error
968 next LN;
969 }
970 ## TODO: NCName check, prefix check and NSURI check
971 my $at = $gattr{$pfx}->{$ln};
972 my $attr = $self->create_attribute_ns ($nsuri, [$pfx, $ln]);
973 for my $at_child (@{$at->child_nodes}) {
974 $attr->append_child ($at_child->clone_node (1));
975 }
976 $attr->manakai_attribute_type ($at->declared_type);
977 $r->set_attribute_node_ns ($attr);
978 ## NOTE: This method changes |specified| flag
979 $attr->specified (0);
980 $has_attr{defined $nsuri ? $nsuri : ''}->{$ln} = 1;
981 } # LN
982 } # pfx
983 $cfg->set_parameter
984 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => $copy_asis);
985 $self->strict_error_checking ($orig_strict);
986 }
987
988 return $r;
989 } # create_element
990
991 sub create_element_ns ($$$) {
992 my $self = $_[0];
993 my ($prefix, $lname);
994 if (ref $_[2] eq 'ARRAY') {
995 ($prefix, $lname) = @{$_[2]};
996 } else {
997 ($prefix, $lname) = split /:/, $_[2], 2;
998 ($prefix, $lname) = (undef, $prefix) unless defined $lname;
999 }
1000 my $nsuri = defined $_[1] ? $_[1] eq '' ? undef : ''.$_[1] : undef;
1001 ## TODO: Need tests against DOM Perl binding.
1002
1003 if ($$self->{strict_error_checking}) {
1004 my $xv = $self->xml_version;
1005 ## TODO: HTML Document ?? (NOT_SUPPORTED_ERR is different from what Web browsers do)
1006 if (defined $xv) {
1007 if ($xv eq '1.0') {
1008 if (ref $_[2] eq 'ARRAY' or
1009 $_[2] =~ /\A\p{InXML_NameStartChar10}\p{InXMLNameChar10}*\z/) {
1010 if (defined $prefix) {
1011 if ($prefix =~ /\A\p{InXML_NCNameStartChar10}\p{InXMLNCNameChar10}*\z/) {
1012 #
1013 } else {
1014 report Message::DOM::DOMException
1015 -object => $self,
1016 -type => 'NAMESPACE_ERR',
1017 -subtype => 'MALFORMED_QNAME_ERR';
1018 }
1019 }
1020 if ($lname =~ /\A\p{InXML_NCNameStartChar10}\p{InXMLNCNameChar10}*\z/) {
1021 #
1022 } else {
1023 report Message::DOM::DOMException
1024 -object => $self,
1025 -type => 'NAMESPACE_ERR',
1026 -subtype => 'MALFORMED_QNAME_ERR';
1027 }
1028 } else {
1029 report Message::DOM::DOMException
1030 -object => $self,
1031 -type => 'INVALID_CHARACTER_ERR',
1032 -subtype => 'MALFORMED_NAME_ERR';
1033 }
1034 } elsif ($xv eq '1.1') {
1035 if (ref $_[2] eq 'ARRAY' or
1036 $_[2] =~ /\A\p{InXML_NameStartChar10}\p{InXMLNameChar10}*\z/) {
1037 if (defined $prefix) {
1038 if ($prefix =~ /\A\p{InXMLNCNameStartChar11}\p{InXMLNCNameChar11}*\z/) {
1039 #
1040 } else {
1041 report Message::DOM::DOMException
1042 -object => $self,
1043 -type => 'NAMESPACE_ERR',
1044 -subtype => 'MALFORMED_QNAME_ERR';
1045 }
1046 }
1047 if ($lname =~ /\A\p{InXMLNCNameStartChar11}\p{InXMLNCNameChar11}*\z/) {
1048 #
1049 } else {
1050 report Message::DOM::DOMException
1051 -object => $self,
1052 -type => 'NAMESPACE_ERR',
1053 -subtype => 'MALFORMED_QNAME_ERR';
1054 }
1055 } else {
1056 report Message::DOM::DOMException
1057 -object => $self,
1058 -type => 'INVALID_CHARACTER_ERR',
1059 -subtype => 'MALFORMED_NAME_ERR';
1060 }
1061 } else {
1062 die "create_attribute_ns: XML version |$xv| is not supported";
1063 }
1064 }
1065
1066 if (defined $prefix) {
1067 if (not defined $nsuri) {
1068 report Message::DOM::DOMException
1069 -object => $self,
1070 -type => 'NAMESPACE_ERR',
1071 -subtype => 'PREFIXED_NULLNS_ERR';
1072 } elsif ($prefix eq 'xml' and
1073 $nsuri ne q<http://www.w3.org/XML/1998/namespace>) {
1074 report Message::DOM::DOMException
1075 -object => $self,
1076 -type => 'NAMESPACE_ERR',
1077 -subtype => 'XMLPREFIX_NONXMLNS_ERR';
1078 } elsif ($prefix eq 'xmlns' and
1079 $nsuri ne q<http://www.w3.org/2000/xmlns/>) {
1080 report Message::DOM::DOMException
1081 -object => $self,
1082 -type => 'NAMESPACE_ERR',
1083 -subtype => 'XMLNSPREFIX_NONXMLNSNS_ERR';
1084 } elsif ($nsuri eq q<http://www.w3.org/2000/xmlns/> and
1085 $prefix ne 'xmlns') {
1086 report Message::DOM::DOMException
1087 -object => $self,
1088 -type => 'NAMESPACE_ERR',
1089 -subtype => 'NONXMLNSPREFIX_XMLNSNS_ERR';
1090 }
1091 } else { # no prefix
1092 if ($lname eq 'xmlns' and
1093 (not defined $nsuri or $nsuri ne q<http://www.w3.org/2000/xmlns/>)) {
1094 report Message::DOM::DOMException
1095 -object => $self,
1096 -type => 'NAMESPACE_ERR',
1097 -subtype => 'XMLNS_NONXMLNSNS_ERR';
1098 } elsif (not defined $nsuri) {
1099 #
1100 } elsif ($nsuri eq q<http://www.w3.org/2000/xmlns/> and
1101 $lname ne 'xmlns') {
1102 report Message::DOM::DOMException
1103 -object => $self,
1104 -type => 'NAMESPACE_ERR',
1105 -subtype => 'NONXMLNSPREFIX_XMLNSNS_ERR';
1106 }
1107 }
1108 }
1109
1110 ## -- Choose the most apppropriate class for the element
1111 my $class = 'Message::DOM::Element';
1112 if (defined $nsuri) {
1113 if ($nsuri eq q<http://www.w3.org/1999/xhtml>) {
1114 require Message::DOM::HTML::HTMLElement;
1115 $class = {
1116 a => 'Message::DOM::HTML::HTMLAnchorElement',
1117 area => 'Message::DOM::HTML::HTMLAreaElement',
1118 audio => 'Message::DOM::HTML::HTMLAudioElement',
1119 base => 'Message::DOM::HTML::HTMLBaseElement',
1120 body => 'Message::DOM::HTML::HTMLBodyElement',
1121 canvas => 'Message::DOM::HTML::HTMLCanvasElement',
1122 command => 'Message::DOM::HTML::HTMLCommandElement',
1123 datagrid => 'Message::DOM::HTML::HTMLDataGridElement',
1124 details => 'Message::DOM::HTML::HTMLDetailsElement',
1125 embed => 'Message::DOM::HTML::HTMLEmbedElement',
1126 'event-source' => 'Message::DOM::HTML::HTMLEventSourceElement',
1127 font => 'Message::DOM::HTML::HTMLFontElement',
1128 head => 'Message::DOM::HTML::HTMLHeadElement',
1129 html => 'Message::DOM::HTML::HTMLHtmlElement',
1130 iframe => 'Message::DOM::HTML::HTMLIFrameElement',
1131 img => 'Message::DOM::HTML::HTMLImageElement',
1132 li => 'Message::DOM::HTML::HTMLLIElement',
1133 link => 'Message::DOM::HTML::HTMLLinkElement',
1134 map => 'Message::DOM::HTML::HTMLMapElement',
1135 menu => 'Message::DOM::HTML::HTMLMenuElement',
1136 meta => 'Message::DOM::HTML::HTMLMetaElement',
1137 meter => 'Message::DOM::HTML::HTMLMeterElement',
1138 del => 'Message::DOM::HTML::HTMLModElement',
1139 ins => 'Message::DOM::HTML::HTMLModElement',
1140 object => 'Message::DOM::HTML::HTMLObjectElement',
1141 ol => 'Message::DOM::HTML::HTMLOListElement',
1142 param => 'Message::DOM::HTML::HTMLParamElement',
1143 progress => 'Message::DOM::HTML::HTMLProgressElement',
1144 blockquote => 'Message::DOM::HTML::HTMLQuoteElement',
1145 q => 'Message::DOM::HTML::HTMLQuoteElement',
1146 script => 'Message::DOM::HTML::HTMLScriptElement',
1147 source => 'Message::DOM::HTML::HTMLSourceElement',
1148 style => 'Message::DOM::HTML::HTMLStyleElement',
1149 table => 'Message::DOM::HTML::HTMLTableElement',
1150 td => 'Message::DOM::HTML::HTMLTableCellElement',
1151 col => 'Message::DOM::HTML::HTMLTableColElement',
1152 colgroup => 'Message::DOM::HTML::HTMLTableColElement',
1153 th => 'Message::DOM::HTML::HTMLTableHeaderCellElement',
1154 tr => 'Message::DOM::HTML::HTMLTableRowElement',
1155 tbody => 'Message::DOM::HTML::HTMLTableSectionElement',
1156 tfoot => 'Message::DOM::HTML::HTMLTableSectionElement',
1157 thead => 'Message::DOM::HTML::HTMLTableSectionElement',
1158 time => 'Message::DOM::HTML::HTMLTimeElement',
1159 video => 'Message::DOM::HTML::HTMLVideoElement',
1160 }->{$lname} || 'Message::DOM::HTML::HTMLElement';
1161 } elsif ($nsuri eq q<http://www.w3.org/2005/Atom>) {
1162 require Message::DOM::Atom::AtomElement;
1163 $class = {
1164 author => 'Message::DOM::Atom::AtomElement::AtomPersonConstruct',
1165 category => 'Message::DOM::Atom::AtomElement::AtomCategoryElement',
1166 content => 'Message::DOM::Atom::AtomElement::AtomContentElement',
1167 contributor => 'Message::DOM::Atom::AtomElement::AtomPersonConstruct',
1168 entry => 'Message::DOM::Atom::AtomElement::AtomEntryElement',
1169 feed => 'Message::DOM::Atom::AtomElement::AtomFeedElement',
1170 generator => 'Message::DOM::Atom::AtomElement::AtomGeneratorElement',
1171 link => 'Message::DOM::Atom::AtomElement::AtomLinkElement',
1172 published => 'Message::DOM::Atom::AtomElement::AtomDateConstruct',
1173 rights => 'Message::DOM::Atom::AtomElement::AtomTextConstruct',
1174 source => 'Message::DOM::Atom::AtomElement::AtomSourceElement',
1175 subtitle => 'Message::DOM::Atom::AtomElement::AtomTextConstruct',
1176 summary => 'Message::DOM::Atom::AtomElement::AtomTextConstruct',
1177 title => 'Message::DOM::Atom::AtomElement::AtomTextConstruct',
1178 updated => 'Message::DOM::Atom::AtomElement::AtomDateConstruct',
1179 }->{$lname} || 'Message::DOM::Atom::AtomElement';
1180 }
1181 }
1182
1183 my $r = $class->____new ($self, $nsuri, $prefix, $lname);
1184
1185 ## -- Default attributes
1186 {
1187 local $Error::Depth = $Error::Depth + 1;
1188 my $cfg = $self->dom_config;
1189 return $r
1190 unless $cfg->get_parameter
1191 (q<http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute>);
1192
1193 my $doctype = $self->doctype;
1194 return $r unless defined $doctype;
1195
1196 my $et = $doctype->get_element_type_definition_node
1197 (defined $prefix ? $prefix . ':' . $lname : $lname);
1198 return $r unless defined $et;
1199
1200 my $orig_strict = $self->strict_error_checking;
1201 $self->strict_error_checking (0);
1202
1203 my %gattr;
1204 my %has_attr;
1205 my %pfx_to_uri;
1206 my $copy_asis = $cfg->get_parameter
1207 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree>);
1208 $cfg->set_parameter
1209 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => 1);
1210
1211 for my $at (@{$et->attribute_definitions}) {
1212 my $at_default = $at->default_type;
1213 if ($at_default == 4 or $at_default == 1) {
1214 # EXPLICIT_DEFAULT, FIXED_DEFAULT
1215 my ($nn1, $nn2) = split /:/, $at->node_name;
1216 if (defined $nn2) { # prefixed
1217 if ($nn1 eq 'xmlns') {
1218 ## TODO: NCName check, prefix check and NSURI check
1219 my $attr = $self->create_attribute_ns
1220 (q<http://www.w3.org/2000/xmlns/>, [$nn1, $nn2]);
1221 for my $at_child (@{$at->child_nodes}) {
1222 $attr->append_child ($at_child->clone_node (1));
1223 }
1224 $attr->manakai_attribute_type ($at->declared_type);
1225 my $nsuri = $attr->value;
1226 ## TODO: Namespace well-formedness check (NSURI), v1.1 chk
1227 $pfx_to_uri{$nn2} = $nsuri;
1228 $r->set_attribute_node_ns ($attr);
1229 ## NOTE: This method changes |specified| flag
1230 $attr->specified (0);
1231 $has_attr{q<http://www.w3.org/2000/xmlns/>}->{$nn2} = 1;
1232 } else {
1233 ## TODO: NCName check
1234 $gattr{$nn1}->{$nn2} = $at;
1235 }
1236 } else { # no prefixed
1237 my $attr;
1238 if ($nn1 eq 'xmlns') {
1239 $attr = $self->create_attribute_ns
1240 (q<http://www.w3.org/2000/xmlns/>, 'xmlns');
1241 $has_attr{q<http://www.w3.org/2000/xmlns/>}->{xmlns} = 1;
1242 } else {
1243 $attr = $self->create_attribute_ns (undef, $nn1);
1244 ## TODO: NCName check
1245 }
1246 for my $at_child (@{$at->child_nodes}) {
1247 $attr->append_child ($at_child->clone_node (1));
1248 }
1249 $attr->manakai_attribute_type ($at->declared_type);
1250 ## TODO: Namespace well-formedness check (NSURI)
1251 $r->set_attribute_node_ns ($attr);
1252 ## NOTE: This method changes |specified| flag
1253 $attr->specified (0);
1254 }
1255 }
1256 } # attrdefs
1257 for my $pfx (keys %gattr) {
1258 my $nsuri = $pfx_to_uri{$pfx};
1259 unless (defined $nsuri) {
1260 ## TODO: Namespace well-formedness error
1261 }
1262 LN: for my $ln (keys %{$gattr{$pfx}}) {
1263 if ($has_attr{defined $nsuri ? $nsuri : ''}->{$ln}) {
1264 ## TODO: Namespace well-formedness error
1265 next LN;
1266 }
1267 ## TODO: NCName check, prefix check and NSURI check
1268 my $at = $gattr{$pfx}->{$ln};
1269 my $attr = $self->create_attribute_ns ($nsuri, [$pfx, $ln]);
1270 for my $at_child (@{$at->child_nodes}) {
1271 $attr->append_child ($at_child->clone_node (1));
1272 }
1273 $attr->manakai_attribute_type ($at->declared_type);
1274 $r->set_attribute_node_ns ($attr);
1275 ## NOTE: This method changes |specified| flag
1276 $attr->specified (0);
1277 $has_attr{defined $nsuri ? $nsuri : ''}->{$ln} = 1;
1278 } # LN
1279 } # pfx
1280 $cfg->set_parameter
1281 (q<http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree> => $copy_asis);
1282 $self->strict_error_checking ($orig_strict);
1283 }
1284
1285 return $r;
1286 } # create_element_ns
1287
1288 =head1 LICENSE
1289
1290 Copyright 2007-2008 Wakaba <w@suika.fam.cx>
1291
1292 This program is free software; you can redistribute it and/or
1293 modify it under the same terms as Perl itself.
1294
1295 =cut
1296
1297 1;
1298 ## $Date: 2008/01/24 11:25:19 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24