/[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.23 - (show annotations) (download)
Sun Jul 29 11:38:57 2007 UTC (17 years, 4 months ago) by wakaba
Branch: MAIN
Changes since 1.22: +51 -3 lines
++ manakai/lib/Message/DOM/ChangeLog	29 Jul 2007 11:38:40 -0000
	* HTML/: New directory.

	* Element.pm (create_element_ns): Return object implementing
	the |HTMLElement| interface for HTML elements.

2007-07-29  Wakaba  <wakaba@suika.fam.cx>

++ manakai/lib/Message/DOM/HTML/ChangeLog	29 Jul 2007 11:37:55 -0000
2007-07-29  Wakaba  <wakaba@suika.fam.cx>

	* ChangeLog: New file.

	* HTMLElement.pm: New module.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24