/[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 - (hide 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 wakaba 1.22 ## NOTE: This module will be renamed as Element.pm.
2    
3     package Message::DOM::Element;
4 wakaba 1.1 use strict;
5 wakaba 1.23 our $VERSION=do{my @r=(q$Revision: 1.22 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
6 wakaba 1.22 push our @ISA, 'Message::DOM::Node', 'Message::IF::Element';
7 wakaba 1.9 require Message::DOM::Document;
8 wakaba 1.22
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 wakaba 1.10 sub AUTOLOAD {
20 wakaba 1.22 my $method_name = our $AUTOLOAD;
21     $method_name =~ s/.*:://;
22     return if $method_name eq 'DESTROY';
23 wakaba 1.10
24 wakaba 1.22 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 wakaba 1.10 }
56 wakaba 1.22 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 wakaba 1.10
66 wakaba 1.22 ## TODO: Test for create_element_ns ('', ...)
67 wakaba 1.10
68 wakaba 1.22 ## |Node| attributes
69 wakaba 1.9
70 wakaba 1.22 sub attributes ($) {
71     require Message::DOM::NamedNodeMap;
72     return bless \\($_[0]), 'Message::DOM::NamedNodeMap::AttrMap';
73     } # attributes
74 wakaba 1.9
75 wakaba 1.22 sub base_uri ($) {
76     my $self = $_[0];
77     return $$self->{manakai_base_uri} if defined $$self->{manakai_base_uri};
78 wakaba 1.9
79 wakaba 1.22 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 wakaba 1.9
86 wakaba 1.22 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 wakaba 1.9
98 wakaba 1.22 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 wakaba 1.9 }
110 wakaba 1.22 $pe = $$pe->{parent_node};
111     }
112     return $pe->base_uri if $pe;
113     return $$self->{owner_document}->base_uri;
114     } # base_uri
115 wakaba 1.9
116 wakaba 1.22 sub local_name ($) { # TODO: HTML5 case
117     return ${$_[0]}->{local_name};
118     } # local_name
119 wakaba 1.9
120 wakaba 1.22 sub manakai_local_name ($) {
121     return ${$_[0]}->{local_name};
122     } # manakai_local_name
123 wakaba 1.9
124 wakaba 1.22 sub namespace_uri ($);
125 wakaba 1.9
126 wakaba 1.22 ## The tag name of the element [DOM1, DOM2].
127     ## Same as |Element.tagName| [DOM3].
128 wakaba 1.9
129 wakaba 1.22 *node_name = \&tag_name;
130 wakaba 1.9
131 wakaba 1.22 sub node_type () { 1 } # ELEMENT_NODE
132 wakaba 1.9
133 wakaba 1.22 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 wakaba 1.9
137 wakaba 1.22 ## NOTE: Same as trivial setter except "" -> undef
138 wakaba 1.9
139 wakaba 1.22 ## 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 wakaba 1.9
157 wakaba 1.22 ## |Element| attributes
158 wakaba 1.9
159 wakaba 1.22 sub manakai_base_uri ($;$);
160 wakaba 1.9
161 wakaba 1.22 ## Defined in |HTMLElement| interface of HTML5
162     sub inner_html ($;$) {
163     my $self = $_[0];
164 wakaba 1.9
165 wakaba 1.22 ## TODO: Setter
166 wakaba 1.9
167 wakaba 1.22 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 wakaba 1.9
181 wakaba 1.22 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 wakaba 1.9
192 wakaba 1.22 ## 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 wakaba 1.9
202 wakaba 1.22 ## 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 wakaba 1.9
212 wakaba 1.22 ## The |Element| interface - methods
213 wakaba 1.9
214 wakaba 1.22 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 wakaba 1.9 }
222     } else {
223 wakaba 1.22 if (not defined $$self->{namespace_uri}) {
224     return ($ln eq $$self->{local_name});
225     } else {
226     return 0;
227 wakaba 1.9 }
228     }
229 wakaba 1.22 } # manakai_element_type_match
230 wakaba 1.9
231 wakaba 1.22 sub get_attribute ($$) {
232     my $attr = ${$_[0]}->{attributes};
233     my $name = ''.$_[1];
234 wakaba 1.9
235 wakaba 1.22 ## 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 wakaba 1.9
240 wakaba 1.22 ## NOTE: Same as |get_attribute_node|, except what is returned.
241 wakaba 1.9
242 wakaba 1.22 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 wakaba 1.9 }
250    
251 wakaba 1.22 return undef;
252     } # get_attribute
253 wakaba 1.9
254 wakaba 1.22 sub get_attribute_node ($$) {
255     my $attr = ${$_[0]}->{attributes};
256     my $name = ''.$_[1];
257 wakaba 1.9
258 wakaba 1.22 ## NOTE: Same as |get_attribute|, except what is returned.
259 wakaba 1.9
260 wakaba 1.22 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 wakaba 1.13 }
267 wakaba 1.18 }
268 wakaba 1.9
269 wakaba 1.22 return undef;
270     } # get_attribute_node
271 wakaba 1.9
272 wakaba 1.22 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 wakaba 1.9 } else {
278 wakaba 1.22 return undef;
279 wakaba 1.9 }
280 wakaba 1.22 } # get_attribute_ns
281 wakaba 1.9
282 wakaba 1.22 sub get_attribute_node_ns ($$$) {
283     return ${$_[0]}->{attributes}->{defined $_[1] ? ''.$_[1] : ''}->{''.$_[2]};
284     } # get_attribute_node_ns
285 wakaba 1.9
286 wakaba 1.22 *get_elements_by_tag_name = \&Message::DOM::Document::get_elements_by_tag_name;
287 wakaba 1.9
288 wakaba 1.22 *get_elements_by_tag_name_ns
289     = \&Message::DOM::Document::get_elements_by_tag_name_ns;
290 wakaba 1.13
291 wakaba 1.22 sub has_attribute ($$) {
292     my $attr = ${$_[0]}->{attributes};
293     my $name = ''.$_[1];
294 wakaba 1.13
295 wakaba 1.22 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 wakaba 1.13
304 wakaba 1.22 return 0;
305     } # has_attribute
306 wakaba 1.9
307 wakaba 1.22 sub has_attribute_ns ($$$) {
308     return ${$_[0]}->{attributes}->{defined $_[1] ? ''.$_[1] : ''}->{''.$_[2]}?1:0;
309     } # has_attribute_ns
310 wakaba 1.9
311 wakaba 1.22 sub remove_attribute ($$) {
312     my $attr = ${$_[0]}->{attributes};
313     my $name = ''.$_[1];
314 wakaba 1.9
315 wakaba 1.22 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 wakaba 1.9
333 wakaba 1.22 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 wakaba 1.9
341 wakaba 1.22 delete $list->{$key};
342     delete $$attr_node->{owner_element};
343     $$attr_node->{specified} = 1;
344     delete ${$_[0]}->{manakai_content_attribute_list};
345 wakaba 1.9
346 wakaba 1.22 ## 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 wakaba 1.9 }
376 wakaba 1.22 $def_ln = $attr_node->manakai_local_name;
377 wakaba 1.9 } else {
378 wakaba 1.22 $def_nsuri = $name eq 'xmlns'
379     ? q<http://www.w3.org/2000/xmlns/> : undef;
380     $def_ln = $name;
381 wakaba 1.9 }
382 wakaba 1.22 if ($attr->{defined $def_nsuri ? $def_nsuri : ''}->{$def_ln}) {
383     ## TODO: Namespace well-formedness warning?
384     last ADD;
385 wakaba 1.9 }
386 wakaba 1.22 $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 wakaba 1.9 }
392 wakaba 1.22 $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 wakaba 1.9 }
402 wakaba 1.22 }
403 wakaba 1.9 }
404 wakaba 1.22 }
405 wakaba 1.9
406 wakaba 1.22 return undef;
407     } # remove_attribute
408 wakaba 1.9
409 wakaba 1.22 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 wakaba 1.9
440 wakaba 1.22 ## 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 wakaba 1.9 }
499 wakaba 1.22 }
500 wakaba 1.9
501 wakaba 1.22 return $_[1];
502     } # remove_attribute_node
503 wakaba 1.9
504 wakaba 1.22 sub remove_attribute_ns ($$$) {
505     my $attr = ${$_[0]}->{attributes};
506 wakaba 1.9
507 wakaba 1.22 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 wakaba 1.9
527 wakaba 1.22 ## 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 wakaba 1.9 }
585 wakaba 1.22 }
586 wakaba 1.9
587 wakaba 1.22 return undef;
588     } # remove_attribute_ns
589 wakaba 1.9
590 wakaba 1.22 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 wakaba 1.9 }
599 wakaba 1.22 }
600 wakaba 1.9
601 wakaba 1.22 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 wakaba 1.9 }
612     }
613    
614 wakaba 1.22 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 wakaba 1.9
642 wakaba 1.22 $attr_node->value ($_[2]); # set or exception
643     $attr_node->specified (1);
644     return undef;
645     } # set_attribute
646 wakaba 1.9
647 wakaba 1.22 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 wakaba 1.9
688 wakaba 1.22 if (defined $current) {
689     delete $$current->{owner_element};
690     $$current->{specified} = 1;
691     }
692     return $current;
693     } # set_attribute_node
694 wakaba 1.9
695 wakaba 1.22 *set_attribute_node_ns = \&set_attribute_node;
696 wakaba 1.9
697 wakaba 1.22 ## 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 wakaba 1.9 }
718    
719 wakaba 1.22 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 wakaba 1.9 }
750    
751 wakaba 1.22 $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 wakaba 1.9 }
820 wakaba 1.22 return;
821     } # set_id_attribute_node
822 wakaba 1.9
823 wakaba 1.22 package Message::IF::Element;
824 wakaba 1.9
825 wakaba 1.22 package Message::DOM::Document;
826 wakaba 1.9
827 wakaba 1.22 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 wakaba 1.13 }
847 wakaba 1.22 ## 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 wakaba 1.13 }
949 wakaba 1.9
950 wakaba 1.22 return $r;
951     } # create_element
952 wakaba 1.9
953 wakaba 1.22 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 wakaba 1.1 }
981 wakaba 1.22 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 wakaba 1.1 }
989 wakaba 1.22 } else {
990     report Message::DOM::DOMException
991     -object => $self,
992     -type => 'INVALID_CHARACTER_ERR',
993     -subtype => 'MALFORMED_NAME_ERR';
994 wakaba 1.1 }
995 wakaba 1.22 } 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 wakaba 1.1 }
1016 wakaba 1.22 } else {
1017     report Message::DOM::DOMException
1018     -object => $self,
1019     -type => 'INVALID_CHARACTER_ERR',
1020     -subtype => 'MALFORMED_NAME_ERR';
1021 wakaba 1.1 }
1022 wakaba 1.9 } else {
1023 wakaba 1.22 die "create_attribute_ns: XML version |$xv| is not supported";
1024 wakaba 1.9 }
1025     }
1026 wakaba 1.1
1027 wakaba 1.22 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 wakaba 1.23 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 wakaba 1.22 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 wakaba 1.10 }
1223 wakaba 1.22 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 wakaba 1.10 }
1245    
1246 wakaba 1.22 return $r;
1247     } # create_element_ns
1248 wakaba 1.10
1249 wakaba 1.22 =head1 LICENSE
1250 wakaba 1.10
1251 wakaba 1.22 Copyright 2007 Wakaba <w@suika.fam.cx>
1252 wakaba 1.10
1253 wakaba 1.22 This program is free software; you can redistribute it and/or
1254     modify it under the same terms as Perl itself.
1255 wakaba 1.10
1256 wakaba 1.22 =cut
1257 wakaba 1.10
1258 wakaba 1.1 1;
1259 wakaba 1.23 ## $Date: 2007/07/29 08:31:14 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24