/[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.3 - (show annotations) (download)
Wed May 2 13:44:34 2007 UTC (17 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +31 -4 lines
++ ChangeLog	2 May 2007 13:37:34 -0000
2007-05-02  Wakaba  <wakaba@suika.fam.cx>

	* readme.en.html: TODO section is added.

++ whatpm/t/ChangeLog	2 May 2007 13:44:02 -0000
2007-05-02  Wakaba  <wakaba@suika.fam.cx>

	* .cvsignore: Result files are added.

	* HTML-tree.t: Support for document fragment tests.

	* Makefile: Generate test result files.

	* tokenizer-test-1.test: A new test to ensure that
	characters after end tag are preserved in RCDATA or CDATA
	case.

++ whatpm/Whatpm/ChangeLog	2 May 2007 13:42:17 -0000
2007-05-02  Wakaba  <wakaba@suika.fam.cx>

	* NanoDOM.pm (DOMImplementation): New class.
	(append_child): Weaken the |parent_node| reference.
	(create_element_ns, Element new): Set the |owner_document|
	reference.
	(implementation): New attribute.
	(owner_document, local_name, namespace_uri): New attributes.

	* HTML.pm.src (parse_string): Line and column numbers
	are now provided to error handler.
	(!!!parse-error): Short descriptions are added.
	(_construct_tree): Split into three methods; support
	for innerHTML mode.
	(set_inner_html): New method.

1 =head1 NAME
2
3 Whatpm::NanoDOM - A Non-Conforming Implementation of DOM Subset
4
5 =head1 DESCRIPTION
6
7 The C<Whatpm::NanoDOM> module contains a non-conforming implementation
8 of a subset of DOM. It is the intention that this module is
9 used only for the purpose of testing the C<Whatpm::HTML> module.
10
11 See source code if you would like to know what it does.
12
13 =cut
14
15 package Whatpm::NanoDOM;
16 use strict;
17
18 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 package Whatpm::NanoDOM::Node;
27
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 ## NOTE: Only applied to Elements and Documents
43 sub child_nodes ($) {
44 return shift->{child_nodes};
45 } # child_nodes
46
47 ## NOTE: Only applied to Elements and Documents
48 sub append_child ($$) {
49 my ($self, $new_child) = @_;
50 if (defined $new_child->{parent_node}) {
51 my $parent_list = $new_child->{parent_node}->{child_nodes};
52 for (0..$#$parent_list) {
53 if ($parent_list->[$_] eq $new_child) {
54 splice @$parent_list, $_, 1;
55 }
56 }
57 }
58 push @{$self->{child_nodes}}, $new_child;
59 $new_child->{parent_node} = $self;
60 Scalar::Util::weaken ($new_child->{parent_node});
61 return $new_child;
62 } # append_child
63
64 ## NOTE: Only applied to Elements and Documents
65 sub insert_before ($$;$) {
66 my ($self, $new_child, $ref_child) = @_;
67 if (defined $new_child->{parent_node}) {
68 my $parent_list = $new_child->{parent_node}->{child_nodes};
69 for (0..$#$parent_list) {
70 if ($parent_list->[$_] eq $new_child) {
71 splice @$parent_list, $_, 1;
72 }
73 }
74 }
75 my $i = @{$self->{child_nodes}};
76 if (defined $ref_child) {
77 for (0..$#{$self->{child_nodes}}) {
78 if ($self->{child_nodes}->[$_] eq $ref_child) {
79 $i = $_;
80 last;
81 }
82 }
83 }
84 splice @{$self->{child_nodes}}, $i, 0, $new_child;
85 $new_child->{parent_node} = $self; ## TODO: weaken this ref
86 return $new_child;
87 } # insert_before
88
89 ## NOTE: Only applied to Elements and Documents
90 sub remove_child ($$) {
91 my ($self, $old_child) = @_;
92 my $parent_list = $self->{child_nodes};
93 for (0..$#$parent_list) {
94 if ($parent_list->[$_] eq $old_child) {
95 splice @$parent_list, $_, 1;
96 }
97 }
98 delete $old_child->{parent_node};
99 return $old_child;
100 } # remove_child
101
102 ## NOTE: Only applied to Elements and Documents
103 sub has_child_nodes ($) {
104 return @{shift->{child_nodes}} > 0;
105 } # has_child_nodes
106
107 ## NOTE: Only applied to Elements and Documents
108 sub last_child ($) {
109 my $self = shift;
110 return @{$self->{child_nodes}} ? $self->{child_nodes}->[-1] : undef;
111 } # last_child
112
113 ## NOTE: Only applied to Elements and Documents
114 sub previous_sibling ($) {
115 my $self = shift;
116 my $parent = $self->{parent_node};
117 return undef unless defined $parent;
118 my $r;
119 for (@{$parent->{child_nodes}}) {
120 if ($_ eq $self) {
121 return $r;
122 } else {
123 $r = $_;
124 }
125 }
126 return undef;
127 } # previous_sibling
128
129 sub ELEMENT_NODE () { 1 }
130 sub ATTRIBUTE_NODE () { 2 }
131 sub TEXT_NODE () { 3 }
132 sub CDATA_SECTION_NODE () { 4 }
133 sub ENTITY_REFERENCE_NODE () { 5 }
134 sub ENTITY_NODE () { 6 }
135 sub PROCESSING_INSTRUCTION_NODE () { 7 }
136 sub COMMENT_NODE () { 8 }
137 sub DOCUMENT_NODE () { 9 }
138 sub DOCUMENT_TYPE_NODE () { 10 }
139 sub DOCUMENT_FRAGMENT_NODE () { 11 }
140 sub NOTATION_NODE () { 12 }
141
142 package Whatpm::NanoDOM::Document;
143 push our @ISA, 'Whatpm::NanoDOM::Node';
144
145 sub new ($) {
146 my $self = shift->SUPER::new;
147 $self->{child_nodes} = [];
148 return $self;
149 } # new
150
151 ## A manakai extension
152 sub manakai_append_text ($$) {
153 my $self = shift;
154 if (@{$self->{child_nodes}} and
155 $self->{child_nodes}->[-1]->node_type == 3) {
156 $self->{child_nodes}->[-1]->manakai_append_text (shift);
157 } else {
158 my $text = $self->create_text_node (shift);
159 $self->append_child ($text);
160 }
161 } # manakai_append_text
162
163 sub node_type () { 9 }
164
165 sub strict_error_checking {
166 return 0;
167 } # strict_error_checking
168
169 sub create_text_node ($$) {
170 shift;
171 return Whatpm::NanoDOM::Text->new (shift);
172 } # create_text_node
173
174 sub create_comment ($$) {
175 shift;
176 return Whatpm::NanoDOM::Comment->new (shift);
177 } # create_comment
178
179 ## The second parameter only supports manakai extended way
180 ## to specify qualified name - "[$prefix, $local_name]"
181 sub create_element_ns ($$$) {
182 my ($self, $nsuri, $qn) = @_;
183 return Whatpm::NanoDOM::Element->new ($self, $nsuri, $qn->[0], $qn->[1]);
184 } # create_element_ns
185
186 ## A manakai extension
187 sub create_document_type_definition ($$) {
188 shift;
189 return Whatpm::NanoDOM::DocumentType->new (shift);
190 } # create_document_type_definition
191
192 sub implementation ($) {
193 return 'Whatpm::NanoDOM::DOMImplementation';
194 } # implementation
195
196 package Whatpm::NanoDOM::Element;
197 push our @ISA, 'Whatpm::NanoDOM::Node';
198
199 sub new ($$$$$) {
200 my $self = shift->SUPER::new;
201 $self->{owner_document} = shift;
202 Scalar::Util::weaken ($self->{owner_document});
203 $self->{namespace_uri} = shift;
204 $self->{prefix} = shift;
205 $self->{local_name} = shift;
206 $self->{attributes} = {};
207 $self->{child_nodes} = [];
208 return $self;
209 } # new
210
211 sub owner_document ($) {
212 return shift->{owner_document};
213 } # owner_document
214
215 sub clone_node ($$) {
216 my ($self, $deep) = @_; ## NOTE: Deep cloning is not supported
217 my $clone = bless {
218 namespace_uri => $self->{namespace_uri},
219 prefix => $self->{prefix},
220 local_name => $self->{local_name},
221 child_nodes => [],
222 }, ref $self;
223 for my $ns (keys %{$self->{attributes}}) {
224 for my $ln (keys %{$self->{attributes}->{$ns}}) {
225 my $attr = $self->{attributes}->{$ns}->{$ln};
226 $clone->{attributes}->{$ns}->{$ln} = bless {
227 namespace_uri => $attr->{namespace_uri},
228 prefix => $attr->{prefix},
229 local_name => $attr->{local_name},
230 value => $attr->{value},
231 }, ref $self->{attributes}->{$ns}->{$ln};
232 }
233 }
234 return $clone;
235 } # clone
236
237 ## A manakai extension
238 sub manakai_append_text ($$) {
239 my $self = shift;
240 if (@{$self->{child_nodes}} and
241 $self->{child_nodes}->[-1]->node_type == 3) {
242 $self->{child_nodes}->[-1]->manakai_append_text (shift);
243 } else {
244 my $text = Whatpm::NanoDOM::Text->new (shift);
245 $self->append_child ($text);
246 }
247 } # manakai_append_text
248
249 sub attributes ($) {
250 my $self = shift;
251 my $r = [];
252 ## Order MUST be stable
253 for my $ns (sort {$a cmp $b} keys %{$self->{attributes}}) {
254 for my $ln (sort {$a cmp $b} keys %{$self->{attributes}->{$ns}}) {
255 push @$r, $self->{attributes}->{$ns}->{$ln}
256 if defined $self->{attributes}->{$ns}->{$ln};
257 }
258 }
259 return $r;
260 } # attributes
261
262 sub local_name ($) { # TODO: HTML5 case
263 return shift->{local_name};
264 } # local_name
265
266 sub namespace_uri ($) {
267 return shift->{namespace_uri};
268 } # namespace_uri
269
270 sub node_type { 1 }
271
272 ## TODO: HTML5 capitalization
273 sub tag_name ($) {
274 my $self = shift;
275 if (defined $self->{prefix}) {
276 return $self->{prefix} . ':' . $self->{local_name};
277 } else {
278 return $self->{local_name};
279 }
280 } # tag_name
281
282 sub has_attribute_ns ($$$) {
283 my ($self, $nsuri, $ln) = @_;
284 return defined $self->{attributes}->{$nsuri}->{$ln};
285 } # has_attribute_ns
286
287 ## The second parameter only supports manakai extended way
288 ## to specify qualified name - "[$prefix, $local_name]"
289 sub set_attribute_ns ($$$$) {
290 my ($self, $nsuri, $qn, $value) = @_;
291 $self->{attributes}->{$nsuri}->{$qn->[1]}
292 = Whatpm::NanoDOM::Attr->new ($nsuri, $qn->[0], $qn->[1], $value);
293 } # set_attribute_ns
294
295 package Whatpm::NanoDOM::Attr;
296 push our @ISA, 'Whatpm::NanoDOM::Node';
297
298 sub new ($$$$$) {
299 my $self = shift->SUPER::new;
300 $self->{namespace_uri} = shift;
301 $self->{prefix} = shift;
302 $self->{local_name} = shift;
303 $self->{value} = shift;
304 return $self;
305 } # new
306
307 sub node_type { 2 }
308
309 ## TODO: HTML5 case stuff?
310 sub name ($) {
311 my $self = shift;
312 if (defined $self->{prefix}) {
313 return $self->{prefix} . ':' . $self->{local_name};
314 } else {
315 return $self->{local_name};
316 }
317 } # name
318
319 sub value ($) {
320 return shift->{value};
321 } # value
322
323 package Whatpm::NanoDOM::CharacterData;
324 push our @ISA, 'Whatpm::NanoDOM::Node';
325
326 sub new ($$) {
327 my $self = shift->SUPER::new;
328 $self->{data} = shift;
329 return $self;
330 } # new
331
332 ## A manakai extension
333 sub manakai_append_text ($$) {
334 my ($self, $s) = @_;
335 $self->{data} .= $s;
336 } # manakai_append_text
337
338 sub data ($) {
339 return shift->{data};
340 } # data
341
342 package Whatpm::NanoDOM::Text;
343 push our @ISA, 'Whatpm::NanoDOM::CharacterData';
344
345 sub node_type () { 3 }
346
347 package Whatpm::NanoDOM::Comment;
348 push our @ISA, 'Whatpm::NanoDOM::CharacterData';
349
350 sub node_type () { 8 }
351
352 package Whatpm::NanoDOM::DocumentType;
353 push our @ISA, 'Whatpm::NanoDOM::Node';
354
355 sub new ($$) {
356 my $self = shift->SUPER::new;
357 $self->{name} = shift;
358 return $self;
359 } # new
360
361 sub node_type () { 10 }
362
363 sub name ($) {
364 return shift->{name};
365 } # name
366
367 =head1 SEE ALSO
368
369 L<Whatpm::HTML>
370
371 =head1 AUTHOR
372
373 Wakaba <w@suika.fam.cx>.
374
375 =head1 LICENSE
376
377 Copyright 2007 Wakaba <w@suika.fam.cx>
378
379 This library is free software; you can redistribute it
380 and/or modify it under the same terms as Perl itself.
381
382 =cut
383
384 1;
385 # $Date: 2007/05/01 10:47:37 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24