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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.22 - (hide annotations) (download)
Mon Sep 24 10:16:14 2007 UTC (17 years, 2 months ago) by wakaba
Branch: MAIN
CVS Tags: manakai-release-0-4-0
Changes since 1.21: +6 -2 lines
++ manakai/lib/Message/DOM/ChangeLog	24 Sep 2007 10:15:28 -0000
2007-09-24  Wakaba  <wakaba@suika.fam.cx>

	* DOMException.pm (SYNTAX_ERR): New subtype is defined.
	(UNDECLARED_PREFIX_ERR): New subtype is defined.

	* Document.pm (Document): Implements the |DocumentSelector|
	interface.

	* Element.pm (Element): Implements the |ElementSelector|
	interface.

	* Node.pm (Node): Implements the |NSResolver| interface.

	* SelectorsAPI.pm: Now (hopefully) conform to the Selectors
	API Editor's Draft (only |query_selector_all| on |Document|,
	with limited selectors syntax support, though).

++ manakai/t/ChangeLog	24 Sep 2007 10:16:05 -0000
2007-09-24  Wakaba  <wakaba@suika.fam.cx>

	* selectors-test-1.dat: New tests for pseudo-elements
	are added.

1 wakaba 1.21 ## NOTE: This module will be renamed as Document.pm.
2 wakaba 1.1
3 wakaba 1.21 package Message::DOM::Document;
4     use strict;
5 wakaba 1.22 our $VERSION=do{my @r=(q$Revision: 1.21 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
6 wakaba 1.21 push our @ISA, 'Message::DOM::Node', 'Message::IF::Document',
7     'Message::IF::DocumentTraversal', 'Message::IF::DocumentXDoctype',
8 wakaba 1.22 'Message::IF::DocumentSelector', # MUST in Selectors API spec
9 wakaba 1.21 'Message::IF::HTMLDocument';
10     require Message::DOM::Node;
11     use Char::Class::XML
12     qw/
13     InXML_NameStartChar10 InXMLNameStartChar11
14     InXMLNameChar10 InXMLNameChar11
15     InXML_NCNameStartChar10 InXMLNCNameStartChar11
16     InXMLNCNameChar10 InXMLNCNameChar11
17     /;
18    
19     sub ____new ($$) {
20     my $self = shift->SUPER::____new (undef);
21     $$self->{implementation} = $_[0];
22     $$self->{strict_error_checking} = 1;
23     $$self->{child_nodes} = [];
24     $$self->{'http://suika.fam.cx/www/2006/dom-config/strict-document-children'} = 1;
25     $$self->{'http://suika.fam.cx/www/2006/dom-config/dtd-default-attribute'} = 1;
26     $$self->{'http://suika.fam.cx/www/2006/dom-config/clone-entity-reference-subtree'} = 1;
27     $$self->{'error-handler'} = sub ($) {
28     ## NOTE: Same as one set by |setParameter| with |undef| value.
29     warn $_[0];
30     return $_[0]->severity != 3; # SEVERITY_FATAL_ERROR
31     };
32     return $self;
33     } # ____new
34    
35     sub AUTOLOAD {
36     my $method_name = our $AUTOLOAD;
37     $method_name =~ s/.*:://;
38     return if $method_name eq 'DESTROY';
39 wakaba 1.1
40     if ({
41 wakaba 1.21 ## Read-only attributes (trivial accessors)
42     implementation => 1,
43     }->{$method_name}) {
44     no strict 'refs';
45     eval qq{
46     sub $method_name (\$) {
47     return \${\$_[0]}->{$method_name};
48 wakaba 1.1 }
49 wakaba 1.21 };
50     goto &{ $AUTOLOAD };
51     } elsif ({
52     ## Read-write attributes (DOMString, trivial accessors)
53     document_uri => 1,
54     input_encoding => 1,
55     }->{$method_name}) {
56     no strict 'refs';
57     eval qq{
58     sub $method_name (\$;\$) {
59     if (\@_ > 1) {
60     if (\${\$_[0]}->{strict_error_checking} and
61     \${\$_[0]}->{manakai_read_only}) {
62     report Message::DOM::DOMException
63     -object => \$_[0],
64     -type => 'NO_MODIFICATION_ALLOWED_ERR',
65     -subtype => 'READ_ONLY_NODE_ERR';
66     }
67     if (defined \$_[1]) {
68     \${\$_[0]}->{$method_name} = ''.\$_[1];
69     } else {
70     delete \${\$_[0]}->{$method_name};
71     }
72     }
73     return \${\$_[0]}->{$method_name};
74 wakaba 1.1 }
75 wakaba 1.21 };
76     goto &{ $AUTOLOAD };
77     } elsif ({
78     ## Read-write attributes (boolean, trivial accessors)
79     all_declarations_processed => 1,
80     }->{$method_name}) {
81     no strict 'refs';
82     eval qq{
83     sub $method_name (\$;\$) {
84     if (\@_ > 1) {
85     if (\${\$_[0]}->{manakai_strict_error_checking} and
86     \${\$_[0]}->{manakai_read_only}) {
87     report Message::DOM::DOMException
88     -object => \$_[0],
89     -type => 'NO_MODIFICATION_ALLOWED_ERR',
90     -subtype => 'READ_ONLY_NODE_ERR';
91     }
92     if (\$_[1]) {
93     \${\$_[0]}->{$method_name} = 1;
94     } else {
95     delete \${\$_[0]}->{$method_name};
96 wakaba 1.1 }
97     }
98 wakaba 1.21 return \${\$_[0]}->{$method_name};
99     }
100     };
101     goto &{ $AUTOLOAD };
102     } elsif (my $module_name = {
103     create_attribute => 'Message::DOM::Attr',
104     create_attribute_ns => 'Message::DOM::Attr',
105     create_attribute_definition => 'Message::DOM::AttributeDefinition',
106     create_cdata_section => 'Message::DOM::Text',
107     create_comment => 'Message::DOM::CharacterData',
108     create_document_fragment => 'Message::DOM::DocumentFragment',
109     create_document_type_definition => 'Message::DOM::DocumentType',
110     create_element => 'Message::DOM::Element',
111     create_element_ns => 'Message::DOM::Element',
112     create_element_type_definition => 'Message::DOM::ElementTypeDefinition',
113     create_entity_reference => 'Message::DOM::EntityReference',
114     create_general_entity => 'Message::DOM::Entity',
115     create_notation => 'Message::DOM::Notation',
116     create_processing_instruction => 'Message::DOM::ProcessingInstruction',
117     manakai_create_serial_walker => 'Message::DOM::SerialWalker',
118     create_text_node => 'Message::DOM::Text',
119     create_tree_walker => 'Message::DOM::TreeWalker',
120 wakaba 1.22 query_selector => 'Message::DOM::SelectorsAPI',
121     query_selector_all => 'Message::DOM::SelectorsAPI',
122 wakaba 1.21 }->{$method_name}) {
123     eval qq{ require $module_name } or die $@;
124     goto &{ $AUTOLOAD };
125     } else {
126     require Carp;
127     Carp::croak (qq<Can't locate method "$AUTOLOAD">);
128 wakaba 1.1 }
129 wakaba 1.21 } # AUTOLOAD
130     sub implementation ($);
131     sub create_attribute ($$);
132     sub create_attribute_ns ($$$);
133     sub create_attribute_definition ($$);
134     sub create_cdata_section ($$);
135     sub create_comment ($$);
136     sub create_document_fragment ($);
137     sub create_document_type_definition ($$);
138     sub create_element ($$);
139     sub create_element_ns ($$$);
140     sub create_element_type_definition ($$);
141     sub create_entity_reference ($$);
142     sub create_general_entity ($$);
143     sub create_notation ($$);
144     sub create_processing_instruction ($$$);
145     sub create_text_node ($$);
146    
147     ## |Node| attributes
148    
149     sub base_uri ($) {
150     my $v = ${$_[0]}->{manakai_entity_base_uri};
151     if (defined $v) {
152     return $v;
153     } else {
154     return ${$_[0]}->{document_uri};
155 wakaba 1.13 }
156 wakaba 1.21 ## TODO: HTML5 <base>
157     } # base_uri
158 wakaba 1.1
159 wakaba 1.21 sub node_name () { '#document' }
160 wakaba 1.1
161 wakaba 1.21 sub node_type () { 9 } # DOCUMENT_NODE
162 wakaba 1.1
163 wakaba 1.21 sub text_content ($;$) {
164     my $self = shift;
165     if ($$self->{'http://suika.fam.cx/www/2006/dom-config/strict-document-children'}) {
166     return undef;
167 wakaba 1.1 } else {
168 wakaba 1.21 local $Error::Depth = $Error::Depth + 1;
169     return $self->SUPER::text_content (@_);
170 wakaba 1.1 }
171 wakaba 1.21 } # text_content
172 wakaba 1.1
173 wakaba 1.21 ## |Node| methods
174 wakaba 1.1
175 wakaba 1.21 sub adopt_node ($$) {
176     my ($self, $source) = @_;
177     ## TODO: Should we apply |copy-asis| configuration parameter to this method?
178 wakaba 1.1
179 wakaba 1.21 return undef unless UNIVERSAL::isa ($source, 'Message::DOM::Node');
180 wakaba 1.1
181 wakaba 1.21 my $strict = $self->strict_error_checking;
182     if ($strict and $$self->{manakai_read_only}) {
183     report Message::DOM::DOMException
184     -object => $self,
185     -type => 'NO_MODIFICATION_ALLOWED_ERR',
186     -subtype => 'READ_ONLY_NODE_ERR';
187     }
188 wakaba 1.1
189 wakaba 1.21 my $parent = $source->parent_node;
190     if ($strict and defined $parent and $$parent->{manakai_read_only}) {
191     report Message::DOM::DOMException
192     -object => $self,
193     -type => 'NO_MODIFICATION_ALLOWED_ERR',
194     -subtype => 'READ_ONLY_NODE_ERR';
195     }
196 wakaba 1.1
197 wakaba 1.21 my $nt = $source->node_type;
198     my $oe;
199     if ($nt == 2) { # ATTRIBUTE_NODE
200     $oe = $source->owner_element;
201     if ($strict and defined $oe and $$oe->{manakai_read_only}) {
202     report Message::DOM::DOMException
203     -object => $self,
204     -type => 'NO_MODIFICATION_ALLOWED_ERR',
205     -subtype => 'READ_ONLY_NODE_ERR';
206     }
207     } elsif ($nt == 9 or $nt == 10 or $nt == 6 or $nt == 12 or
208     $nt == 81001 or $nt == 81002) {
209     # DOCUMENT_NODE, DOCUMENT_TYPE_NODE, ENTITY_NODE, NOTATION_NODE,
210     # ELEMENT_TYPE_DEFINITION_NODE, ATTRIBUTE_DEFINITION_NODE
211     report Message::DOM::DOMException
212     -object => $self,
213     -type => 'NOT_SUPPORTED_ERR',
214     -subtype => 'ADOPT_NODE_TYPE_NOT_SUPPORTED_ERR';
215     ## ISSUE: Define ELEMENT_TYPE_DEFINITION_NODE and ATTRIBUTE_DEFINITION_NODE
216     }
217 wakaba 1.1
218 wakaba 1.21 my @change_od;
219     my @nodes = ($source);
220     while (@nodes) {
221     my $node = shift @nodes;
222     my $nt = $node->node_type;
223     if ($strict and $$node->{manakai_read_only}) {
224     report Message::DOM::DOMException
225     -object => $self,
226     -type => 'NO_MODIFICATION_ALLOWED_ERR',
227     -subtype => 'READ_ONLY_NODE_ERR';
228 wakaba 1.1 }
229    
230 wakaba 1.21 push @change_od, $node;
231     push @nodes, @{$node->child_nodes}, @{$node->attributes or []};
232     } # @nodes
233 wakaba 1.1
234 wakaba 1.21 local $Error::Depth = $Error::Depth + 1;
235 wakaba 1.1
236 wakaba 1.21 if (defined $parent) {
237     $parent->remove_child ($source);
238     } elsif (defined $oe) {
239     $oe->remove_attribute_node ($source);
240     }
241 wakaba 1.1
242 wakaba 1.21 return $source if $self eq $change_od[0]->owner_document;
243     ## NOTE: The array must have more than zero
244     ## nodes by definition. In addition,
245     ## it cannot contain document or document
246     ## type nodes in current implementation.
247 wakaba 1.1
248 wakaba 1.21 my @ud_node;
249     for my $n (@change_od) {
250     $$n->{owner_document} = $self;
251     Scalar::Util::weaken ($$n->{owner_document});
252     if ($$n->{user_data}) {
253     push @ud_node, $n;
254     }
255     }
256 wakaba 1.1
257 wakaba 1.21 for my $src (@ud_node) {
258     my $src_ud = $$src->{user_data};
259     for my $key (keys %{$src_ud}) {
260     my $dh = $src_ud->{$key}->[1];
261     if ($dh) {
262     $dh->(5, $key, $src_ud->{$key}->[0], $src, undef); # NODE_ADOPTED
263 wakaba 1.1 }
264     }
265     }
266    
267 wakaba 1.21 return $source;
268     } # adopt_node
269    
270     sub append_child ($$) {
271     ## NOTE: Overrides |Node|'s implementation.
272     my $self = $_[0];
273 wakaba 1.1
274 wakaba 1.21 ## NOTE: |$self_od| code here in some $self->node_type.
275 wakaba 1.1
276 wakaba 1.21 ## -- Node Type check
277     my @new_child;
278     my $new_child_parent;
279     if ($_[1]->node_type == 11) { # DOCUMENT_FRAGMENT_NODE
280     push @new_child, @{$_[1]->child_nodes};
281     $new_child_parent = $_[1];
282     } else {
283     @new_child = ($_[1]);
284     $new_child_parent = $_[1]->parent_node;
285     }
286 wakaba 1.1
287 wakaba 1.21 ## NOTE: Depends on $self->node_type:
288     if ($$self->{strict_error_checking}) {
289     my $child_od = $_[1]->owner_document || $_[1]; # might be DocumentType
290     if ($self ne $child_od and $child_od->node_type != 10) {
291     report Message::DOM::DOMException # DOCUMENT_TYPE_NODE
292     -object => $self,
293     -type => 'WRONG_DOCUMENT_ERR',
294     -subtype => 'EXTERNAL_OBJECT_ERR';
295     }
296    
297     if ($$self->{manakai_read_only} or
298     (@new_child and defined $new_child_parent and
299     $$new_child_parent->{manakai_read_only})) {
300     report Message::DOM::DOMException
301     -object => $self,
302     -type => 'NO_MODIFICATION_ALLOWED_ERR',
303     -subtype => 'READ_ONLY_NODE_ERR';
304     }
305    
306     ## NOTE: Only in |Document|:
307     my $strict_children = $self->dom_config->get_parameter
308     (q<http://suika.fam.cx/www/2006/dom-config/strict-document-children>);
309     if ($strict_children) {
310     my $has_el;
311     my $has_dt;
312     my $child_nt = $_[1]->node_type;
313     if ($child_nt == 1) { # ELEMENT_NODE
314     $has_el = 1;
315     } elsif ($child_nt == 10) { # DOCUMENT_TYPE_NODE
316     $has_dt = 1;
317     } elsif ($child_nt == 11) { # DOCUMENT_FRAGMENT_NODE
318     for my $cn (@{$_[1]->child_nodes}) {
319     my $cnt = $cn->node_type;
320     if ($cnt == 1) { # ELEMENT_NODE
321     if ($has_el) {
322     report Message::DOM::DOMException
323     -object => $self,
324     -type => 'HIERARCHY_REQUEST_ERR',
325     -subtype => 'CHILD_NODE_TYPE_ERR';
326     }
327     $has_el = 1;
328     } elsif ($cnt == 10) { # DOCUMENT_TYPE_NODE
329     ## NOTE: |DocumentType| node cannot be contained in
330     ## |DocumentFragment| in strict mode.
331     if ($has_dt) {
332     report Message::DOM::DOMException
333     -object => $self,
334     -type => 'HIERARCHY_REQUEST_ERR',
335     -subtype => 'CHILD_NODE_TYPE_ERR';
336     }
337     $has_dt = 1;
338     }
339     }
340     }
341    
342     if ($has_el) {
343     my $anode = $self->last_child;
344     while (defined $anode) {
345     if ($anode->node_type == 1) { # ELEMENT_NODE
346     report Message::DOM::DOMException
347     -object => $self,
348     -type => 'HIERARCHY_REQUEST_ERR',
349     -subtype => 'CHILD_NODE_TYPE_ERR';
350     }
351     $anode = $anode->previous_sibling;
352     }
353     } # has_el
354     if ($has_dt) {
355     my $anode = $self->last_child;
356     while (defined $anode) {
357     my $ant = $anode->node_type;
358     if ($ant == 1 or $ant == 10) { # ELEMENT_NODE or DOCUMENT_TYPE_NODE
359     report Message::DOM::DOMException
360     -object => $self,
361     -type => 'HIERARCHY_REQUEST_ERR',
362     -subtype => 'CHILD_NODE_TYPE_ERR';
363     }
364     $anode = $anode->previous_sibling;
365     }
366     } # has_dt
367     }
368 wakaba 1.1
369 wakaba 1.21 for my $cn (@new_child) {
370     unless ({
371     3, (not $strict_children), # TEXT_NODE
372     5, (not $strict_children), # ENTITY_REFERENCE_NODE
373     1, 1, # ELEMENT_NODE
374     4, (not $strict_children), # CDATA_SECTION_NODE
375     7, 1, # PROCESSING_INSTRUCTION_NODE
376     8, 1, # COMMENT_NODE
377     10, 1, # DOCUMENT_TYPE_NODE
378     }->{$cn->node_type}) {
379     report Message::DOM::DOMException
380     -object => $self,
381     -type => 'HIERARCHY_REQUEST_ERR',
382     -subtype => 'CHILD_NODE_TYPE_ERR';
383     }
384     }
385 wakaba 1.1
386 wakaba 1.21 ## NOTE: Ancestor check here in |Node|.
387     }
388 wakaba 1.1
389 wakaba 1.21 ## NOTE: "Insert at" code only in insert_before and replace_child
390 wakaba 1.1
391 wakaba 1.21 ## -- Removes from parent
392     if ($new_child_parent) {
393     if (@new_child == 1) {
394     my $v = $$new_child_parent->{child_nodes};
395     RP: for my $i (0..$#$v) {
396     if ($v->[$i] eq $new_child[0]) {
397     splice @$v, $i, 1, ();
398     last RP;
399     }
400     } # RP
401     } else {
402     @{$$new_child_parent->{child_nodes}} = ();
403     }
404     }
405 wakaba 1.1
406 wakaba 1.21 ## -- Rewrite the |parentNode| properties
407     for my $nc (@new_child) {
408     $$nc->{parent_node} = $self;
409     Scalar::Util::weaken ($$nc->{parent_node});
410     }
411 wakaba 1.1
412 wakaba 1.21 ## NOTE: Depends on method:
413     push @{$$self->{child_nodes}}, @new_child;
414 wakaba 1.1
415 wakaba 1.21 ## NOTE: Only in |Document|.
416     for (@new_child) {
417     delete $$_->{implementation};
418     $$_->{owner_document} = $self;
419     Scalar::Util::weaken ($$_->{owner_document});
420     }
421 wakaba 1.1
422 wakaba 1.21 return $_[1];
423     } # apepnd_child
424 wakaba 1.1
425 wakaba 1.21 sub manakai_append_text ($$) {
426     my $self = shift;
427     if ($$self->{'http://suika.fam.cx/www/2006/dom-config/strict-document-children'}) {
428     #
429     } else {
430     local $Error::Depth = $Error::Depth + 1;
431     return $self->SUPER::manakai_append_text (@_);
432     }
433     } # manakai_append_text
434 wakaba 1.1
435 wakaba 1.21 sub insert_before ($$) {
436     ## NOTE: Overrides |Node|'s implementation.
437     my $self = $_[0];
438 wakaba 1.1
439 wakaba 1.21 ## NOTE: |$self_od| code here depending on $self->node_type.
440 wakaba 1.1
441 wakaba 1.21 ## -- Node Type check
442     my @new_child;
443     my $new_child_parent;
444     if ($_[1]->node_type == 11) { # DOCUMENT_FRAGMENT_NODE
445     push @new_child, @{$_[1]->child_nodes};
446     $new_child_parent = $_[1];
447     } else {
448     @new_child = ($_[1]);
449     $new_child_parent = $_[1]->parent_node;
450     }
451 wakaba 1.1
452 wakaba 1.21 ## NOTE: Depends on $self->node_type:
453     if ($$self->{strict_error_checking}) {
454     my $child_od = $_[1]->owner_document || $_[1]; # might be DocumentType
455     if ($self ne $child_od and $child_od->node_type != 10) {
456     report Message::DOM::DOMException # DOCUMENT_TYPE_NODE
457     -object => $self,
458     -type => 'WRONG_DOCUMENT_ERR',
459     -subtype => 'EXTERNAL_OBJECT_ERR';
460     }
461    
462     if ($$self->{manakai_read_only} or
463     (@new_child and defined $new_child_parent and
464     $$new_child_parent->{manakai_read_only})) {
465     report Message::DOM::DOMException
466     -object => $self,
467     -type => 'NO_MODIFICATION_ALLOWED_ERR',
468     -subtype => 'READ_ONLY_NODE_ERR';
469     }
470    
471     ## NOTE: Only in |Document|:
472     my $strict_children = $self->dom_config->get_parameter
473     (q<http://suika.fam.cx/www/2006/dom-config/strict-document-children>);
474     if ($strict_children) {
475     my $has_el;
476     my $has_dt;
477     my $child_nt = $_[1]->node_type;
478     if ($child_nt == 1) { # ELEMENT_NODE
479     $has_el = 1;
480     } elsif ($child_nt == 10) { # DOCUMENT_TYPE_NODE
481     $has_dt = 1;
482     } elsif ($child_nt == 11) { # DOCUMENT_FRAGMENT_NODE
483     for my $cn (@{$_[1]->child_nodes}) {
484     my $cnt = $cn->node_type;
485     if ($cnt == 1) { # ELEMENT_NODE
486     if ($has_el) {
487     report Message::DOM::DOMException
488     -object => $self,
489     -type => 'HIERARCHY_REQUEST_ERR',
490     -subtype => 'CHILD_NODE_TYPE_ERR';
491     }
492     $has_el = 1;
493     } elsif ($cnt == 10) { # DOCUMENT_TYPE_NODE
494     ## NOTE: |DocumentType| node cannot be contained in
495     ## |DocumentFragment| in strict mode.
496     if ($has_dt) {
497     report Message::DOM::DOMException
498     -object => $self,
499     -type => 'HIERARCHY_REQUEST_ERR',
500     -subtype => 'CHILD_NODE_TYPE_ERR';
501     }
502     $has_dt = 1;
503     }
504     }
505 wakaba 1.1 }
506    
507 wakaba 1.21 ## ISSUE: This code is wrong. Old manakai's implementation
508     ## is better, but it is also wrong in some edge cases.
509     ## Maybe we should remove these code entirely. DOM3Core
510     ## conformance is not important for this bit. It only makes
511     ## things too complex. Same for replace_child's code.
512     if ($has_el) {
513     my $anode = $self->last_child;
514     while (defined $anode) {
515     if ($anode->node_type == 1) { # ELEMENT_NODE
516     report Message::DOM::DOMException
517     -object => $self,
518     -type => 'HIERARCHY_REQUEST_ERR',
519     -subtype => 'CHILD_NODE_TYPE_ERR';
520 wakaba 1.1 }
521 wakaba 1.21 $anode = $anode->previous_sibling;
522 wakaba 1.1 }
523 wakaba 1.21 } # has_el
524     if ($has_dt) {
525     my $anode = $self->last_child;
526     while (defined $anode) {
527     my $ant = $anode->node_type;
528     if ($ant == 1 or $ant == 10) { # ELEMENT_NODE or DOCUMENT_TYPE_NODE
529     report Message::DOM::DOMException
530     -object => $self,
531     -type => 'HIERARCHY_REQUEST_ERR',
532     -subtype => 'CHILD_NODE_TYPE_ERR';
533     }
534     $anode = $anode->previous_sibling;
535     }
536     } # has_dt
537     }
538 wakaba 1.1
539 wakaba 1.21 for my $cn (@new_child) {
540     unless ({
541     3, (not $strict_children), # TEXT_NODE
542     5, (not $strict_children), # ENTITY_REFERENCE_NODE
543     1, 1, # ELEMENT_NODE
544     4, (not $strict_children), # CDATA_SECTION_NODE
545     7, 1, # PROCESSING_INSTRUCTION_NODE
546     8, 1, # COMMENT_NODE
547     10, 1, # DOCUMENT_TYPE_NODE
548     }->{$cn->node_type}) {
549     report Message::DOM::DOMException
550     -object => $self,
551     -type => 'HIERARCHY_REQUEST_ERR',
552     -subtype => 'CHILD_NODE_TYPE_ERR';
553     }
554     }
555 wakaba 1.1
556 wakaba 1.21 ## NOTE: Ancestor check here in |Node|.
557     }
558    
559     ## -- Insert at... ## NOTE: Only in insert_before and replace_child
560     my $index = -1; # last
561     if (defined $_[2]) {
562     ## error if $_[1] eq $_[2];
563    
564     my $cns = $self->child_nodes;
565     my $cnsl = @$cns;
566     C: {
567     $index = 0;
568     for my $i (0..($cnsl-1)) {
569     my $cn = $cns->[$i];
570     if ($cn eq $_[2]) {
571     $index += $i;
572     last C;
573     } elsif ($cn eq $_[1]) {
574     $index = -1; # offset
575     }
576     }
577 wakaba 1.1
578 wakaba 1.21 report Message::DOM::DOMException
579     -object => $self,
580     -type => 'NOT_FOUND_ERR',
581     -subtype => 'NOT_CHILD_ERR';
582     } # C
583     }
584     ## NOTE: "else" only in replace_child
585 wakaba 1.1
586 wakaba 1.21 ## -- Removes from parent
587     if ($new_child_parent) {
588     if (@new_child == 1) {
589     my $v = $$new_child_parent->{child_nodes};
590     RP: for my $i (0..$#$v) {
591     if ($v->[$i] eq $new_child[0]) {
592     splice @$v, $i, 1, ();
593     last RP;
594     }
595     } # RP
596     } else {
597     @{$$new_child_parent->{child_nodes}} = ();
598     }
599     }
600 wakaba 1.1
601 wakaba 1.21 ## -- Rewrite the |parentNode| properties
602     for my $nc (@new_child) {
603     $$nc->{parent_node} = $self;
604     Scalar::Util::weaken ($$nc->{parent_node});
605     }
606 wakaba 1.1
607 wakaba 1.21 ## NOTE: Depends on method:
608     if ($index == -1) {
609     push @{$$self->{child_nodes}}, @new_child;
610     } else {
611     splice @{$$self->{child_nodes}}, $index, 0, @new_child;
612     }
613 wakaba 1.1
614 wakaba 1.21 ## NOTE: Only in |Document|.
615     for (@new_child) {
616     delete $$_->{implementation};
617     $$_->{owner_document} = $self;
618     Scalar::Util::weaken ($$_->{owner_document});
619     }
620 wakaba 1.1
621 wakaba 1.21 return $_[1];
622     } # insert_before
623 wakaba 1.1
624 wakaba 1.21 sub replace_child ($$) {
625     ## NOTE: Overrides |Node|'s implementation.
626     my $self = $_[0];
627 wakaba 1.1
628 wakaba 1.21 ## NOTE: |$self_od| code here depending on $self->node_type.
629 wakaba 1.1
630 wakaba 1.21 ## -- Node Type check
631     my @new_child;
632     my $new_child_parent;
633     if ($_[1]->node_type == 11) { # DOCUMENT_FRAGMENT_NODE
634     push @new_child, @{$_[1]->child_nodes};
635     $new_child_parent = $_[1];
636     } else {
637     @new_child = ($_[1]);
638     $new_child_parent = $_[1]->parent_node;
639     }
640 wakaba 1.1
641 wakaba 1.21 ## NOTE: Depends on $self->node_type:
642     if ($$self->{strict_error_checking}) {
643     my $child_od = $_[1]->owner_document || $_[1]; # might be DocumentType
644     if ($self ne $child_od and $child_od->node_type != 10) {
645     report Message::DOM::DOMException # DOCUMENT_TYPE_NODE
646     -object => $self,
647     -type => 'WRONG_DOCUMENT_ERR',
648     -subtype => 'EXTERNAL_OBJECT_ERR';
649     }
650    
651     if ($$self->{manakai_read_only} or
652     (@new_child and defined $new_child_parent and
653     $$new_child_parent->{manakai_read_only})) {
654     report Message::DOM::DOMException
655     -object => $self,
656     -type => 'NO_MODIFICATION_ALLOWED_ERR',
657     -subtype => 'READ_ONLY_NODE_ERR';
658     }
659    
660     ## NOTE: Only in |Document|:
661     my $strict_children = $self->dom_config->get_parameter
662     (q<http://suika.fam.cx/www/2006/dom-config/strict-document-children>);
663     if ($strict_children) {
664     my $has_el;
665     my $has_dt;
666     my $child_nt = $_[1]->node_type;
667     if ($child_nt == 1) { # ELEMENT_NODE
668     $has_el = 1;
669     } elsif ($child_nt == 10) { # DOCUMENT_TYPE_NODE
670     $has_dt = 1;
671     } elsif ($child_nt == 11) { # DOCUMENT_FRAGMENT_NODE
672     for my $cn (@{$_[1]->child_nodes}) {
673     my $cnt = $cn->node_type;
674     if ($cnt == 1) { # ELEMENT_NODE
675     if ($has_el) {
676     report Message::DOM::DOMException
677     -object => $self,
678     -type => 'HIERARCHY_REQUEST_ERR',
679     -subtype => 'CHILD_NODE_TYPE_ERR';
680     }
681     $has_el = 1;
682     } elsif ($cnt == 10) { # DOCUMENT_TYPE_NODE
683     ## NOTE: |DocumentType| node cannot be contained in
684     ## |DocumentFragment| in strict mode.
685     if ($has_dt) {
686     report Message::DOM::DOMException
687     -object => $self,
688     -type => 'HIERARCHY_REQUEST_ERR',
689     -subtype => 'CHILD_NODE_TYPE_ERR';
690     }
691     $has_dt = 1;
692     }
693     }
694     }
695    
696     if ($has_el) {
697     my $anode = $self->last_child;
698     while (defined $anode) {
699     if ($anode->node_type == 1) { # ELEMENT_NODE
700     report Message::DOM::DOMException
701     -object => $self,
702     -type => 'HIERARCHY_REQUEST_ERR',
703     -subtype => 'CHILD_NODE_TYPE_ERR';
704     }
705     $anode = $anode->previous_sibling;
706     }
707     } # has_el
708     if ($has_dt) {
709     my $anode = $self->last_child;
710     while (defined $anode) {
711     my $ant = $anode->node_type;
712     if ($ant == 1 or $ant == 10) { # ELEMENT_NODE or DOCUMENT_TYPE_NODE
713     report Message::DOM::DOMException
714     -object => $self,
715     -type => 'HIERARCHY_REQUEST_ERR',
716     -subtype => 'CHILD_NODE_TYPE_ERR';
717     }
718     $anode = $anode->previous_sibling;
719     }
720     } # has_dt
721     }
722 wakaba 1.1
723 wakaba 1.21 for my $cn (@new_child) {
724     unless ({
725     3, (not $strict_children), # TEXT_NODE
726     5, (not $strict_children), # ENTITY_REFERENCE_NODE
727     1, 1, # ELEMENT_NODE
728     4, (not $strict_children), # CDATA_SECTION_NODE
729     7, 1, # PROCESSING_INSTRUCTION_NODE
730     8, 1, # COMMENT_NODE
731     10, 1, # DOCUMENT_TYPE_NODE
732     }->{$cn->node_type}) {
733     report Message::DOM::DOMException
734     -object => $self,
735     -type => 'HIERARCHY_REQUEST_ERR',
736     -subtype => 'CHILD_NODE_TYPE_ERR';
737     }
738     }
739 wakaba 1.1
740 wakaba 1.21 ## NOTE: Ancestor check here in |Node|.
741     }
742    
743     ## -- Insert at... ## NOTE: Only in insertBefore and replaceChild
744     my $index = -1; # last
745     if (defined $_[2]) {
746     ## error if $_[1] eq $_[2];
747    
748     my $cns = $self->child_nodes;
749     my $cnsl = @$cns;
750     C: {
751     $index = 0;
752     for my $i (0..($cnsl-1)) {
753     my $cn = $cns->[$i];
754     if ($cn eq $_[2]) {
755     $index += $i;
756     last C;
757     } elsif ($cn eq $_[1]) {
758     $index = -1; # offset
759     }
760     }
761 wakaba 1.1
762 wakaba 1.21 report Message::DOM::DOMException
763     -object => $self,
764     -type => 'NOT_FOUND_ERR',
765     -subtype => 'NOT_CHILD_ERR';
766     } # C
767     } else {
768     ## NOTE: Only in replaceChild
769     report Message::DOM::DOMException
770     -object => $self,
771     -type => 'NOT_FOUND_ERR',
772     -subtype => 'NOT_CHILD_ERR';
773     }
774 wakaba 1.1
775     ## -- Removes from parent
776 wakaba 1.21 if ($new_child_parent) {
777     if (@new_child == 1) {
778     my $v = $$new_child_parent->{child_nodes};
779 wakaba 1.1 RP: for my $i (0..$#$v) {
780 wakaba 1.13 if ($v->[$i] eq $new_child[0]) {
781 wakaba 1.1 splice @$v, $i, 1, ();
782     last RP;
783     }
784     } # RP
785 wakaba 1.21 } else {
786     @{$$new_child_parent->{child_nodes}} = ();
787 wakaba 1.1 }
788     }
789    
790     ## -- Rewrite the |parentNode| properties
791     for my $nc (@new_child) {
792 wakaba 1.21 $$nc->{parent_node} = $self;
793     Scalar::Util::weaken ($$nc->{parent_node});
794 wakaba 1.13 }
795 wakaba 1.1
796 wakaba 1.21 ## NOTE: Depends on method:
797     splice @{$$self->{child_nodes}}, $index, 1, @new_child;
798     delete ${$_[2]}->{parent_node};
799 wakaba 1.1
800 wakaba 1.21 ## NOTE: Only in |Document|.
801     for (@new_child) {
802     delete $$_->{implementation};
803     $$_->{owner_document} = $self;
804     Scalar::Util::weaken ($$_->{owner_document});
805     }
806    
807     return $_[2];
808     } # replace_child
809 wakaba 1.1
810 wakaba 1.21 ## |Document| attributes
811 wakaba 1.1
812 wakaba 1.21 ## NOTE: A manakai extension.
813     sub all_declarations_processed ($;$);
814 wakaba 1.1
815 wakaba 1.21 sub doctype ($) {
816     my $self = $_[0];
817     for (@{$self->child_nodes}) {
818     if ($_->node_type == 10) { # DOCUMENT_TYPE_NODE
819     return $_;
820     }
821     }
822     return undef;
823     } # doctype
824 wakaba 1.1
825 wakaba 1.21 sub document_element ($) {
826     my $self = shift;
827     for (@{$self->child_nodes}) {
828     if ($_->node_type == 1) { # ELEMENT_NODE
829     return $_;
830     }
831     }
832     return undef;
833     } # document_element
834 wakaba 1.1
835 wakaba 1.21 sub document_uri ($;$);
836 wakaba 1.1
837 wakaba 1.21 sub dom_config ($) {
838     require Message::DOM::DOMConfiguration;
839     return bless \\($_[0]), 'Message::DOM::DOMConfiguration';
840     } # dom_config
841 wakaba 1.1
842 wakaba 1.21 sub manakai_entity_base_uri ($;$) {
843     my $self = $_[0];
844     if (@_ > 1) {
845     if ($$self->{strict_error_checking}) {
846     if ($$self->{manakai_read_only}) {
847     report Message::DOM::DOMException
848     -object => $self,
849     -type => 'NO_MODIFICATION_ALLOWED_ERR',
850     -subtype => 'READ_ONLY_NODE_ERR';
851     }
852     }
853     if (defined $_[1]) {
854     $$self->{manakai_entity_base_uri} = ''.$_[1];
855     } else {
856     delete $$self->{manakai_entity_base_uri};
857     }
858     }
859 wakaba 1.1
860 wakaba 1.21 if (defined $$self->{manakai_entity_base_uri}) {
861     return $$self->{manakai_entity_base_uri};
862     } else {
863     return $$self->{document_uri};
864     }
865     } # manakai_entity_base_uri
866 wakaba 1.1
867 wakaba 1.21 sub input_encoding ($;$);
868 wakaba 1.1
869 wakaba 1.21 sub strict_error_checking ($;$) {
870     ## NOTE: Same as trivial boolean accessor, except no read-only checking.
871     if (@_ > 1) {
872     if ($_[1]) {
873     ${$_[0]}->{strict_error_checking} = 1;
874     } else {
875     delete ${$_[0]}->{strict_error_checking};
876     }
877     }
878     return ${$_[0]}->{strict_error_checking};
879     } # strict_error_checking
880 wakaba 1.1
881 wakaba 1.21 ## ISSUE: Setting manakai_is_html true shadows
882     ## xml_* properties. Is this desired?
883 wakaba 1.1
884 wakaba 1.21 sub xml_encoding ($;$) {
885     my $self = $_[0];
886     if (@_ > 1) {
887     ## NOTE: A manakai extension.
888     if ($$self->{strict_error_checking}) {
889     if ($$self->{manakai_is_html}) {
890     report Message::DOM::DOMException
891     -object => $self,
892     -type => 'NOT_SUPPORTED_ERR',
893     -subtype => 'NON_HTML_OPERATION_ERR';
894     }
895     if ($$self->{manakai_read_only}) {
896     report Message::DOM::DOMException
897     -object => $self,
898     -type => 'NO_MODIFICATION_ALLOWED_ERR',
899     -subtype => 'READ_ONLY_NODE_ERR';
900     }
901     }
902     if (defined $_[1]) {
903     $$self->{xml_encoding} = ''.$_[1];
904     } else {
905     delete $$self->{xml_encoding};
906     }
907     }
908    
909     if ($$self->{manakai_is_html}) {
910     return undef;
911     } else {
912     return $$self->{xml_encoding};
913     }
914     } # xml_encoding
915 wakaba 1.1
916 wakaba 1.21 sub xml_standalone ($;$) {
917     my $self = $_[0];
918     if (@_ > 1) {
919     if ($$self->{strict_error_checking}) {
920     if ($$self->{manakai_is_html}) {
921     report Message::DOM::DOMException
922     -object => $self,
923     -type => 'NOT_SUPPORTED_ERR',
924     -subtype => 'NON_HTML_OPERATION_ERR';
925     }
926     ## NOTE: Not in DOM3.
927     if ($$self->{manakai_read_only}) {
928     report Message::DOM::DOMException
929     -object => $self,
930     -type => 'NO_MODIFICATION_ALLOWED_ERR',
931     -subtype => 'READ_ONLY_NODE_ERR';
932     }
933     }
934     if ($_[1]) {
935     $$self->{xml_standalone} = 1;
936     } else {
937     delete $$self->{xml_standalone};
938     }
939     }
940    
941     if ($$self->{manakai_is_html}) {
942     return 0;
943     } else {
944     return $$self->{xml_standalone};
945     }
946     } # xml_standalone
947 wakaba 1.1
948 wakaba 1.21 sub xml_version ($;$) {
949     my $self = $_[0];
950     if (@_ > 1) {
951     my $v = ''.$_[1];
952     if ($$self->{strict_error_checking}) {
953     if ($$self->{manakai_is_html}) {
954     report Message::DOM::DOMException
955     -object => $self,
956     -type => 'NOT_SUPPORTED_ERR',
957     -subtype => 'NON_HTML_OPERATION_ERR';
958     }
959     if ($v ne '1.0' and $v ne '1.1') {
960     report Message::DOM::DOMException
961     -object => $self,
962     -type => 'NOT_SUPPORTED_ERR',
963     -subtype => 'UNKNOWN_XML_VERSION_ERR';
964     }
965     if ($$self->{manakai_read_only}) {
966     ## ISSUE: Not in DOM3.
967     report Message::DOM::DOMException
968     -object => $self,
969     -type => 'NO_MODIFICATION_ALLOWED_ERR',
970     -subtype => 'READ_ONLY_NODE_ERR';
971     }
972     }
973     $$self->{xml_version} = $v;
974     }
975    
976     if (defined wantarray) {
977     if ($$self->{manakai_is_html}) {
978     return undef;
979     } elsif (defined $$self->{xml_version}) {
980     return $$self->{xml_version};
981     } else {
982     return '1.0';
983     }
984     }
985     } # xml_version
986 wakaba 1.1
987 wakaba 1.21 ## |Document| methods
988 wakaba 1.1
989 wakaba 1.21 sub get_element_by_id ($$) {
990     local $Error::Depth = $Error::Depth + 1;
991     my @nodes = @{$_[0]->child_nodes};
992     N: while (@nodes) {
993     my $node = shift @nodes;
994     next N unless $node->node_type == 1; # ELEMENT_NODE
995     for my $attr (@{$node->attributes}) {
996     if ($attr->is_id and $attr->value eq $_[1]) {
997     return $node;
998     }
999     }
1000     unshift @nodes, @{$node->child_nodes};
1001     } # N
1002     return undef;
1003     } # get_element_by_id
1004 wakaba 1.1
1005 wakaba 1.21 ## TODO: HTML5 case normalization
1006     sub get_elements_by_tag_name ($$) {
1007     my $name = ''.$_[1];
1008     my $chk;
1009     if ($name eq '*') {
1010     $chk = sub () { 1 };
1011     } else {
1012     $chk = sub ($) {
1013     return $_[0]->manakai_tag_name eq $name;
1014     };
1015     }
1016 wakaba 1.1
1017 wakaba 1.21 require Message::DOM::NodeList;
1018     return bless \[$_[0], $chk], 'Message::DOM::NodeList::GetElementsList';
1019     } # get_elements_by_tag_name
1020 wakaba 1.1
1021 wakaba 1.21 sub get_elements_by_tag_name_ns ($$$) {
1022     my $nsuri = defined $_[1] ? ''.$_[1] : '';
1023     my $lname = ''.$_[2];
1024     my $chk;
1025     if ($nsuri eq '*') {
1026     if ($lname eq '*') {
1027     $chk = sub () { 1 };
1028     } else {
1029     $chk = sub ($) {
1030     return $_[0]->manakai_local_name eq $lname;
1031     };
1032     }
1033     } elsif ($nsuri eq '') {
1034     if ($lname eq '*') {
1035     $chk = sub ($) {
1036     return not defined $_[0]->namespace_uri;
1037     };
1038     } else {
1039     $chk = sub ($) {
1040     return (not defined $_[0]->namespace_uri and
1041     $_[0]->manakai_local_name eq $lname);
1042     };
1043     }
1044     } else {
1045     if ($lname eq '*') {
1046     $chk = sub ($) {
1047     my $ns = $_[0]->namespace_uri;
1048     return (defined $ns and $ns eq $nsuri);
1049     };
1050     } else {
1051     $chk = sub ($) {
1052     my $ns = $_[0]->namespace_uri;
1053     return (defined $ns and $ns eq $nsuri and
1054     $_[0]->manakai_local_name eq $lname);
1055     };
1056     }
1057     }
1058 wakaba 1.1
1059 wakaba 1.21 require Message::DOM::NodeList;
1060     return bless \[$_[0], $chk], 'Message::DOM::NodeList::GetElementsList';
1061     } # get_elements_by_tag_name
1062 wakaba 1.1
1063 wakaba 1.21 ## TODO: import_node
1064 wakaba 1.1
1065 wakaba 1.21 ## TODO: normalize_document
1066 wakaba 1.1
1067 wakaba 1.21 ## TODO: rename_node
1068 wakaba 1.1
1069 wakaba 1.21 ## |DocumentTraversal| methods
1070 wakaba 1.1
1071 wakaba 1.21 ## TODO: create_node_iterator
1072 wakaba 1.1
1073 wakaba 1.21 sub manakai_create_serial_walker ($$;$$$);
1074 wakaba 1.1
1075 wakaba 1.21 sub create_tree_walker ($$;$$$);
1076 wakaba 1.1
1077 wakaba 1.21 ## |HTMLDocument| attributes
1078 wakaba 1.1
1079 wakaba 1.21 sub compat_mode ($) {
1080     if (${$_[0]}->{manakai_is_html}) {
1081     if (defined ${$_[0]}->{manakai_compat_mode} and
1082     ${$_[0]}->{manakai_compat_mode} eq 'quirks') {
1083     return 'BackCompat';
1084     }
1085     }
1086     return 'CSS1Compat';
1087     } # compat_mode
1088 wakaba 1.1
1089 wakaba 1.21 sub manakai_compat_mode ($;$) {
1090     if (${$_[0]}->{manakai_is_html}) {
1091     if (@_ > 1 and defined $_[1] and
1092     {'no quirks' => 1, 'limited quirks' => 1, 'quirks' => 1}->{$_[1]}) {
1093     ${$_[0]}->{manakai_compat_mode} = $_[1];
1094     }
1095     return ${$_[0]}->{manakai_compat_mode} || 'no quirks';
1096 wakaba 1.1 } else {
1097 wakaba 1.21 return 'no quirks';
1098 wakaba 1.1 }
1099 wakaba 1.21 } # manakai_compat_mode
1100 wakaba 1.1
1101 wakaba 1.21 sub inner_html ($;$) {
1102     my $self = $_[0];
1103     local $Error::Depth = $Error::Depth + 1;
1104    
1105     if ($$self->{manakai_is_html}) {
1106     require Whatpm::HTML;
1107     if (@_ > 1) {
1108     ## Step 1
1109     ## TODO: Stop parsing and ...
1110    
1111     ## Step 2
1112     my @cn = @{$self->child_nodes};
1113     for (@cn) { ## NOTE: Might throw a |NO_MODIFICATION_ALLOWED_ERR|.
1114     $self->remove_child ($_); #
1115     }
1116 wakaba 1.1
1117 wakaba 1.21 ## Step 3, 4, 5
1118     Whatpm::HTML->parse_string ($_[1] => $self);
1119 wakaba 1.1
1120 wakaba 1.21 ## TODO:
1121     ## <script>var input = function_to_do_xmlhttprequest (location.href);
1122     ## document.innerHTML = input</script>
1123 wakaba 1.1
1124 wakaba 1.21 return unless defined wantarray;
1125     }
1126 wakaba 1.1
1127 wakaba 1.21 return ${ Whatpm::HTML->get_inner_html ($self) };
1128     } else {
1129     if (@_ > 1) {
1130     ## Step 1
1131     require Whatpm::XMLParser; # MUST
1132     my $doc = $self->implementation->create_document;
1133    
1134     ## Step 2
1135     #
1136 wakaba 1.1
1137 wakaba 1.21 ## Step 3
1138     $doc = Whatpm::XMLParser->parse_string ($_[1] => $doc); # MUST
1139 wakaba 1.1
1140 wakaba 1.21 ## Step 4
1141     #
1142 wakaba 1.1
1143 wakaba 1.21 ## Step 5
1144     ## TODO: ill-formed -> SYNTAX_ERR # MUST
1145 wakaba 1.1
1146 wakaba 1.21 ## Step 6 # MUST
1147     my @cn = @{$self->child_nodes}; ## TODO: If read-only
1148     for (@cn) {
1149     $self->remove_child ($_);
1150     }
1151 wakaba 1.1
1152 wakaba 1.21 ## Step 7, 8, 9, 10
1153     for my $node (@{$doc->child_nodes}) {
1154     $self->append_child ($self->adopt_node ($node));
1155     }
1156 wakaba 1.1
1157 wakaba 1.21 return unless defined wantarray;
1158     }
1159 wakaba 1.1
1160 wakaba 1.21 ## TODO: This serializer is currently not conformant to HTML5 spec.
1161     require Whatpm::XMLSerializer;
1162     my $r = '';
1163     for (@{$self->child_nodes}) {
1164     $r .= ${ Whatpm::XMLSerializer->get_outer_xml ($_, sub {
1165     ## TODO: INVALID_STATE_ERR
1166     }) };
1167     }
1168     return $r;
1169     }
1170     } # inner_html
1171 wakaba 1.1
1172 wakaba 1.21 sub manakai_is_html ($;$) {
1173     if (@_ > 1) {
1174     if ($_[1]) {
1175     ${$_[0]}->{manakai_is_html} = 1;
1176     } else {
1177     delete ${$_[0]}->{manakai_is_html};
1178     delete ${$_[0]}->{manakai_compat_mode};
1179     }
1180     }
1181     return ${$_[0]}->{manakai_is_html};
1182     } # manakai_is_html
1183 wakaba 1.1
1184 wakaba 1.21 package Message::IF::Document;
1185     package Message::IF::DocumentTraversal;
1186     package Message::IF::DocumentXDoctype;
1187 wakaba 1.22 package Message::IF::DocumentSelector;
1188 wakaba 1.21 package Message::IF::HTMLDocument;
1189 wakaba 1.1
1190 wakaba 1.21 package Message::DOM::DOMImplementation;
1191 wakaba 1.1
1192 wakaba 1.21 sub create_document ($;$$$) {
1193     my $r = Message::DOM::Document->____new ($_[0]);
1194 wakaba 1.1
1195 wakaba 1.21 if (defined $_[2]) {
1196     local $Error::Depth = $Error::Depth + 1;
1197     $r->append_child ($r->create_element_ns ($_[1], $_[2])); # NAMESPACE_ERR
1198     ## NOTE: manakai might raise DOMExceptions in cases not defined
1199     ## in DOM3Core spec: XMLNSPREFIX_NONXMLNSNS_ERR,
1200     ## XMLNS_NONXMLNSNS_ERR, and NONXMLNSPREFIX_XMLNSNS_ERR.
1201     } elsif (defined $_[1]) {
1202     report Message::DOM::DOMException
1203     -object => $_[0],
1204     -type => 'NAMESPACE_ERR',
1205     -subtype => 'QNAME_NULLNS_ERR';
1206     }
1207 wakaba 1.1
1208 wakaba 1.21 if (defined $_[3]) {
1209     if ($_[3]->parent_node) {
1210     report Message::DOM::DOMException
1211     -object => $_[0],
1212     -type => 'WRONG_DOCUMENT_ERR',
1213     -subtype => 'INUSE_DOCTYPE_ERR';
1214     }
1215     local $Error::Depth = $Error::Depth + 1;
1216     $r->insert_before ($_[3], $r->first_child); # EXTERNAL_OBJECT_ERR
1217     }
1218 wakaba 1.1
1219 wakaba 1.21 return $r;
1220     } # create_document
1221 wakaba 1.1
1222 wakaba 1.21 =head1 LICENSE
1223 wakaba 1.1
1224 wakaba 1.21 Copyright 2007 Wakaba <w@suika.fam.cx>
1225 wakaba 1.1
1226 wakaba 1.21 This program is free software; you can redistribute it and/or
1227     modify it under the same terms as Perl itself.
1228 wakaba 1.1
1229 wakaba 1.21 =cut
1230 wakaba 1.1
1231     1;
1232 wakaba 1.22 ## $Date: 2007/07/29 08:31:14 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24