/[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.25 - (hide annotations) (download)
Sun Nov 11 04:23:32 2007 UTC (17 years ago) by wakaba
Branch: MAIN
Changes since 1.24: +4 -4 lines
++ manakai/lib/Message/DOM/ChangeLog	11 Nov 2007 04:23:26 -0000
2007-11-11  Wakaba  <wakaba@suika.fam.cx>

	* Document.pm, Element.pm (inner_html): Use |Whatpm::HTML::Serializer|
	for getter.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24