/[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.17 - (hide annotations) (download)
Fri Nov 23 05:39:43 2007 UTC (16 years, 11 months ago) by wakaba
Branch: MAIN
Changes since 1.16: +17 -2 lines
++ ChangeLog	23 Nov 2007 05:35:10 -0000
2007-11-23  Wakaba  <wakaba@suika.fam.cx>

	* readme.en.html: Whatpm::ContentChecker now depends
	on Message::Charset::Info.

++ whatpm/t/ChangeLog	23 Nov 2007 05:38:36 -0000
2007-11-23  Wakaba  <wakaba@suika.fam.cx>

	* ContentChecker.t: Unset |input_encoding| attribute.

	* content-model-1.dat, content-model-2.dat: New tests
	for |charset| attribute value are added.

++ whatpm/Whatpm/ChangeLog	23 Nov 2007 05:37:17 -0000
2007-11-23  Wakaba  <wakaba@suika.fam.cx>

	* NanoDOM.pm (input_encoding, manakai_charset, manakai_has_bom): New
	attributes.

	* ContentChecker.pm (check_document): Warn if charset requirements
	cannot be tested.

++ whatpm/Whatpm/ContentChecker/ChangeLog	23 Nov 2007 05:37:42 -0000
2007-11-23  Wakaba  <wakaba@suika.fam.cx>

	* HTML.pm (meta): |charset| value tests implemented.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24