/[suikacvs]/markup/html/whatpm/Whatpm/NanoDOM.pm
Suika

Contents of /markup/html/whatpm/Whatpm/NanoDOM.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (hide annotations) (download)
Mon Jul 16 07:48:19 2007 UTC (17 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.13: +5 -1 lines
++ whatpm/t/ChangeLog	16 Jul 2007 07:48:16 -0000
	* content-model-1.dat, content-model-2.dat: Add "in XML:charset"
	error for test data that has |charset| in XML context.

	* content-model-2.dat: Test data for "in XML:charset", "in XML:lang",
	and "in HTML:xml:lang" are added.

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

++ whatpm/Whatpm/ChangeLog	16 Jul 2007 07:33:46 -0000
	* ContentChecker.pm: Report error if |xml:lang|
	in HTML, |lang| in XML, |xmlns| in XML, and |meta| |charset|
	in XML.

	* NanoDOM.pm (Attr.owner_document): New attribute.

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

1 wakaba 1.1 =head1 NAME
2    
3 wakaba 1.2 Whatpm::NanoDOM - A Non-Conforming Implementation of DOM Subset
4 wakaba 1.1
5     =head1 DESCRIPTION
6    
7 wakaba 1.2 The C<Whatpm::NanoDOM> module contains a non-conforming implementation
8 wakaba 1.1 of a subset of DOM. It is the intention that this module is
9 wakaba 1.2 used only for the purpose of testing the C<Whatpm::HTML> module.
10 wakaba 1.1
11     See source code if you would like to know what it does.
12    
13     =cut
14    
15 wakaba 1.2 package Whatpm::NanoDOM;
16 wakaba 1.1 use strict;
17    
18 wakaba 1.3 require Scalar::Util;
19    
20     package Whatpm::NanoDOM::DOMImplementation;
21    
22     sub create_document ($) {
23     return Whatpm::NanoDOM::Document->new;
24     } # create_document
25    
26 wakaba 1.2 package Whatpm::NanoDOM::Node;
27 wakaba 1.1
28     sub new ($) {
29     my $class = shift;
30     my $self = bless {}, $class;
31     return $self;
32     } # new
33    
34     sub parent_node ($) {
35     return shift->{parent_node};
36     } # parent_node
37    
38 wakaba 1.4 sub manakai_parent_element ($) {
39     my $self = shift;
40     my $parent = $self->{parent_node};
41     while (defined $parent) {
42     if ($parent->node_type == 1) {
43     return $parent;
44     } else {
45     $parent = $parent->{parent_node};
46     }
47     }
48     return undef;
49     } # manakai_parent_element
50    
51 wakaba 1.1 sub child_nodes ($) {
52 wakaba 1.7 return shift->{child_nodes} || [];
53 wakaba 1.1 } # child_nodes
54    
55     ## NOTE: Only applied to Elements and Documents
56     sub append_child ($$) {
57     my ($self, $new_child) = @_;
58     if (defined $new_child->{parent_node}) {
59     my $parent_list = $new_child->{parent_node}->{child_nodes};
60     for (0..$#$parent_list) {
61     if ($parent_list->[$_] eq $new_child) {
62     splice @$parent_list, $_, 1;
63     }
64     }
65     }
66     push @{$self->{child_nodes}}, $new_child;
67 wakaba 1.3 $new_child->{parent_node} = $self;
68     Scalar::Util::weaken ($new_child->{parent_node});
69 wakaba 1.1 return $new_child;
70     } # append_child
71    
72     ## NOTE: Only applied to Elements and Documents
73     sub insert_before ($$;$) {
74     my ($self, $new_child, $ref_child) = @_;
75     if (defined $new_child->{parent_node}) {
76     my $parent_list = $new_child->{parent_node}->{child_nodes};
77     for (0..$#$parent_list) {
78     if ($parent_list->[$_] eq $new_child) {
79     splice @$parent_list, $_, 1;
80     }
81     }
82     }
83     my $i = @{$self->{child_nodes}};
84     if (defined $ref_child) {
85     for (0..$#{$self->{child_nodes}}) {
86     if ($self->{child_nodes}->[$_] eq $ref_child) {
87     $i = $_;
88     last;
89     }
90     }
91     }
92     splice @{$self->{child_nodes}}, $i, 0, $new_child;
93 wakaba 1.5 $new_child->{parent_node} = $self;
94     Scalar::Util::weaken ($new_child->{parent_node});
95 wakaba 1.1 return $new_child;
96     } # insert_before
97    
98     ## NOTE: Only applied to Elements and Documents
99     sub remove_child ($$) {
100     my ($self, $old_child) = @_;
101     my $parent_list = $self->{child_nodes};
102     for (0..$#$parent_list) {
103     if ($parent_list->[$_] eq $old_child) {
104     splice @$parent_list, $_, 1;
105     }
106     }
107     delete $old_child->{parent_node};
108     return $old_child;
109     } # remove_child
110    
111     ## NOTE: Only applied to Elements and Documents
112     sub has_child_nodes ($) {
113     return @{shift->{child_nodes}} > 0;
114     } # has_child_nodes
115    
116     ## NOTE: Only applied to Elements and Documents
117 wakaba 1.8 sub first_child ($) {
118     my $self = shift;
119     return $self->{child_nodes}->[0];
120     } # first_child
121    
122     ## NOTE: Only applied to Elements and Documents
123 wakaba 1.1 sub last_child ($) {
124     my $self = shift;
125     return @{$self->{child_nodes}} ? $self->{child_nodes}->[-1] : undef;
126     } # last_child
127    
128     ## NOTE: Only applied to Elements and Documents
129     sub previous_sibling ($) {
130     my $self = shift;
131     my $parent = $self->{parent_node};
132     return undef unless defined $parent;
133     my $r;
134     for (@{$parent->{child_nodes}}) {
135     if ($_ eq $self) {
136     return $r;
137     } else {
138     $r = $_;
139     }
140     }
141     return undef;
142     } # previous_sibling
143    
144 wakaba 1.6 sub prefix ($;$) {
145     my $self = shift;
146     if (@_) {
147     $self->{prefix} = shift;
148     }
149     return $self->{prefix};
150     } # prefix
151    
152 wakaba 1.1 sub ELEMENT_NODE () { 1 }
153     sub ATTRIBUTE_NODE () { 2 }
154     sub TEXT_NODE () { 3 }
155     sub CDATA_SECTION_NODE () { 4 }
156     sub ENTITY_REFERENCE_NODE () { 5 }
157     sub ENTITY_NODE () { 6 }
158     sub PROCESSING_INSTRUCTION_NODE () { 7 }
159     sub COMMENT_NODE () { 8 }
160     sub DOCUMENT_NODE () { 9 }
161     sub DOCUMENT_TYPE_NODE () { 10 }
162     sub DOCUMENT_FRAGMENT_NODE () { 11 }
163     sub NOTATION_NODE () { 12 }
164    
165 wakaba 1.2 package Whatpm::NanoDOM::Document;
166     push our @ISA, 'Whatpm::NanoDOM::Node';
167 wakaba 1.1
168     sub new ($) {
169     my $self = shift->SUPER::new;
170     $self->{child_nodes} = [];
171     return $self;
172     } # new
173    
174     ## A manakai extension
175     sub manakai_append_text ($$) {
176     my $self = shift;
177     if (@{$self->{child_nodes}} and
178     $self->{child_nodes}->[-1]->node_type == 3) {
179     $self->{child_nodes}->[-1]->manakai_append_text (shift);
180     } else {
181     my $text = $self->create_text_node (shift);
182     $self->append_child ($text);
183     }
184     } # manakai_append_text
185    
186     sub node_type () { 9 }
187    
188     sub strict_error_checking {
189     return 0;
190     } # strict_error_checking
191    
192     sub create_text_node ($$) {
193     shift;
194 wakaba 1.2 return Whatpm::NanoDOM::Text->new (shift);
195 wakaba 1.1 } # create_text_node
196    
197     sub create_comment ($$) {
198     shift;
199 wakaba 1.2 return Whatpm::NanoDOM::Comment->new (shift);
200 wakaba 1.1 } # create_comment
201    
202     ## The second parameter only supports manakai extended way
203     ## to specify qualified name - "[$prefix, $local_name]"
204     sub create_element_ns ($$$) {
205     my ($self, $nsuri, $qn) = @_;
206 wakaba 1.3 return Whatpm::NanoDOM::Element->new ($self, $nsuri, $qn->[0], $qn->[1]);
207 wakaba 1.1 } # create_element_ns
208    
209     ## A manakai extension
210     sub create_document_type_definition ($$) {
211     shift;
212 wakaba 1.2 return Whatpm::NanoDOM::DocumentType->new (shift);
213 wakaba 1.1 } # create_document_type_definition
214    
215 wakaba 1.3 sub implementation ($) {
216     return 'Whatpm::NanoDOM::DOMImplementation';
217     } # implementation
218    
219 wakaba 1.4 sub document_element ($) {
220     my $self = shift;
221     for (@{$self->child_nodes}) {
222     if ($_->node_type == 1) {
223     return $_;
224     }
225     }
226     return undef;
227     } # document_element
228    
229 wakaba 1.12 sub adopt_node ($$) {
230 wakaba 1.11 my @node = ($_[1]);
231     while (@node) {
232     my $node = shift @node;
233     $node->{owner_document} = $_[0];
234     Scalar::Util::weaken ($node->{owner_document});
235     push @node, @{$node->child_nodes};
236     push @node, @{$node->attributes or []} if $node->can ('attributes');
237     }
238     return $_[1];
239     } # adopt_node
240    
241 wakaba 1.12 sub manakai_is_html ($;$) {
242     if (@_ > 1) {
243     if ($_[1]) {
244     $_[0]->{manakai_is_html} = 1;
245     } else {
246 wakaba 1.13 delete $_[0]->{manakai_is_html};
247 wakaba 1.12 delete $_[0]->{manakai_compat_mode};
248     }
249     }
250     return $_[0]->{manakai_is_html};
251     } # manakai_is_html
252    
253     sub compat_mode ($) {
254     if ($_[0]->{manakai_is_html}) {
255     if ($_[0]->{manakai_compat_mode} eq 'quirks') {
256     return 'BackCompat';
257     }
258     }
259     return 'CSS1Compat';
260     } # compat_mode
261    
262     sub manakai_compat_mode ($;$) {
263     if ($_[0]->{manakai_is_html}) {
264     if (@_ > 1 and defined $_[1] and
265     {'no quirks' => 1, 'limited quirks' => 1, 'quirks' => 1}->{$_[1]}) {
266     $_[0]->{manakai_compat_mode} = $_[1];
267     }
268     return $_[0]->{manakai_compat_mode} || 'no quirks';
269     } else {
270     return 'no quirks';
271     }
272     } # manakai_compat_mode
273    
274 wakaba 1.2 package Whatpm::NanoDOM::Element;
275     push our @ISA, 'Whatpm::NanoDOM::Node';
276 wakaba 1.1
277 wakaba 1.3 sub new ($$$$$) {
278 wakaba 1.1 my $self = shift->SUPER::new;
279 wakaba 1.3 $self->{owner_document} = shift;
280     Scalar::Util::weaken ($self->{owner_document});
281 wakaba 1.1 $self->{namespace_uri} = shift;
282     $self->{prefix} = shift;
283     $self->{local_name} = shift;
284     $self->{attributes} = {};
285     $self->{child_nodes} = [];
286     return $self;
287     } # new
288    
289 wakaba 1.3 sub owner_document ($) {
290     return shift->{owner_document};
291     } # owner_document
292    
293 wakaba 1.1 sub clone_node ($$) {
294     my ($self, $deep) = @_; ## NOTE: Deep cloning is not supported
295     my $clone = bless {
296     namespace_uri => $self->{namespace_uri},
297     prefix => $self->{prefix},
298     local_name => $self->{local_name},
299     child_nodes => [],
300     }, ref $self;
301     for my $ns (keys %{$self->{attributes}}) {
302     for my $ln (keys %{$self->{attributes}->{$ns}}) {
303     my $attr = $self->{attributes}->{$ns}->{$ln};
304     $clone->{attributes}->{$ns}->{$ln} = bless {
305     namespace_uri => $attr->{namespace_uri},
306     prefix => $attr->{prefix},
307     local_name => $attr->{local_name},
308     value => $attr->{value},
309     }, ref $self->{attributes}->{$ns}->{$ln};
310     }
311     }
312     return $clone;
313     } # clone
314    
315     ## A manakai extension
316     sub manakai_append_text ($$) {
317     my $self = shift;
318     if (@{$self->{child_nodes}} and
319     $self->{child_nodes}->[-1]->node_type == 3) {
320     $self->{child_nodes}->[-1]->manakai_append_text (shift);
321     } else {
322 wakaba 1.2 my $text = Whatpm::NanoDOM::Text->new (shift);
323 wakaba 1.1 $self->append_child ($text);
324     }
325     } # manakai_append_text
326    
327 wakaba 1.7 sub text_content ($) {
328     my $self = shift;
329     my $r = '';
330     for my $child (@{$self->child_nodes}) {
331     if ($child->can ('data')) {
332     $r .= $child->data;
333     } else {
334     $r .= $child->text_content;
335     }
336     }
337     return $r;
338     } # text_content
339    
340 wakaba 1.1 sub attributes ($) {
341     my $self = shift;
342     my $r = [];
343     ## Order MUST be stable
344     for my $ns (sort {$a cmp $b} keys %{$self->{attributes}}) {
345     for my $ln (sort {$a cmp $b} keys %{$self->{attributes}->{$ns}}) {
346     push @$r, $self->{attributes}->{$ns}->{$ln}
347     if defined $self->{attributes}->{$ns}->{$ln};
348     }
349     }
350     return $r;
351     } # attributes
352    
353 wakaba 1.3 sub local_name ($) { # TODO: HTML5 case
354     return shift->{local_name};
355     } # local_name
356    
357 wakaba 1.4 sub manakai_local_name ($) {
358     return shift->{local_name}; # no case fixing for HTML5
359     } # manakai_local_name
360    
361 wakaba 1.3 sub namespace_uri ($) {
362     return shift->{namespace_uri};
363     } # namespace_uri
364    
365 wakaba 1.4 sub manakai_element_type_match ($$$) {
366     my ($self, $nsuri, $ln) = @_;
367     if (defined $nsuri) {
368     if (defined $self->{namespace_uri} and $nsuri eq $self->{namespace_uri}) {
369     return ($ln eq $self->{local_name});
370     } else {
371     return 0;
372     }
373     } else {
374     if (not defined $self->{namespace_uri}) {
375     return ($ln eq $self->{local_name});
376     } else {
377     return 0;
378     }
379     }
380     } # manakai_element_type_match
381    
382 wakaba 1.1 sub node_type { 1 }
383    
384     ## TODO: HTML5 capitalization
385     sub tag_name ($) {
386     my $self = shift;
387     if (defined $self->{prefix}) {
388     return $self->{prefix} . ':' . $self->{local_name};
389     } else {
390     return $self->{local_name};
391     }
392     } # tag_name
393    
394 wakaba 1.8 sub get_attribute_ns ($$$) {
395     my ($self, $nsuri, $ln) = @_;
396     $nsuri = '' unless defined $nsuri;
397     return defined $self->{attributes}->{$nsuri}->{$ln}
398     ? $self->{attributes}->{$nsuri}->{$ln}->value : undef;
399     } # get_attribute_ns
400    
401 wakaba 1.9 sub get_attribute_node_ns ($$$) {
402     my ($self, $nsuri, $ln) = @_;
403     $nsuri = '' unless defined $nsuri;
404     return $self->{attributes}->{$nsuri}->{$ln};
405     } # get_attribute_node_ns
406    
407 wakaba 1.1 sub has_attribute_ns ($$$) {
408     my ($self, $nsuri, $ln) = @_;
409 wakaba 1.8 $nsuri = '' unless defined $nsuri;
410 wakaba 1.1 return defined $self->{attributes}->{$nsuri}->{$ln};
411     } # has_attribute_ns
412    
413     ## The second parameter only supports manakai extended way
414     ## to specify qualified name - "[$prefix, $local_name]"
415     sub set_attribute_ns ($$$$) {
416     my ($self, $nsuri, $qn, $value) = @_;
417     $self->{attributes}->{$nsuri}->{$qn->[1]}
418 wakaba 1.5 = Whatpm::NanoDOM::Attr->new ($self, $nsuri, $qn->[0], $qn->[1], $value);
419 wakaba 1.1 } # set_attribute_ns
420    
421 wakaba 1.2 package Whatpm::NanoDOM::Attr;
422     push our @ISA, 'Whatpm::NanoDOM::Node';
423 wakaba 1.1
424 wakaba 1.5 sub new ($$$$$$) {
425 wakaba 1.1 my $self = shift->SUPER::new;
426 wakaba 1.5 $self->{owner_element} = shift;
427     Scalar::Util::weaken ($self->{owner_element});
428 wakaba 1.1 $self->{namespace_uri} = shift;
429     $self->{prefix} = shift;
430     $self->{local_name} = shift;
431     $self->{value} = shift;
432     return $self;
433     } # new
434    
435 wakaba 1.5 sub namespace_uri ($) {
436     return shift->{namespace_uri};
437     } # namespace_uri
438    
439     sub manakai_local_name ($) {
440     return shift->{local_name};
441     } # manakai_local_name
442    
443 wakaba 1.1 sub node_type { 2 }
444    
445 wakaba 1.14 sub owner_document ($) {
446     return shift->owner_element->owner_document;
447     } # owner_document
448    
449 wakaba 1.1 ## TODO: HTML5 case stuff?
450     sub name ($) {
451     my $self = shift;
452     if (defined $self->{prefix}) {
453     return $self->{prefix} . ':' . $self->{local_name};
454     } else {
455     return $self->{local_name};
456     }
457     } # name
458    
459     sub value ($) {
460     return shift->{value};
461     } # value
462    
463 wakaba 1.5 sub owner_element ($) {
464     return shift->{owner_element};
465     } # owner_element
466    
467 wakaba 1.2 package Whatpm::NanoDOM::CharacterData;
468     push our @ISA, 'Whatpm::NanoDOM::Node';
469 wakaba 1.1
470     sub new ($$) {
471     my $self = shift->SUPER::new;
472     $self->{data} = shift;
473     return $self;
474     } # new
475    
476     ## A manakai extension
477     sub manakai_append_text ($$) {
478     my ($self, $s) = @_;
479     $self->{data} .= $s;
480     } # manakai_append_text
481    
482     sub data ($) {
483     return shift->{data};
484     } # data
485    
486 wakaba 1.2 package Whatpm::NanoDOM::Text;
487     push our @ISA, 'Whatpm::NanoDOM::CharacterData';
488 wakaba 1.1
489     sub node_type () { 3 }
490    
491 wakaba 1.2 package Whatpm::NanoDOM::Comment;
492     push our @ISA, 'Whatpm::NanoDOM::CharacterData';
493 wakaba 1.1
494     sub node_type () { 8 }
495    
496 wakaba 1.2 package Whatpm::NanoDOM::DocumentType;
497     push our @ISA, 'Whatpm::NanoDOM::Node';
498 wakaba 1.1
499     sub new ($$) {
500     my $self = shift->SUPER::new;
501     $self->{name} = shift;
502     return $self;
503     } # new
504    
505     sub node_type () { 10 }
506    
507     sub name ($) {
508     return shift->{name};
509     } # name
510    
511     =head1 SEE ALSO
512    
513 wakaba 1.2 L<Whatpm::HTML>
514 wakaba 1.1
515     =head1 AUTHOR
516    
517     Wakaba <w@suika.fam.cx>.
518    
519     =head1 LICENSE
520    
521     Copyright 2007 Wakaba <w@suika.fam.cx>
522    
523     This library is free software; you can redistribute it
524     and/or modify it under the same terms as Perl itself.
525    
526     =cut
527    
528     1;
529 wakaba 1.14 # $Date: 2007/06/23 13:05:16 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24