/[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.9 - (hide annotations) (download)
Tue Jun 5 00:56:42 2007 UTC (17 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.8: +7 -1 lines
++ whatpm/t/ChangeLog	5 Jun 2007 00:48:32 -0000
2007-06-05  Wakaba  <wakaba@suika.fam.cx>

	* content-model-2.dat: |script| |async| and |defer|
	no longer require |src|.  |async| MUST NOT be
	specified if |defer|.  (HTML5 revision 858).

++ whatpm/Whatpm/ChangeLog	5 Jun 2007 00:55:11 -0000
2007-06-05  Wakaba  <wakaba@suika.fam.cx>

	* NanoDOM.pm (get_attribute_node_ns): New method.

	* ContentChecker.pm: |script| |async| and |defer|
	no longer require |src|.  |async| MUST NOT be
	specified if |defer|.  (HTML5 revision 858).

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24