/[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.31 - (show annotations) (download)
Sun Nov 9 14:06:24 2008 UTC (16 years ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +8 -4 lines
Error occurred while calculating annotation data.
++ manakai/lib/Message/CGI/ChangeLog	29 Oct 2008 05:42:58 -0000
2008-10-29  Wakaba  <wakaba@suika.fam.cx>

	* HTTP.pm (remote_user): New method.

++ manakai/lib/Message/DOM/ChangeLog	9 Nov 2008 14:06:17 -0000
2008-11-09  Wakaba  <wakaba@suika.fam.cx>

	* Element.pm (inner_html): Setter for HTML element nodes
	implemented.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24