/[suikacvs]/messaging/manakai/lib/Message/DOM/Node.pm
Suika

Contents of /messaging/manakai/lib/Message/DOM/Node.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Sat Jun 16 15:27:45 2007 UTC (17 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.5: +82 -25 lines
++ manakai/t/ChangeLog	16 Jun 2007 15:27:38 -0000
	* DOM-Node.t: Tests for |prefix| and |text_content| are added.

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

++ manakai/lib/Message/DOM/ChangeLog	16 Jun 2007 15:27:12 -0000
	* DOMConfiguration.pm: New module.

	* Attr.pm (trivial accessor for read-write attributes): Throw
	an exception if the node is read-only.  Delete the property
	if undef is specified.
	(prefix): Implemented.

	* DOMElement.pm (trivial accessor for read-write attributes): Throw
        an exception if the node is read-only.  Delete the property
        if undef is specified.
        (prefix): Implemented.
	(text_content, manakai_append_text): Old implementations are removed.

	* DOMCharacterData.pm (text_content): Implemented.

	* DOMDocument.pm (____new): Initialize the strict-document-children
	parameter by true.
	(text_content): Reimplemented.
	(dom_config): New.

	* DOMException.pm (READ_ONLY_NODE_ERR): New subtype.

	* DocumentType.pm (text_content): Implemented.

	* ElementTypeDefinition.pm (text_content): Implemented.

	* Node.pm (___report_error): New method.
	(text_content): Implemented.
	(manakai_append_text): Copied from |DOMElement.pm|.

	* Notation.pm (text_content): Implemented.

	* ProcessingInstruction.pm (text_content): Implemented.

	* Text.pm (is_element_content_whitespace): Alpha version.

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

1 wakaba 1.1 package Message::DOM::Node;
2     use strict;
3 wakaba 1.6 our $VERSION=do{my @r=(q$Revision: 1.5 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.1 push our @ISA, 'Message::IF::Node';
5     require Scalar::Util;
6 wakaba 1.6 require Message::DOM::DOMException;
7 wakaba 1.1
8 wakaba 1.4 ## NOTE:
9     ## Node
10     ## + Attr (2)
11     ## + AttributeDefinition (81002)
12     ## + CharacterData
13     ## + Comment (8)
14     ## + Text (3)
15     ## + CDATASection (4)
16     ## + Document (9)
17     ## + DocumentFragment (11)
18     ## + DocumentType (10)
19     ## + Element (1)
20     ## + ElementTypeDefinition (81001)
21     ## + Entity (6)
22     ## + EntityReference (5)
23     ## + Notation (12)
24     ## + ProcessingInstruction (7)
25    
26     use overload
27     '==' => sub {
28     return 0 unless UNIVERSAL::isa ($_[0], 'Message::IF::Node');
29     ## TODO: implement is_equal_node
30     return $_[0]->is_equal_node ($_[1]);
31     },
32     '!=' => sub {
33     return not ($_[0] == $_[1]);
34     },
35     fallback => 1;
36    
37 wakaba 1.2 ## The |Node| interface - constants
38    
39     ## Definition group NodeType
40    
41     ## NOTE: Numeric codes up to 200 are reserved by W3C [DOM1SE, DOM2, DOM3].
42    
43     sub ELEMENT_NODE () { 1 }
44     sub ATTRIBUTE_NODE () { 2 }
45     sub TEXT_NODE () { 3 }
46     sub CDATA_SECTION_NODE () { 4 }
47     sub ENTITY_REFERENCE_NODE () { 5 }
48     sub ENTITY_NODE () { 6 }
49     sub PROCESSING_INSTRUCTION_NODE () { 7 }
50     sub COMMENT_NODE () { 8 }
51     sub DOCUMENT_NODE () { 9 }
52     sub DOCUMENT_TYPE_NODE () { 10 }
53     sub DOCUMENT_FRAGMENT_NODE () { 11 }
54     sub NOTATION_NODE () { 12 }
55     sub ELEMENT_TYPE_DEFINITION_NODE () { 81001 }
56     sub ATTRIBUTE_DEFINITION_NODE () { 81002 }
57    
58     ## Definition group DocumentPosition
59    
60     ## Spec:
61     ## <http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DocumentPosition>
62    
63     sub DOCUMENT_POSITION_DISCONNECTED () { 0x01 }
64     sub DOCUMENT_POSITION_PRECEDING () { 0x02 }
65     sub DOCUMENT_POSITION_FOLLOWING () { 0x04 }
66     sub DOCUMENT_POSITION_CONTAINS () { 0x08 }
67     sub DOCUMENT_POSITION_CONTAINED_BY () { 0x10 }
68     sub DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC () { 0x20 }
69    
70 wakaba 1.1 sub ____new ($$) {
71     my $self = bless \({}), shift;
72     $$self->{owner_document} = shift;
73     Scalar::Util::weaken ($$self->{owner_document});
74     return $self;
75     } # ____new
76    
77 wakaba 1.6 sub ___report_error ($$) {
78     $_[1]->throw;
79     } # ___report_error
80    
81 wakaba 1.1 sub AUTOLOAD {
82     my $method_name = our $AUTOLOAD;
83     $method_name =~ s/.*:://;
84     return if $method_name eq 'DESTROY';
85    
86     if ({
87     ## Read-only attributes (trivial accessors)
88     owner_document => 1,
89     parent_node => 1,
90 wakaba 1.4 manakai_read_only => 1,
91 wakaba 1.1 }->{$method_name}) {
92     no strict 'refs';
93     eval qq{
94     sub $method_name (\$) {
95     return \${\$_[0]}->{$method_name};
96     }
97     };
98     goto &{ $AUTOLOAD };
99     } elsif ({
100     ## Read-write attributes (DOMString, trivial accessors)
101     }->{$method_name}) {
102     no strict 'refs';
103     eval qq{
104 wakaba 1.2 sub $method_name (\$;\$) {
105 wakaba 1.1 if (\@_ > 1) {
106 wakaba 1.2 \${\$_[0]}->{$method_name} = ''.\$_[1];
107 wakaba 1.1 }
108     return \${\$_[0]}->{$method_name};
109     }
110     };
111     goto &{ $AUTOLOAD };
112     } else {
113     require Carp;
114     Carp::croak (qq<Can't locate method "$AUTOLOAD">);
115     }
116     } # AUTOLOAD
117    
118 wakaba 1.6 ## |Node| attributes
119 wakaba 1.1
120 wakaba 1.6 ## NOTE: Overridden by |Element|.
121     sub attributes () { undef }
122 wakaba 1.2
123 wakaba 1.3 ## TODO: baseURI
124    
125     sub child_nodes ($) {
126 wakaba 1.6 ## NOTE: Overridden by |CharacterData|, |ElementTypeDefinition|,
127     ## |Notation|, and |ProcessingInstruction|.
128 wakaba 1.4 require Message::DOM::NodeList;
129     return bless \\($_[0]), 'Message::DOM::NodeList::ChildNodeList';
130 wakaba 1.3 } # child_nodes
131    
132     sub first_child ($) {
133     my $self = shift;
134     return $$self->{child_nodes} ? $$self->{child_nodes}->[0] : undef;
135     } # first_child
136    
137     sub last_child ($) {
138     my $self = shift;
139     return $$self->{child_nodes} && $$self->{child_nodes}->[0]
140     ? $$self->{child_nodes}->[-1] : undef;
141     } # last_child
142    
143 wakaba 1.6 sub local_name { undef }
144 wakaba 1.3
145 wakaba 1.6 sub manakai_local_name { undef }
146    
147     sub namespace_uri { undef }
148 wakaba 1.3
149     sub next_sibling ($) {
150     my $self = shift;
151     my $parent = $$self->{parent_node};
152     return undef unless defined $parent;
153     my $has_self;
154     for (@{$parent->child_nodes}) {
155     if ($_ eq $self) {
156     $has_self = 1;
157     } elsif ($has_self) {
158     return $_;
159     }
160     }
161     return undef;
162     } # next_sibling
163 wakaba 1.2
164 wakaba 1.6 ## NOTE: Overridden by subclasses.
165     sub node_name () { undef }
166 wakaba 1.2
167 wakaba 1.6 ## NOTE: Overridden by subclasses.
168     sub node_type () { }
169 wakaba 1.2
170 wakaba 1.6 ## NOTE: Overridden by |Attr|, |AttributeDefinition|,
171     ## |CharacterData|, and |ProcessingInstruction|.
172     sub node_value () { undef }
173 wakaba 1.3
174     sub owner_document ($);
175    
176     sub parent_node ($);
177    
178 wakaba 1.6 ## NOTE: Overridden by |Element| and |Attr|.
179 wakaba 1.3 sub prefix ($;$) { undef }
180    
181     sub previous_sibling ($) {
182     my $self = shift;
183     my $parent = $$self->{parent_node};
184     return undef unless defined $parent;
185     my $prev;
186     for (@{$parent->child_nodes}) {
187     if ($_ eq $self) {
188     return $prev;
189     } else {
190     $prev = $_;
191     }
192     }
193     return undef;
194     } # previous_sibling
195    
196 wakaba 1.4 sub manakai_read_only ($);
197    
198 wakaba 1.3 sub text_content ($;$) {
199 wakaba 1.6 ## NOTE: For |Element|, |Attr|, |Entity|, |EntityReference|,
200     ## |DocumentFragment|, and |AttributeDefinition|. In addition,
201     ## |Document|'s |text_content| might call this attribute.
202    
203     ## NOTE: Overridden by |Document|, |DocumentType|, |Notation|,
204     ## |CharacterData|, |ProcessingInstruction|, and |ElementTypeDefinition|.
205    
206     my $self = $_[0];
207    
208     if (@_ > 1) {
209     if ($$self->{manakai_read_only}) {
210     report Message::DOM::DOMException
211     -object => $self,
212     -type => 'NO_MODIFICATION_ALLOWED_ERR',
213     -subtype => 'READ_ONLY_NODE_ERR';
214     }
215    
216     local $Error::Depth = $Error::Depth + 1;
217     @{$self->child_nodes} = ();
218     if (defined $_[1] and length $_[1]) {
219     ## NOTE: |DocumentType| don't use this code.
220     my $text = ($$self->{owner_document} || $self)->create_text_node ($_[1]);
221     $self->append_child ($text);
222     }
223     }
224    
225     if (defined wantarray) {
226     local $Error::Depth = $Error::Depth + 1;
227     my $r = '';
228     my @node = @{$self->child_nodes};
229     while (@node) {
230     my $child = shift @node;
231     my $child_nt = $child->node_type;
232     if ($child_nt == TEXT_NODE or $child_nt == CDATA_SECTION_NODE) {
233     $r .= $child->node_value unless $child->is_element_content_whitespace;
234     } elsif ($child_nt == COMMENT_NODE or
235     $child_nt == PROCESSING_INSTRUCTION_NODE or
236     $child_nt == DOCUMENT_TYPE_NODE) {
237     #
238     } else {
239     unshift @node, @{$child->child_nodes};
240     }
241     }
242     return $r;
243     }
244 wakaba 1.3 } # text_content
245    
246 wakaba 1.4 ## TODO:
247     sub is_same_node ($$) {
248     return $_[0] eq $_[1];
249     } # is_same_node
250    
251     ## TODO:
252 wakaba 1.1 sub is_equal_node ($$) {
253 wakaba 1.4 return $_[0]->node_name eq $_[1]->node_name &&
254     $_[0]->node_value eq $_[1]->node_value;
255 wakaba 1.1 } # is_equal_node
256    
257     sub manakai_parent_element ($) {
258     my $self = shift;
259     my $parent = $$self->{parent_node};
260     while (defined $parent) {
261     if ($parent->node_type == 1) { # ELEMENT_NODE
262     return $parent;
263     } else {
264     $parent = $$parent->{parent_node};
265     }
266     }
267     return undef;
268     } # manakai_parent_element
269    
270     ## NOTE: Only applied to Elements and Documents
271     sub append_child ($$) {
272     my ($self, $new_child) = @_;
273     if (defined $$new_child->{parent_node}) {
274 wakaba 1.5 my $parent_list = ${$$new_child->{parent_node}}->{child_nodes};
275 wakaba 1.1 for (0..$#$parent_list) {
276     if ($parent_list->[$_] eq $new_child) {
277     splice @$parent_list, $_, 1;
278     }
279     }
280     }
281     push @{$$self->{child_nodes}}, $new_child;
282     $$new_child->{parent_node} = $self;
283     Scalar::Util::weaken ($$new_child->{parent_node});
284     return $new_child;
285     } # append_child
286    
287     ## NOTE: Only applied to Elements and Documents
288     sub insert_before ($$;$) {
289     my ($self, $new_child, $ref_child) = @_;
290     if (defined $$new_child->{parent_node}) {
291 wakaba 1.5 my $parent_list = ${$$new_child->{parent_node}}->{child_nodes};
292 wakaba 1.1 for (0..$#$parent_list) {
293     if ($parent_list->[$_] eq $new_child) {
294     splice @$parent_list, $_, 1;
295     }
296     }
297     }
298     my $i = @{$$self->{child_nodes}};
299     if (defined $ref_child) {
300     for (0..$#{$$self->{child_nodes}}) {
301     if ($$self->{child_nodes}->[$_] eq $ref_child) {
302     $i = $_;
303     last;
304     }
305     }
306     }
307     splice @{$$self->{child_nodes}}, $i, 0, $new_child;
308     $$new_child->{parent_node} = $self;
309     Scalar::Util::weaken ($$new_child->{parent_node});
310     return $new_child;
311     } # insert_before
312    
313 wakaba 1.6 ## NOTE: For nodeTypes with childNodes
314     sub manakai_append_text ($$) {
315     my $self = shift;
316     local $Error::Depth = $Error::Depth + 1;
317     if (@{$$self->{child_nodes}} and
318     $$self->{child_nodes}->[-1]->node_type == 3) {
319     $$self->{child_nodes}->[-1]->manakai_append_text (shift);
320     } else {
321     my $text = $$self->{owner_document}->create_text_node ($_[0]);
322     $self->append_child ($text);
323     }
324     } # manakai_append_text
325    
326 wakaba 1.1 ## NOTE: Only applied to Elements and Documents
327     sub remove_child ($$) {
328     my ($self, $old_child) = @_;
329     my $parent_list = $$self->{child_nodes};
330     for (0..$#$parent_list) {
331     if ($parent_list->[$_] eq $old_child) {
332     splice @$parent_list, $_, 1;
333     }
334     }
335     delete $$old_child->{parent_node};
336     return $old_child;
337     } # remove_child
338    
339     ## NOTE: Only applied to Elements and Documents
340     sub has_child_nodes ($) {
341     return @{${+shift}->{child_nodes}} > 0;
342     } # has_child_nodes
343    
344 wakaba 1.4 sub manakai_set_read_only ($;$$) {
345     my ($self, $value, $deep) = @_;
346     ## TODO: deep
347     $$self->{manakai_read_only} = $value;
348     } # manakai_set_read_only
349    
350     package Message::IF::Node;
351    
352     =head1 LICENSE
353 wakaba 1.1
354 wakaba 1.4 Copyright 2007 Wakaba <w@suika.fam.cx>
355 wakaba 1.1
356 wakaba 1.4 This program is free software; you can redistribute it and/or
357     modify it under the same terms as Perl itself.
358 wakaba 1.1
359 wakaba 1.4 =cut
360 wakaba 1.1
361     1;
362 wakaba 1.6 ## $Date: 2007/06/16 08:49:00 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24