/[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.18 - (hide annotations) (download)
Fri Nov 23 07:35:03 2007 UTC (18 years, 2 months ago) by wakaba
Branch: MAIN
Changes since 1.17: +10 -2 lines
++ ChangeLog	23 Nov 2007 07:29:08 -0000
	* readme.en.html: Link to user data names documentation
	is added.

2007-11-23  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/t/ChangeLog	23 Nov 2007 07:08:15 -0000
	* content-model-2.dat: New test data for character references
	in |charset| attribute values.

2007-11-23  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ChangeLog	23 Nov 2007 07:09:44 -0000
	* NanoDOM.pm (get_user_data, set_user_data): New methods.

	* HTML.pm.src: A flag for character references in attribute
	values are added.  Set |manakai_has_reference| user data
	to |charset| attribute.

2007-11-23  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ContentChecker/ChangeLog	23 Nov 2007 07:08:45 -0000
	* HTML.pm (meta): Character references in |charset| attribute
	values are now erred.

2007-11-23  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 wakaba 1.18 our $VERSION=do{my @r=(q$Revision: 1.17 $=~/\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.18 sub get_user_data ($$) {
154     return $_[0]->{$_[1]};
155     } # get_user_data
156    
157     sub set_user_data ($$;$$) {
158     $_[0]->{$_[1]} = $_[2];
159     } # set_user_data
160    
161 wakaba 1.1 sub ELEMENT_NODE () { 1 }
162     sub ATTRIBUTE_NODE () { 2 }
163     sub TEXT_NODE () { 3 }
164     sub CDATA_SECTION_NODE () { 4 }
165     sub ENTITY_REFERENCE_NODE () { 5 }
166     sub ENTITY_NODE () { 6 }
167     sub PROCESSING_INSTRUCTION_NODE () { 7 }
168     sub COMMENT_NODE () { 8 }
169     sub DOCUMENT_NODE () { 9 }
170     sub DOCUMENT_TYPE_NODE () { 10 }
171     sub DOCUMENT_FRAGMENT_NODE () { 11 }
172     sub NOTATION_NODE () { 12 }
173    
174 wakaba 1.2 package Whatpm::NanoDOM::Document;
175     push our @ISA, 'Whatpm::NanoDOM::Node';
176 wakaba 1.1
177     sub new ($) {
178     my $self = shift->SUPER::new;
179     $self->{child_nodes} = [];
180     return $self;
181     } # new
182    
183     ## A manakai extension
184     sub manakai_append_text ($$) {
185     my $self = shift;
186     if (@{$self->{child_nodes}} and
187     $self->{child_nodes}->[-1]->node_type == 3) {
188     $self->{child_nodes}->[-1]->manakai_append_text (shift);
189     } else {
190     my $text = $self->create_text_node (shift);
191     $self->append_child ($text);
192     }
193     } # manakai_append_text
194    
195     sub node_type () { 9 }
196    
197     sub strict_error_checking {
198     return 0;
199     } # strict_error_checking
200    
201     sub create_text_node ($$) {
202     shift;
203 wakaba 1.2 return Whatpm::NanoDOM::Text->new (shift);
204 wakaba 1.1 } # create_text_node
205    
206     sub create_comment ($$) {
207     shift;
208 wakaba 1.2 return Whatpm::NanoDOM::Comment->new (shift);
209 wakaba 1.1 } # create_comment
210    
211     ## The second parameter only supports manakai extended way
212     ## to specify qualified name - "[$prefix, $local_name]"
213     sub create_element_ns ($$$) {
214     my ($self, $nsuri, $qn) = @_;
215 wakaba 1.3 return Whatpm::NanoDOM::Element->new ($self, $nsuri, $qn->[0], $qn->[1]);
216 wakaba 1.1 } # create_element_ns
217    
218     ## A manakai extension
219     sub create_document_type_definition ($$) {
220     shift;
221 wakaba 1.2 return Whatpm::NanoDOM::DocumentType->new (shift);
222 wakaba 1.1 } # create_document_type_definition
223    
224 wakaba 1.3 sub implementation ($) {
225     return 'Whatpm::NanoDOM::DOMImplementation';
226     } # implementation
227    
228 wakaba 1.4 sub document_element ($) {
229     my $self = shift;
230     for (@{$self->child_nodes}) {
231     if ($_->node_type == 1) {
232     return $_;
233     }
234     }
235     return undef;
236     } # document_element
237    
238 wakaba 1.12 sub adopt_node ($$) {
239 wakaba 1.11 my @node = ($_[1]);
240     while (@node) {
241     my $node = shift @node;
242     $node->{owner_document} = $_[0];
243     Scalar::Util::weaken ($node->{owner_document});
244     push @node, @{$node->child_nodes};
245     push @node, @{$node->attributes or []} if $node->can ('attributes');
246     }
247     return $_[1];
248     } # adopt_node
249    
250 wakaba 1.12 sub manakai_is_html ($;$) {
251     if (@_ > 1) {
252     if ($_[1]) {
253     $_[0]->{manakai_is_html} = 1;
254     } else {
255 wakaba 1.13 delete $_[0]->{manakai_is_html};
256 wakaba 1.12 delete $_[0]->{manakai_compat_mode};
257     }
258     }
259     return $_[0]->{manakai_is_html};
260     } # manakai_is_html
261    
262     sub compat_mode ($) {
263     if ($_[0]->{manakai_is_html}) {
264     if ($_[0]->{manakai_compat_mode} eq 'quirks') {
265     return 'BackCompat';
266     }
267     }
268     return 'CSS1Compat';
269     } # compat_mode
270    
271     sub manakai_compat_mode ($;$) {
272     if ($_[0]->{manakai_is_html}) {
273     if (@_ > 1 and defined $_[1] and
274     {'no quirks' => 1, 'limited quirks' => 1, 'quirks' => 1}->{$_[1]}) {
275     $_[0]->{manakai_compat_mode} = $_[1];
276     }
277     return $_[0]->{manakai_compat_mode} || 'no quirks';
278     } else {
279     return 'no quirks';
280     }
281     } # manakai_compat_mode
282    
283 wakaba 1.17 sub input_encoding ($;$) {
284     $_[0]->{input_encoding} = $_[1] if @_ > 1;
285     return $_[0]->{input_encoding};
286     }
287    
288     sub manakai_charset ($;$) {
289     $_[0]->{manakai_charset} = $_[1] if @_ > 1;
290     return $_[0]->{manakai_charset};
291     }
292    
293     sub manakai_has_bom ($;$) {
294     $_[0]->{manakai_has_bom} = $_[1] if @_ > 1;
295     return $_[0]->{manakai_has_bom};
296     }
297    
298 wakaba 1.2 package Whatpm::NanoDOM::Element;
299     push our @ISA, 'Whatpm::NanoDOM::Node';
300 wakaba 1.1
301 wakaba 1.3 sub new ($$$$$) {
302 wakaba 1.1 my $self = shift->SUPER::new;
303 wakaba 1.3 $self->{owner_document} = shift;
304     Scalar::Util::weaken ($self->{owner_document});
305 wakaba 1.1 $self->{namespace_uri} = shift;
306     $self->{prefix} = shift;
307     $self->{local_name} = shift;
308     $self->{attributes} = {};
309     $self->{child_nodes} = [];
310     return $self;
311     } # new
312    
313 wakaba 1.3 sub owner_document ($) {
314     return shift->{owner_document};
315     } # owner_document
316    
317 wakaba 1.1 sub clone_node ($$) {
318     my ($self, $deep) = @_; ## NOTE: Deep cloning is not supported
319     my $clone = bless {
320     namespace_uri => $self->{namespace_uri},
321     prefix => $self->{prefix},
322     local_name => $self->{local_name},
323     child_nodes => [],
324     }, ref $self;
325     for my $ns (keys %{$self->{attributes}}) {
326     for my $ln (keys %{$self->{attributes}->{$ns}}) {
327     my $attr = $self->{attributes}->{$ns}->{$ln};
328     $clone->{attributes}->{$ns}->{$ln} = bless {
329     namespace_uri => $attr->{namespace_uri},
330     prefix => $attr->{prefix},
331     local_name => $attr->{local_name},
332     value => $attr->{value},
333     }, ref $self->{attributes}->{$ns}->{$ln};
334     }
335     }
336     return $clone;
337     } # clone
338    
339     ## A manakai extension
340     sub manakai_append_text ($$) {
341     my $self = shift;
342     if (@{$self->{child_nodes}} and
343     $self->{child_nodes}->[-1]->node_type == 3) {
344     $self->{child_nodes}->[-1]->manakai_append_text (shift);
345     } else {
346 wakaba 1.2 my $text = Whatpm::NanoDOM::Text->new (shift);
347 wakaba 1.1 $self->append_child ($text);
348     }
349     } # manakai_append_text
350    
351 wakaba 1.7 sub text_content ($) {
352     my $self = shift;
353     my $r = '';
354     for my $child (@{$self->child_nodes}) {
355     if ($child->can ('data')) {
356     $r .= $child->data;
357     } else {
358     $r .= $child->text_content;
359     }
360     }
361     return $r;
362     } # text_content
363    
364 wakaba 1.1 sub attributes ($) {
365     my $self = shift;
366     my $r = [];
367     ## Order MUST be stable
368     for my $ns (sort {$a cmp $b} keys %{$self->{attributes}}) {
369     for my $ln (sort {$a cmp $b} keys %{$self->{attributes}->{$ns}}) {
370     push @$r, $self->{attributes}->{$ns}->{$ln}
371     if defined $self->{attributes}->{$ns}->{$ln};
372     }
373     }
374     return $r;
375     } # attributes
376    
377 wakaba 1.3 sub local_name ($) { # TODO: HTML5 case
378     return shift->{local_name};
379     } # local_name
380    
381 wakaba 1.4 sub manakai_local_name ($) {
382     return shift->{local_name}; # no case fixing for HTML5
383     } # manakai_local_name
384    
385 wakaba 1.3 sub namespace_uri ($) {
386     return shift->{namespace_uri};
387     } # namespace_uri
388    
389 wakaba 1.4 sub manakai_element_type_match ($$$) {
390     my ($self, $nsuri, $ln) = @_;
391     if (defined $nsuri) {
392     if (defined $self->{namespace_uri} and $nsuri eq $self->{namespace_uri}) {
393     return ($ln eq $self->{local_name});
394     } else {
395     return 0;
396     }
397     } else {
398     if (not defined $self->{namespace_uri}) {
399     return ($ln eq $self->{local_name});
400     } else {
401     return 0;
402     }
403     }
404     } # manakai_element_type_match
405    
406 wakaba 1.1 sub node_type { 1 }
407    
408     ## TODO: HTML5 capitalization
409     sub tag_name ($) {
410     my $self = shift;
411     if (defined $self->{prefix}) {
412     return $self->{prefix} . ':' . $self->{local_name};
413     } else {
414     return $self->{local_name};
415     }
416     } # tag_name
417    
418 wakaba 1.8 sub get_attribute_ns ($$$) {
419     my ($self, $nsuri, $ln) = @_;
420     $nsuri = '' unless defined $nsuri;
421     return defined $self->{attributes}->{$nsuri}->{$ln}
422     ? $self->{attributes}->{$nsuri}->{$ln}->value : undef;
423     } # get_attribute_ns
424    
425 wakaba 1.9 sub get_attribute_node_ns ($$$) {
426     my ($self, $nsuri, $ln) = @_;
427     $nsuri = '' unless defined $nsuri;
428     return $self->{attributes}->{$nsuri}->{$ln};
429     } # get_attribute_node_ns
430    
431 wakaba 1.1 sub has_attribute_ns ($$$) {
432     my ($self, $nsuri, $ln) = @_;
433 wakaba 1.8 $nsuri = '' unless defined $nsuri;
434 wakaba 1.1 return defined $self->{attributes}->{$nsuri}->{$ln};
435     } # has_attribute_ns
436    
437     ## The second parameter only supports manakai extended way
438     ## to specify qualified name - "[$prefix, $local_name]"
439     sub set_attribute_ns ($$$$) {
440     my ($self, $nsuri, $qn, $value) = @_;
441     $self->{attributes}->{$nsuri}->{$qn->[1]}
442 wakaba 1.5 = Whatpm::NanoDOM::Attr->new ($self, $nsuri, $qn->[0], $qn->[1], $value);
443 wakaba 1.1 } # set_attribute_ns
444    
445 wakaba 1.2 package Whatpm::NanoDOM::Attr;
446     push our @ISA, 'Whatpm::NanoDOM::Node';
447 wakaba 1.1
448 wakaba 1.5 sub new ($$$$$$) {
449 wakaba 1.1 my $self = shift->SUPER::new;
450 wakaba 1.5 $self->{owner_element} = shift;
451     Scalar::Util::weaken ($self->{owner_element});
452 wakaba 1.1 $self->{namespace_uri} = shift;
453     $self->{prefix} = shift;
454     $self->{local_name} = shift;
455     $self->{value} = shift;
456     return $self;
457     } # new
458    
459 wakaba 1.5 sub namespace_uri ($) {
460     return shift->{namespace_uri};
461     } # namespace_uri
462    
463     sub manakai_local_name ($) {
464     return shift->{local_name};
465     } # manakai_local_name
466    
467 wakaba 1.1 sub node_type { 2 }
468    
469 wakaba 1.14 sub owner_document ($) {
470     return shift->owner_element->owner_document;
471     } # owner_document
472    
473 wakaba 1.1 ## TODO: HTML5 case stuff?
474     sub name ($) {
475     my $self = shift;
476     if (defined $self->{prefix}) {
477     return $self->{prefix} . ':' . $self->{local_name};
478     } else {
479     return $self->{local_name};
480     }
481     } # name
482    
483     sub value ($) {
484     return shift->{value};
485     } # value
486    
487 wakaba 1.5 sub owner_element ($) {
488     return shift->{owner_element};
489     } # owner_element
490    
491 wakaba 1.2 package Whatpm::NanoDOM::CharacterData;
492     push our @ISA, 'Whatpm::NanoDOM::Node';
493 wakaba 1.1
494     sub new ($$) {
495     my $self = shift->SUPER::new;
496     $self->{data} = shift;
497     return $self;
498     } # new
499    
500     ## A manakai extension
501     sub manakai_append_text ($$) {
502     my ($self, $s) = @_;
503     $self->{data} .= $s;
504     } # manakai_append_text
505    
506     sub data ($) {
507     return shift->{data};
508     } # data
509    
510 wakaba 1.2 package Whatpm::NanoDOM::Text;
511     push our @ISA, 'Whatpm::NanoDOM::CharacterData';
512 wakaba 1.1
513     sub node_type () { 3 }
514    
515 wakaba 1.2 package Whatpm::NanoDOM::Comment;
516     push our @ISA, 'Whatpm::NanoDOM::CharacterData';
517 wakaba 1.1
518     sub node_type () { 8 }
519    
520 wakaba 1.2 package Whatpm::NanoDOM::DocumentType;
521     push our @ISA, 'Whatpm::NanoDOM::Node';
522 wakaba 1.1
523     sub new ($$) {
524     my $self = shift->SUPER::new;
525     $self->{name} = shift;
526     return $self;
527     } # new
528    
529     sub node_type () { 10 }
530    
531     sub name ($) {
532     return shift->{name};
533     } # name
534    
535 wakaba 1.16 sub public_id ($;$) {
536     $_[0]->{public_id} = $_[1] if @_ > 1;
537     return $_[0]->{public_id};
538     } # public_id
539    
540     sub system_id ($;$) {
541     $_[0]->{system_id} = $_[1] if @_ > 1;
542     return $_[0]->{system_id};
543     } # system_id
544    
545 wakaba 1.1 =head1 SEE ALSO
546    
547 wakaba 1.2 L<Whatpm::HTML>
548 wakaba 1.1
549     =head1 AUTHOR
550    
551     Wakaba <w@suika.fam.cx>.
552    
553     =head1 LICENSE
554    
555     Copyright 2007 Wakaba <w@suika.fam.cx>
556    
557     This library is free software; you can redistribute it
558     and/or modify it under the same terms as Perl itself.
559    
560     =cut
561    
562     1;
563 wakaba 1.18 # $Date: 2007/11/23 05:39:43 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24