File Coverage

blib/lib/XML/XSH2/Iterators.pm
Criterion Covered Total %
statement 8 144 5.5
branch 0 72 0.0
condition 0 21 0.0
subroutine 3 32 9.3
pod 0 24 0.0
total 11 293 3.7


line stmt bran cond sub pod time code
1             # $Id: Iterators.pm,v 2.2 2007-01-02 22:03:22 pajas Exp $
2              
3             package XML::XSH2::Iterators;
4              
5             $VERSION='2.2.8'; # VERSION TEMPLATE
6              
7             #namespace ???
8             #attribute ??
9              
10             sub create_iterator {
11 0     0 0   my ($class,$node,$axis,$filter)=@_;
12 0           my $iterator;
13              
14 0 0         die "Unsupported or unknown axis $axis\n"
15             unless $class->can("iterate_$axis");
16              
17 0 0         if ($class->can("init_$axis")) {
18 0           $node=&{"init_$axis"}($node);
  0            
19             }
20 0 0         return undef unless defined $node;
21              
22 0           $iterator= XML::XSH2::FilteredIterator->new($node, $filter);
23 0           $iterator->iterator_function(\&{"iterate_$axis"});
  0            
24 0 0         $iterator->first_filtered() || return undef;
25 0           return $iterator;
26             }
27              
28             sub iterate_self {
29 0     0 0   return undef; # the most trivial iterator :-)
30             }
31              
32             sub init_child {
33 0     0 0   my ($node)=@_;
34 0           return $node->firstChild;
35             }
36              
37             sub iterate_child { # iteration must start at the first child!
38 0     0 0   my ($iter, $dir) = @_;
39 0 0         if ( $dir < 0 ) {
40 0           return $iter->{CURRENT}->previousSibling;
41             } else {
42 0           return $iter->{CURRENT}->nextSibling;
43             }
44             }
45              
46             sub init_following_sibling {
47 0     0 0   my ($node)=@_;
48 0           return $node->nextSibling();
49             }
50              
51             sub iterate_following_sibling {
52 0     0 0   my ($iter, $dir) = @_;
53 0 0         if ( $dir < 0 ) {
54 0 0         if ($iter->{FIRST}->isSameNode( $iter->{CURRENT}->previousSibling )) {
55 0           return undef;
56             }
57 0           return $iter->{CURRENT}->previousSibling;
58             } else {
59 0           return $iter->{CURRENT}->nextSibling;
60             }
61             }
62              
63              
64             sub init_preceding_sibling {
65 0     0 0   my ($node)=@_;
66 0           return $node->nextSibling();
67             }
68              
69             sub iterate_preceding_sibling {
70 0     0 0   my ($iter, $dir) = @_;
71 0 0         if ( $dir < 0 ) {
72 0 0         if ($iter->{FIRST}->isSameNode( $iter->{CURRENT}->nextSibling )) {
73 0           return undef;
74             }
75 0           return $iter->{CURRENT}->nextSibling;
76             } else {
77 0           return $iter->{CURRENT}->previousSibling;
78             }
79             }
80              
81             sub iterate_ancestor_or_self {
82 0     0 0   my ($iter, $dir) = @_;
83 0 0         if ( $dir < 0 ) {
84 0           my $node = undef;
85 0 0         return undef if $iter->{CURRENT}->isSameNode( $iter->{FIRST} );
86 0           $node=$iter->{FIRST};
87 0   0       while ($node->parentNode and
88             not($node->parentNode->isSameNode($iter->{CURRENT}))) {
89 0           $node=$node->parentNode;
90             }
91 0           return $node;
92             } else {
93 0           return $iter->{CURRENT}->parentNode;
94             }
95             }
96              
97             sub init_ancestor {
98 0     0 0   my ($node)=@_;
99 0           return $node->parentNode();
100             }
101             *iterate_ancestor = *iterate_ancestor_or_self;
102              
103             *init_parent = *init_ancestor;
104             *iterate_parent = *iterate_ancestor_or_self;
105              
106             sub iterate_descendant_or_self {
107 0     0 0   my $iter = shift;
108 0           my $dir = shift;
109 0 0         if ( $dir < 0 ) {
110 0 0         return undef if $iter->{CURRENT}->isSameNode( $iter->{FIRST} );
111 0           return get_prev_node($iter->{CURRENT});
112             } else {
113 0           return get_next_node($iter->{CURRENT},$iter->{FIRST});
114             }
115 0           return $node;
116             }
117              
118             sub init_descendant {
119 0     0 0   my ($node)=@_;
120 0           return $node->firstChild;
121             }
122             sub iterate_descendant { # iteration must start at the first child!
123 0     0 0   my $iter = shift;
124 0           my $dir = shift;
125 0 0         if ( $dir < 0 ) {
126 0 0         return undef if $iter->{CURRENT}->isSameNode( $iter->{FIRST} );
127 0           return get_prev_node($iter->{CURRENT});
128             } else {
129 0           return get_next_node($iter->{CURRENT},$iter->{FIRST}->parentNode);
130             }
131             }
132              
133             sub iterate_following_or_self {
134 0     0 0   my $iter = shift;
135 0           my $dir = shift;
136 0 0         if ( $dir < 0 ) {
137 0 0         return undef if $iter->{CURRENT}->isSameNode( $iter->{FIRST} );
138 0           return get_prev_node($iter->{CURRENT});
139             } else {
140 0           return get_next_node($iter->{CURRENT});
141             }
142             }
143              
144             sub iterate_preceding_or_self {
145 0     0 0   my $iter = shift;
146 0           my $dir = shift;
147 0 0         if ( $dir < 0 ) {
148 0 0         return undef if $iter->{CURRENT}->isSameNode( $iter->{FIRST} );
149 0           return get_next_node($iter->{CURRENT});
150             } else {
151 0           return get_prev_node($iter->{CURRENT});
152             }
153             }
154              
155             sub init_following {
156 0     0 0   return get_next_node($_[0]);
157             }
158             *iterate_following = *iterate_following_or_self;
159              
160             sub init_preceding {
161 0     0 0   return get_prev_node($_[0]);
162             }
163             *iterate_preceding = *iterate_preceding_or_self;
164              
165             sub init_first_descendant {
166 0     0 0   return $_[0]->firstChild;
167             }
168              
169             sub iterate_first_descendant_or_self {
170 0     0 0   my ($iter, $dir) = @_;
171              
172 0 0         if ( $dir < 0 ) {
173 0 0         if ($iter->{FIRST}->isSameNode( $iter->{CURRENT} )) {
174 0           return undef;
175             }
176 0           return $iter->{CURRENT}->parent;
177             } else {
178 0           return $iter->{CURRENT}->firstChild;
179             }
180             }
181             sub iterate_first_descendant {
182 0     0 0   iterate_first_descendant_or_self(@_);
183             }
184             #*iterate_first_descendant = *iterate_first_descendant_or_self;
185              
186             sub init_last_descendant {
187 0     0 0   return $_[0]->lastChild;
188             }
189             *iterate_last_descendant = *iterate_last_descendant_or_self;
190              
191             sub iterate_last_descendant_or_self {
192 0     0 0   my ($iter, $dir) = @_;
193 0 0         if ( $dir < 0 ) {
194 0 0         if ($iter->{FIRST}->isSameNode( $iter->{CURRENT} )) {
195 0           return undef;
196             }
197 0           return $iter->{CURRENT}->parent;
198             } else {
199 0           return $iter->{CURRENT}->lastChild;
200             }
201             }
202              
203              
204             #STATIC
205             sub get_prev_node {
206 0     0 0   my ($node) = @_;
207 0 0         if ($node->previousSibling) {
208 0           $node = $node->previousSibling;
209 0 0         if ($node->hasChildNodes) {
210 0           return $node->lastChild;
211             } else {
212 0           return $node;
213             }
214             }
215 0           return $node->parentNode;
216             }
217              
218             #STATIC
219             sub get_next_node {
220 0     0 0   my ($node,$stop) = @_;
221              
222 0 0         if ( $node->hasChildNodes ) {
223 0           return $node->firstChild;
224             } else {
225 0           while ($node) {
226 0 0 0       return undef if ($stop and $node->isSameNode($stop) or
      0        
227             not $node->parentNode);
228 0 0         return $node->nextSibling if $node->nextSibling;
229 0           $node = $node->parentNode;
230             }
231 0           return undef;
232             }
233             }
234              
235             package XML::XSH2::FilteredIterator;
236 8     8   58 use strict;
  8         16  
  8         351  
