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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations) (download)
Sun Jul 8 07:59:02 2007 UTC (17 years, 4 months ago) by wakaba
Branch: MAIN
++ manakai/lib/Message/DOM/ChangeLog	8 Jul 2007 07:58:55 -0000
	* DOMElement.pm (attributes): Implemented.

	* DOMException.pm (INUSE_DEFINITION_ERR): New error type.

	* DocumentType.pm (entities, general_entities,
	notations, element_types): Implemented.

	* ElementTypeDefinition.pm (attribute_definitions): Implemented.

	* NamedNodeMap.pm: New Perl module.

2007-07-08  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Message::DOM::NamedNodeMap;
2     use strict;
3     our $VERSION=do{my @r=(q$Revision: 1.3 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4     push our @ISA, 'Message::IF::NamedNodeMap';
5     require Message::DOM::DOMException;
6     require Tie::Array;
7    
8     use overload
9     '@{}' => sub {
10     tie my @list, (ref $_[0]) . '::Array', $_[0];
11     return \@list;
12     },
13     '%{}' => sub {
14     tie my %list, ref $_[0], $_[0];
15     return \%list;
16     },
17     eq => sub {
18     return 0 unless UNIVERSAL::isa ($_[1], 'Message::DOM::NamedNodeMap');
19     return 0 if $_[1]->isa ('Message::DOM::NamedNodeMap::ArrayMap');
20     return (${$_[0]}->[0] eq ${$_[1]}->[0] and ${$_[0]}->[1] eq ${$_[1]}->[1]);
21     },
22     ne => sub {
23     return not ($_[0] eq $_[1]);
24     },
25     '==' => sub {
26     return 0 unless UNIVERSAL::isa ($_[1], 'Message::IF::NamedNodeMap');
27    
28     local $Error::Depth = $Error::Depth + 1;
29     my $length1 = @{$_[0]};
30     my $length2 = @{$_[1]};
31     return 0 if $length1 != $length2;
32    
33     for my $i (0..($length1 - 1)) {
34     my $node1 = $_[0]->[$i];
35     my $node2 = $_[1]->[$i];
36     return 0 if $node1 != $node2;
37     }
38     ## TODO: This ordering is only assumed in manakai...
39    
40     return 1;
41     },
42     '!=' => sub {
43     return not ($_[0] == $_[1]);
44     },
45     fallback => 1;
46    
47     sub ___report_error ($$) {
48     $_[1]->throw;
49     } # ___report_error
50    
51     ## |NamedNodeMap| attributes
52    
53     sub length ($) {
54     return scalar @{[map {$_} values %{${${$_[0]}->[0]}->{${$_[0]}->[1]}}]};
55     } # length
56    
57     sub manakai_read_only ($) {
58     return ${${$_[0]}->[0]}->{manakai_read_only};
59     } # manakai_read_only
60    
61     ## |NamedNodeMap| methods
62    
63     sub get_named_item ($$) {
64     return ${${$_[0]}->[0]}->{${$_[0]}->[1]}->{$_[1]};
65     } # get_named_item
66     *FETCH = \&get_named_item;
67    
68     sub get_named_item_ns ($$$) { }
69    
70     sub item ($$) {
71     my $index = 0+$_[1];
72     my $list = ${${$_[0]}->[0]}->{${$_[0]}->[1]};
73    
74     my $key = $index >= 0 ? [sort {$a cmp $b} keys %$list]->[$index] : undef;
75     if (defined $key and defined $list->{$key}) {
76     return $list->{$key};
77     } else {
78     return undef;
79     }
80     } # item
81    
82     sub remove_named_item ($$) {
83     my $name = ''.$_[1];
84     my $list = ${${$_[0]}->[0]}->{${$_[0]}->[1]};
85    
86     my $od = ${${$_[0]}->[0]}->{owner_document}; # might be undef, but no problem
87    
88     my $key = ${$_[0]}->[1] eq 'attribute_definitions'
89     ? 'owner_element_type_definition' : 'owner_document_type_definition';
90    
91     if ($$od->{strict_error_checking}) {
92     if (${${$_[0]}->[0]}->{manakai_read_only}) {
93     report Message::DOM::DOMException
94     -object => $_[0],
95     -type => 'NO_MODIFICATION_ALLOWED_ERR',
96     -subtype => 'READ_ONLY_NODE_ERR';
97     }
98     }
99    
100     if (defined $list->{$name}) {
101     my $r = $list->{$name};
102     delete $$r->{$key};
103     delete $list->{$name};
104     return $r;
105     } else {
106     report Message::DOM::DOMException
107     -object => $_[0],
108     -type => 'NOT_FOUND_ERR',
109     -subtype => 'NOT_CHILD_ERR';
110     }
111     } # remove_named_item
112    
113     sub remove_named_item_ns ($$) {
114     report Message::DOM::DOMException
115     -object => $_[0],
116     -type => 'NOT_FOUND_ERR',
117     -subtype => 'NOT_CHILD_ERR';
118     } # remove_named_item_ns
119    
120     sub DELETE ($$) {
121     my $r;
122     try {
123     $r = $_[0]->remove_named_item ($_[1]);
124     } catch Message::DOM::DOMException with {
125     my $err = shift;
126     unless ($err->subtype eq 'NOT_CHILD_ERR') {
127     $err->throw;
128     }
129     };
130     return $r; ## TODO: This return value is ok?
131     } # DELETE
132    
133     sub set_named_item ($$) {
134     my $od = ${${$_[0]}->[0]}->{owner_document};
135     if (not defined $od or
136     $od ne ($_[1]->owner_document || $_[1])) {
137     ## TODO: $od not defined case is manakai extension. Document it!
138     report Message::DOM::DOMException
139     -object => $_[0],
140     -type => 'WRONG_DOCUMENT_ERR',
141     -subtype => 'EXTERNAL_OBJECT_ERR';
142     }
143    
144     my $key = ${$_[0]}->[1] eq 'attribute_definitions'
145     ? 'owner_element_type_definition' : 'owner_document_type_definition';
146    
147     if ($$od->{strict_error_checking}) {
148     if ($_[1]->node_type !=
149     {
150     element_types => 81001, # ELEMENT_TYPE_DEFINITION_NODE
151     attribute_definitions => 81002, # ATTRIBUTE_DEFINITION_NODE
152     entities => 6, # ENTITY_NODE
153     notations => 12, # NOTATION_NODE
154     }->{${$_[0]}->[1]}) {
155     report Message::DOM::DOMException
156     -object => $_[0],
157     -type => 'HIERARCHY_REQUEST_ERR',
158     -subtype => 'CHILD_NODE_TYPE_ERR';
159     }
160    
161     if (${${$_[0]}->[0]}->{manakai_read_only}) {
162     report Message::DOM::DOMException
163     -object => $_[0],
164     -type => 'NO_MODIFICATION_ALLOWED_ERR',
165     -subtype => 'READ_ONLY_NODE_ERR';
166     }
167    
168     if (${$_[1]}->{$key} and not ${$_[1]}->{$key} eq ${$_[0]}->[0]) {
169     ## TODO: This is manakai extension. Document it!
170     report Message::DOM::DOMException
171     -object => $_[0],
172     -type => 'HIERARCHY_REQUEST_ERR',
173     -subtype => 'INUSE_DEFINITION_ERR';
174     }
175     }
176    
177     my $name = $_[1]->node_name;
178     my $list = ${${$_[0]}->[0]}->{${$_[0]}->[1]};
179     if (defined $list->{$name}) {
180     my $r = $list->{$name};
181     if ($r eq $_[1]) {
182     ## NOTE: Replace by itself (implementation dependent).
183     return undef;
184     } else {
185     $list->{$name} = $_[1];
186     ${$_[1]}->{$key} = ${$_[0]}->[0];
187     Scalar::Util::weaken (${$_[1]}->{$key});
188     delete $$r->{$key};
189     return $r;
190     }
191     } else {
192     $list->{$name} = $_[1];
193     ${$_[1]}->{$key} = ${$_[0]}->[0];
194     Scalar::Util::weaken (${$_[1]}->{$key});
195     return undef;
196     }
197     } # set_named_item
198    
199     sub set_named_item_ns ($$) {
200     report Message::DOM::DOMException
201     -object => $_[0],
202     -type => 'HIERARCHY_REQUEST_ERR',
203     -subtype => 'CHILD_NODE_TYPE_ERR';
204     } # set_named_item_ns
205    
206     sub EXISTS ($$) {
207     return exists ${${$_[0]}->[0]}->{${$_[0]}->[1]}->{$_[1]};
208     } # EXISTS
209    
210     sub FIRSTKEY ($) {
211     my $list = ${${$_[0]}->[0]}->{${$_[0]}->[1]};
212     my $a = keys %$list; # reset
213     return each %$list;
214     } # FIRSTKEY
215    
216     sub NEXTKEY ($) {
217     return each %{${${$_[0]}->[0]}->{${$_[0]}->[1]}};
218     } # NEXTKEY
219    
220     sub SCALAR ($) {
221     return scalar %{${${$_[0]}->[0]}->{${$_[0]}->[1]}};
222     } # SCALAR
223    
224     package Message::DOM::NamedNodeMap::Array;
225     push our @ISA, 'Tie::Array';
226    
227     sub DELETE ($$) {
228     my $item = $_[0]->item ($_[1]);
229     if ($item) {
230     local $Error::Depth = $Error::Depth + 1;
231     return $_[0]->remove_named_item ($item->node_name);
232     } else {
233     return undef;
234     }
235     } # DELETE
236    
237     sub EXISTS ($$) {
238     return ($_[1] < $_[0]->length);
239     } # EXISTS
240    
241     *FETCH = \&Message::DOM::NamedNodeMap::item;
242    
243     *FETCHSIZE = \&Message::DOM::NamedNodeMap::length;
244    
245     ## TODO: |STORE|
246    
247     sub STORESIZE ($) {
248     local $Error::Depth = $Error::Depth + 1;
249     my $length = $_[0]->length;
250     if ($length > $_[1]) {
251     for (my $i = $length - 1; $i >= $_[1]; $i--) {
252     my $item = $_[0]->item ($i);
253     $_[0]->remove_named_item ($item->node_name);
254     }
255     }
256     } # STORESIZE
257    
258     sub TIEARRAY ($$) { bless \[${$_[1]}->[0], ${$_[1]}->[1]], __PACKAGE__ }
259    
260     package Message::DOM::NamedNodeMap::AttrMap;
261     push our @ISA, 'Message::DOM::NamedNodeMap';
262    
263     use overload
264     eq => sub {
265     return 0 unless UNIVERSAL::isa ($_[1], 'Message::DOM::NamedNodeMap');
266     return $${$_[0]} eq $${$_[1]};
267     },
268     fallback => 1;
269    
270     ## |NamedNodeMap| attributes
271    
272     sub length ($) {
273     my $list = ${$${$_[0]}}->{manakai_content_attribute_list};
274     if (defined $list) {
275     return scalar @$list;
276     } else {
277     $list = ${$${$_[0]}}->{attributes};
278     my $r = 0;
279     for my $l (values %$list) {
280     $r += grep {$l->{$_}} keys %$l;
281     }
282     return $r;
283     }
284     } # length
285    
286     sub manakai_read_only ($) {
287     return ${$${$_[0]}}->{manakai_read_only};
288     } # manakai_read_only
289    
290     ## |NamedNodeMap| methods
291    
292     sub get_named_item ($$) {
293     local $Error::Depth = $Error::Depth + 1;
294     return $${$_[0]}->get_attribute_node ($_[1]);
295     } # get_named_item
296     *FETCH = \&get_named_item;
297    
298     sub get_named_item_ns ($$$) {
299     local $Error::Depth = $Error::Depth + 1;
300     return $${$_[0]}->get_attribute_node_ns ($_[1], $_[2]);
301     } # get_named_item_ns
302    
303     sub item ($$) {
304     ## Update the sorted content attribute name list
305     my $list = ${$${$_[0]}}->{manakai_content_attribute_list};
306     my $attrs = ${$${$_[0]}}->{attributes};
307     unless (defined $list) {
308     $list = [];
309     for my $ns (sort {$a cmp $b} keys %{$attrs}) {
310     push @$list, map {[$ns => $_]} sort {$a cmp $b} keys %{$attrs->{$ns}};
311     }
312     ${$${$_[0]}}->{manakai_content_attribute_list} = $list;
313     }
314    
315     my $index = 0+$_[1];
316     return $attrs->{$list->[$index]->[0]}->{$list->[$index]->[1]};
317     } # item
318    
319     sub remove_named_item ($$) {
320     my $el = $${$_[0]};
321     local $Error::Depth = $Error::Depth + 1;
322     my $node = $el->get_attribute_node ($_[1]);
323     unless ($node) {
324     local $Error::Depth = $Error::Depth - 1;
325     report Message::DOM::DOMException
326     -object => $_[0],
327     -type => 'NOT_FOUND_ERR',
328     -subtype => 'NOT_CHILD_ERR';
329     }
330     return $el->remove_attribute_node ($node);
331     } # remove_named_item
332    
333     sub remove_named_item_ns ($$) {
334     my $el = $${$_[0]};
335     local $Error::Depth = $Error::Depth + 1;
336     my $node = $el->get_attribute_node_ns ($_[1], $_[2]);
337     unless ($node) {
338     local $Error::Depth = $Error::Depth - 1;
339     report Message::DOM::DOMException
340     -object => $_[0],
341     -type => 'NOT_FOUND_ERR',
342     -subtype => 'NOT_CHILD_ERR';
343     }
344     return $el->remove_attribute_node ($node);
345     } # remove_named_item_ns
346    
347     sub set_named_item ($$) {
348     if ($_[1]->node_type != 2) { # ATTRIBUTE_NODE
349     report Message::DOM::DOMException
350     -object => $_[0],
351     -type => 'HIERARCHY_REQUEST_ERR',
352     -subtype => 'CHILD_NODE_TYPE_ERR';
353     }
354    
355     local $Error::Depth = $Error::Depth + 1;
356     return $${$_[0]}->set_attribute_node ($_[1]);
357     } # set_named_item
358    
359     sub set_named_item_ns ($$) {
360     if ($_[1]->node_type != 2) { # ATTRIBUTE_NODE
361     report Message::DOM::DOMException
362     -object => $_[0],
363     -type => 'HIERARCHY_REQUEST_ERR',
364     -subtype => 'CHILD_NODE_TYPE_ERR';
365     }
366    
367     local $Error::Depth = $Error::Depth + 1;
368     return $${$_[0]}->set_attribute_node_ns ($_[1]);
369     } # set_named_item_ns
370    
371     sub EXISTS ($$) {
372     local $Error::Depth = $Error::Depth + 1;
373     return defined ($_[0]->get_named_item ($_[1]));
374     } # EXISTS
375    
376     sub FIRSTKEY ($) {
377     local $Error::Depth = $Error::Depth + 1;
378     my $node = $_[0]->item (0);
379     ${$${$_[0]}}->{manakai_hash_position} = 1;
380     return $node ? $node->node_name : undef;
381     } # FIRSTKEY
382    
383     sub NEXTKEY ($) {
384     my $i = ${$${$_[0]}}->{manakai_hash_position}++;
385     my $node = $_[0]->item ($i);
386     return $node ? $node->node_name : undef;
387     } # NEXTKEY
388    
389     sub SCALAR ($) {
390     local $Error::Depth = $Error::Depth + 1;
391     return $${$_[0]}->has_attributes;
392     } # SCALAR
393    
394     package Message::DOM::NamedNodeMap::AttrMap::Array;
395     push our @ISA, 'Tie::Array';
396    
397     sub DELETE ($$) {
398     my $item = $_[0]->item ($_[1]);
399     if ($item) {
400     local $Error::Depth = $Error::Depth + 1;
401     return $_[0]->remove_named_item_ns
402     ($item->namespace_uri, $item->manakai_local_name);
403     } else {
404     return undef;
405     }
406     } # DELETE
407    
408     sub EXISTS ($$) {
409     return ($_[1] < $_[0]->length);
410     } # EXISTS
411    
412     *FETCH = \&Message::DOM::NamedNodeMap::AttrMap::item;
413    
414     *FETCHSIZE = \&Message::DOM::NamedNodeMap::AttrMap::length;
415    
416     sub STORESIZE ($) {
417     local $Error::Depth = $Error::Depth + 1;
418     my $length = $_[0]->length;
419     if ($length > $_[1]) {
420     for (my $i = $length - 1; $i >= $_[1]; $i--) {
421     my $item = $_[0]->item ($i);
422     $_[0]->remove_named_item_ns
423     ($item->namespace_uri, $item->manakai_local_name);
424     }
425     }
426     } # STORESIZE
427    
428     sub TIEARRAY ($$) { bless \\$${$_[1]}, __PACKAGE__ }
429    
430     package Message::IF::NamedNodeMap;
431    
432     =head1 LICENSE
433    
434     Copyright 2007 Wakaba <w@suika.fam.cx>
435    
436     This program is free software; you can redistribute it and/or
437     modify it under the same terms as Perl itself.
438    
439     =cut
440    
441     1;
442     ## $Date: 2007/06/17 13:37:40 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24