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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (hide annotations) (download)
Sun Nov 9 14:06:24 2008 UTC (16 years ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +8 -4 lines
++ manakai/lib/Message/CGI/ChangeLog	29 Oct 2008 05:42:58 -0000
2008-10-29  Wakaba  <wakaba@suika.fam.cx>

	* HTTP.pm (remote_user): New method.

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

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

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24