237             BEGIN {
238 8     8   99 local $^W=0; # suppress warning with perl5.8.2
239 8         4283 require XML::LibXML::Iterator;
240             };
241 8     8   47079 use base qw(XML::LibXML::Iterator);
  8         16  
  8         4069  
242              
243             sub new {
244 0     0     my ($class,$node,$filter)=@_;
245 0   0       $class = ref($class) || $class;
246 0           my $self = $class->SUPER::new($node);
247 0           $self->{FILTER}=$filter;
248 0           return $self;
249             }
250              
251             sub filter {
252 0     0     my $self=shift;
253 0 0         if (@_) { $self->{FILTER}=$_[0]; }
  0            
254 0           return $self->{FILTER};
255             }
256              
257             sub first_filtered {
258 0     0     my $self=shift;
259 0           my ($node)=@_;
260 0           my $filter=$self->filter;
261 0 0         $self->first(@_) || return undef;
262 0 0         if (ref($filter) eq 'CODE') {
263 0   0       while ($self->current() and not &$filter($self->current())) {
264 0 0         $self->next() || return undef;
265             }
266             }
267 0           return $self->current();
268             }
269              
270             sub next {
271 0     0     my $self=shift;
272 0           my ($node)=@_;
273 0           my $filter=$self->filter;
274 0 0         $self->SUPER::next() || return undef;
275 0   0       while ($self->current() and not &$filter($self->current())) {
276 0 0         $self->SUPER::next() || return undef;
277             }
278 0           return $self->current();
279             }
280              
281             sub prev {
282 0     0     my $self=shift;
283 0           my ($node)=@_;
284 0           my $filter=$self->filter;
285 0 0         $self->SUPER::prev() || return undef;
286 0   0       while ($self->current() and not &$filter($self->current())) {
287 0 0         $self->SUPER::prev() || return undef;
288             }
289 0           return $self->current();
290             }
291              
292             1;
293