/[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.11 - (show annotations) (download)
Sat Jun 23 06:38:12 2007 UTC (19 years, 2 months ago) by wakaba
Branch: MAIN
Changes since 1.10: +13 -1 lines
++ whatpm/t/ChangeLog	23 Jun 2007 06:37:09 -0000
	* tokenizer-test-1.test: |™| test added.  (HTML5 revision 889.)

	* HTML-tree.t: Output test file names.  Escaped
	new line at the end of test data was removed.

	* tokenizer-test-2.dat: Tests for newlines, NULL, and
	escape flag stuff in |set_inner_html|.

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

++ whatpm/Whatpm/ChangeLog	23 Jun 2007 06:35:23 -0000
	* HTML.pm.src (set_inner_html): HTML5 revision 892 (adopt
	nodes before appended).  Parser was not ready for NULL
	parse error and escape flag.

	* NanoDOM.pm (adopt_node): New.

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

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 parent_node ($) {
35 return shift->{parent_node};
36 } # parent_node
37
38 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 sub child_nodes ($) {
52 return shift->{child_nodes} || [];
53 } # 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 $new_child->{parent_node} = $self;
68 Scalar::Util::weaken ($new_child->{parent_node});
69 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 $new_child->{parent_node} = $self;
94 Scalar::Util::weaken ($new_child->{parent_node});
95 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 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 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 sub prefix ($;$) {
145 my $self = shift;
146 if (@_) {
147 $self->{prefix} = shift;
148 }
149 return $self->{prefix};
150 } # prefix
151
152 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 package Whatpm::NanoDOM::Document;
166 push our @ISA, 'Whatpm::NanoDOM::Node';
167
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 return Whatpm::NanoDOM::Text->new (shift);
195 } # create_text_node
196
197 sub create_comment ($$) {
198 shift;
199 return Whatpm::NanoDOM::Comment->new (shift);
200 } # 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 return Whatpm::NanoDOM::Element->new ($self, $nsuri, $qn->[0], $qn->[1]);
207 } # create_element_ns
208
209 ## A manakai extension
210 sub create_document_type_definition ($$) {
211 shift;
212 return Whatpm::NanoDOM::DocumentType->new (shift);
213 } # create_document_type_definition
214
215 sub implementation ($) {
216 return 'Whatpm::NanoDOM::DOMImplementation';
217 } # implementation
218
219 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 sub adopt_node {
230 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 package Whatpm::NanoDOM::Element;
242 push our @ISA, 'Whatpm::NanoDOM::Node';
243
244 sub new ($$$$$) {
245 my $self = shift->SUPER::new;
246 $self->{owner_document} = shift;
247 Scalar::Util::weaken ($self->{owner_document});
248 $self->{namespace_uri} = shift;
249 $self->{prefix} = shift;
250 $self->{local_name} = shift;
251 $self->{attributes} = {};
252 $self->{child_nodes} = [];
253 return $self;
254 } # new
255
256 sub owner_document ($) {
257 return shift->{owner_document};
258 } # owner_document
259
260 sub clone_node ($$) {
261 my ($self, $deep) = @_; ## NOTE: Deep cloning is not supported
262 my $clone = bless {
263 namespace_uri => $self->{namespace_uri},
264 prefix => $self->{prefix},
265 local_name => $self->{local_name},
266 child_nodes => [],
267 }, ref $self;
268 for my $ns (keys %{$self->{attributes}}) {
269 for my $ln (keys %{$self->{attributes}->{$ns}}) {
270 my $attr = $self->{attributes}->{$ns}->{$ln};
271 $clone->{attributes}->{$ns}->{$ln} = bless {
272 namespace_uri => $attr->{namespace_uri},
273 prefix => $attr->{prefix},
274 local_name => $attr->{local_name},
275 value => $attr->{value},
276 }, ref $self->{attributes}->{$ns}->{$ln};
277 }
278 }
279 return $clone;
280 } # clone
281
282 ## A manakai extension
283 sub manakai_append_text ($$) {
284 my $self = shift;
285 if (@{$self->{child_nodes}} and
286 $self->{child_nodes}->[-1]->node_type == 3) {
287 $self->{child_nodes}->[-1]->manakai_append_text (shift);
288 } else {
289 my $text = Whatpm::NanoDOM::Text->new (shift);
290 $self->append_child ($text);
291 }
292 } # manakai_append_text
293
294 sub text_content ($) {
295 my $self = shift;
296 my $r = '';
297 for my $child (@{$self->child_nodes}) {
298 if ($child->can ('data')) {
299 $r .= $child->data;
300 } else {
301 $r .= $child->text_content;
302 }
303 }
304 return $r;
305 } # text_content
306
307 sub attributes ($) {
308 my $self = shift;
309 my $r = [];
310 ## Order MUST be stable
311 for my $ns (sort {$a cmp $b} keys %{$self->{attributes}}) {
312 for my $ln (sort {$a cmp $b} keys %{$self->{attributes}->{$ns}}) {
313 push @$r, $self->{attributes}->{$ns}->{$ln}
314 if defined $self->{attributes}->{$ns}->{$ln};
315 }
316 }
317 return $r;
318 } # attributes
319
320 sub local_name ($) { # TODO: HTML5 case
321 return shift->{local_name};
322 } # local_name
323
324 sub manakai_local_name ($) {
325 return shift->{local_name}; # no case fixing for HTML5
326 } # manakai_local_name
327
328 sub namespace_uri ($) {
329 return shift->{namespace_uri};
330 } # namespace_uri
331
332 sub manakai_element_type_match ($$$) {
333 my ($self, $nsuri, $ln) = @_;
334 if (defined $nsuri) {
335 if (defined $self->{namespace_uri} and $nsuri eq $self->{namespace_uri}) {
336 return ($ln eq $self->{local_name});
337 } else {
338 return 0;
339 }
340 } else {
341 if (not defined $self->{namespace_uri}) {
342 return ($ln eq $self->{local_name});
343 } else {
344 return 0;
345 }
346 }
347 } # manakai_element_type_match
348
349 sub node_type { 1 }
350
351 ## TODO: HTML5 capitalization
352 sub tag_name ($) {
353 my $self = shift;
354 if (defined $self->{prefix}) {
355 return $self->{prefix} . ':' . $self->{local_name};
356 } else {
357 return $self->{local_name};
358 }
359 } # tag_name
360
361 sub get_attribute_ns ($$$) {
362 my ($self, $nsuri, $ln) = @_;
363 $nsuri = '' unless defined $nsuri;
364 return defined $self->{attributes}->{$nsuri}->{$ln}
365 ? $self->{attributes}->{$nsuri}->{$ln}->value : undef;
366 } # get_attribute_ns
367
368 sub get_attribute_node_ns ($$$) {
369 my ($self, $nsuri, $ln) = @_;
370 $nsuri = '' unless defined $nsuri;
371 return $self->{attributes}->{$nsuri}->{$ln};
372 } # get_attribute_node_ns
373
374 sub has_attribute_ns ($$$) {
375 my ($self, $nsuri, $ln) = @_;
376 $nsuri = '' unless defined $nsuri;
377 return defined $self->{attributes}->{$nsuri}->{$ln};
378 } # has_attribute_ns
379
380 ## The second parameter only supports manakai extended way
381 ## to specify qualified name - "[$prefix, $local_name]"
382 sub set_attribute_ns ($$$$) {
383 my ($self, $nsuri, $qn, $value) = @_;
384 $self->{attributes}->{$nsuri}->{$qn->[1]}
385 = Whatpm::NanoDOM::Attr->new ($self, $nsuri, $qn->[0], $qn->[1], $value);
386 } # set_attribute_ns
387
388 package Whatpm::NanoDOM::Attr;
389 push our @ISA, 'Whatpm::NanoDOM::Node';
390
391 sub new ($$$$$$) {
392 my $self = shift->SUPER::new;
393 $self->{owner_element} = shift;
394 Scalar::Util::weaken ($self->{owner_element});
395 $self->{namespace_uri} = shift;
396 $self->{prefix} = shift;
397 $self->{local_name} = shift;
398 $self->{value} = shift;
399 return $self;
400 } # new
401
402 sub namespace_uri ($) {
403 return shift->{namespace_uri};
404 } # namespace_uri
405
406 sub manakai_local_name ($) {
407 return shift->{local_name};
408 } # manakai_local_name
409
410 sub node_type { 2 }
411
412 ## TODO: HTML5 case stuff?
413 sub name ($) {
414 my $self = shift;
415 if (defined $self->{prefix}) {
416 return $self->{prefix} . ':' . $self->{local_name};
417 } else {
418 return $self->{local_name};
419 }
420 } # name
421
422 sub value ($) {
423 return shift->{value};
424 } # value
425
426 sub owner_element ($) {
427 return shift->{owner_element};
428 } # owner_element
429
430 package Whatpm::NanoDOM::CharacterData;
431 push our @ISA, 'Whatpm::NanoDOM::Node';
432
433 sub new ($$) {
434 my $self = shift->SUPER::new;
435 $self->{data} = shift;
436 return $self;
437 } # new
438
439 ## A manakai extension
440 sub manakai_append_text ($$) {
441 my ($self, $s) = @_;
442 $self->{data} .= $s;
443 } # manakai_append_text
444
445 sub data ($) {
446 return shift->{data};
447 } # data
448
449 package Whatpm::NanoDOM::Text;
450 push our @ISA, 'Whatpm::NanoDOM::CharacterData';
451
452 sub node_type () { 3 }
453
454 package Whatpm::NanoDOM::Comment;
455 push our @ISA, 'Whatpm::NanoDOM::CharacterData';
456
457 sub node_type () { 8 }
458
459 package Whatpm::NanoDOM::DocumentType;
460 push our @ISA, 'Whatpm::NanoDOM::Node';
461
462 sub new ($$) {
463 my $self = shift->SUPER::new;
464 $self->{name} = shift;
465 return $self;
466 } # new
467
468 sub node_type () { 10 }
469
470 sub name ($) {
471 return shift->{name};
472 } # name
473
474 =head1 SEE ALSO
475
476 L<Whatpm::HTML>
477
478 =head1 AUTHOR
479
480 Wakaba <[email protected]>.
481
482 =head1 LICENSE
483
484 Copyright 2007 Wakaba <[email protected]>
485
486 This library is free software; you can redistribute it
487 and/or modify it under the same terms as Perl itself.
488
489 =cut
490
491 1;
492 # $Date: 2007/06/23 02:26:51 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24