File Coverage

blib/lib/XML/LibXML/Iterator.pm
Criterion Covered Total %
statement 102 138 73.9
branch 34 58 58.6
condition 8 20 40.0
subroutine 13 22 59.0
pod 14 14 100.0
total 171 252 67.8


line stmt bran cond sub pod time code
1             #
2             #
3             package XML::LibXML::Iterator;
4             $XML::LibXML::Iterator::VERSION = '1.05';
5 2     2   72649 use strict;
  2         22  
  2         68  
6              
7 2     2   1069 use XML::NodeFilter qw(:results);
  2         3788  
  2         236  
8              
9 2     2   15 use vars qw($VERSION);
  2         4  
  2         235  
10              
11             $VERSION = '1.04';
12              
13             use overload
14 0     0   0 '++' => sub { $_[0]->nextNode(); $_[0]; },
  0         0  
15 0     0   0 '--' => sub { $_[0]->previousNode(); $_[0]; },
  0         0  
16 0 0   0   0 '<>' => sub { return wantarray ? $_[0]->_get_all() : $_[0]->nextNode(); },
17 2     2   1365 ;
  2         1286  
  2         46  
18              
19             sub new
20             {
21 7     7 1 2081 my $class = shift;
22 7         12 my $node = shift;
23              
24 7 50       18 return undef unless defined $node;
25              
26 7         14 my $self = bless {}, $class;
27              
28 7         53 $self->{FIRST} = $node;
29              
30             # $self->first;
31              
32 7         14 $self->{CURRENT} = undef;
33 7         11 $self->{INDEX} = -1;
34              
35 7         16 $self->{ITERATOR} = \&default_iterator;
36              
37 7         14 $self->{FILTERS} = [];
38              
39 7         21 return $self;
40             }
41              
42             sub iterator_function
43             {
44 0     0 1 0 my $self = shift;
45 0         0 my $func = shift;
46              
47 0 0 0     0 return if defined $func and ref($func) ne "CODE";
48              
49 0         0 $self->first;
50 0 0       0 if ( defined $func )
51             {
52 0         0 $self->{ITERATOR} = $func;
53             }
54             else
55             {
56 0         0 $self->{ITERATOR} = \&default_iterator;
57             }
58             }
59              
60             sub set_filter
61             {
62 0     0 1 0 my $self = shift;
63 0         0 $self->{FILTERS} = [@_];
64             }
65              
66             sub add_filter
67             {
68 0     0 1 0 my $self = shift;
69 0         0 push @{ $self->{FILTERS} }, @_;
  0         0  
70             }
71              
72 18     18 1 88 sub current { return $_[0]->{CURRENT}; }
73 0     0 1 0 sub index { return $_[0]->{INDEX}; }
74              
75 20     20 1 88 sub next { return $_[0]->nextNode(); }
76 0     0 1 0 sub previous { return $_[0]->previousNode(); }
77              
78             sub nextNode
79             {
80 41     41 1 141 my $self = shift;
81 41         53 my @filters = @{ $self->{FILTERS} };
  41         78  
82 41         51 my $node = undef;
83              
84 41 100       81 if ( $self->{INDEX} != -1 )
85             {
86 36         42 my $fv = FILTER_SKIP;
87 36 50       75 unless ( scalar @filters > 0 )
88             {
89 36         41 $fv = FILTER_DECLINED;
90             }
91              
92 36         46 while (1)
93             {
94 36         64 $node = $self->{ITERATOR}->( $self, 1 );
95 36 100       67 last unless defined $node;
96 30         51 foreach my $f (@filters)
97             {
98 0         0 $fv = $f->accept_node($node);
99 0 0       0 last if $fv;
100             }
101 30 50 33     94 last if $fv == FILTER_ACCEPT or $fv == FILTER_DECLINED;
102             }
103             }
104             else
105             {
106 5         22 $node = $self->first();
107             }
108              
109 41 100       72 if ( defined $node )
110             {
111 35         70 $self->{CURRENT} = $node;
112 35 100       223 if ( $node->isSameNode( $self->{FIRST} ) )
113             {
114 5         10 $self->{INDEX} = 0;
115             }
116             else
117             {
118 30         42 $self->{INDEX}++;
119             }
120             }
121              
122 41         124 return $node;
123             }
124              
125             sub previousNode
126             {
127 12     12 1 58 my $self = shift;
128 12         15 my @filters = @{ $self->{FILTERS} };
  12         23  
129 12         16 my $node = undef;
130 12         14 my $fv = FILTER_SKIP;
131 12 50       26 unless ( scalar @filters > 0 )
132             {
133 12         25 $fv = FILTER_DECLINED;
134             }
135 12         19 while (1)
136             {
137 12         18 $node = $self->{ITERATOR}->( $self, -1 );
138 12 100       25 last unless defined $node;
139 10         16 foreach my $f (@filters)
140             {
141 0         0 $fv = $f->accept_node($node);
142 0 0       0 last if $fv;
143             }
144 10 50 33     36 last if $fv == FILTER_ACCEPT or $fv == FILTER_DECLINED;
145             }
146              
147 12 100       21 if ( defined $node )
148             {
149 10         26 $self->{CURRENT} = $node;
150 10         81 $self->{INDEX}--;
151             }
152              
153 12         20 return $node;
154             }
155              
156             sub first
157             {
158 8     8 1 25 my $self = shift;
159 8 50       18 if ( scalar @_ )
160             {
161 0         0 $self->{FIRST} = shift;
162             }
163              
164 8         16 $self->{CURRENT} = $self->{FIRST};
165              
166             # this logic is required if the node is not allowed to be shown
167 8 50       19 my @filters = @{ $self->{FILTERS} || [] };
  8         69  
168 8         17 my $fv = FILTER_DECLINED;
169              
170 8         27 foreach my $f (@filters)
171             {
172 0         0 $fv = $f->accept_node( $self->{CURRENT} );
173 0 0       0 last if $fv;
174             }
175              
176 8   50     35 $fv ||= FILTER_ACCEPT;
177              
178 8 50       18 unless ( $fv == FILTER_ACCEPT )
179             {
180 0         0 return undef;
181             }
182              
183 8         14 $self->{INDEX} = 0;
184 8         18 return $self->current;
185             }
186              
187             sub last
188             {
189 2     2 1 10 my $self = shift;
190 2         16 while ( $self->next ) { }
191 2         5 return $self->current;
192             }
193              
194             sub iterate
195             {
196 1     1 1 30 my $self = shift;
197 1         3 my $function = shift;
198 1 50 33     7 return unless defined $function and ref($function) eq 'CODE';
199 1         3 my $rv;
200 1         7 my $node = $self->first;
201 1         24 while ($node)
202             {
203 6         64 $rv = $function->( $self, $node );
204 6         19 $node = $self->next;
205             }
206 1         2 return $rv;
207             }
208              
209             sub default_iterator
210             {
211 48     48 1 66 my $self = shift;
212 48         69 my $dir = shift;
213 48         59 my $node = undef;
214              
215 48 100       83 if ( $dir < 0 )
216             {
217             return undef
218             if $self->{CURRENT}->isSameNode( $self->{FIRST} )
219 12 100 66     43 and $self->{INDEX} <= 0;
220              
221 10         29 $node = $self->{CURRENT}->previousSibling;
222 10 100       28 return $self->{CURRENT}->parentNode unless defined $node;
223              
224 6         17 while ( $node->hasChildNodes )
225             {
226 0         0 $node = $node->lastChild;
227             }
228             }
229             else
230             {
231 36 50       58 if ( defined $self->{CURRENT} )
232             {
233             return undef
234             if $self->{CURRENT}->isSameNode( $self->{FIRST} )
235 36 50 66     120 and $self->{INDEX} > 0;
236              
237 36 100       85 if ( $self->{CURRENT}->hasChildNodes )
238             {
239 12         36 $node = $self->{CURRENT}->firstChild;
240             }
241             else
242             {
243 24         58 $node = $self->{CURRENT}->nextSibling;
244 24         59 my $pnode = $self->{CURRENT}->parentNode;
245 24         65 while ( not defined $node )
246             {
247 24 100       141 last unless defined $pnode;
248 18         36 $node = $pnode->nextSibling;
249 18 50       62 $pnode = $pnode->parentNode unless defined $node;
250             }
251             }
252             }
253             else
254             {
255 0         0 $self->{CURRENT} = $self->{FIRST};
256 0         0 $node = $self->{CURRENT};
257             }
258             }
259              
260 42         232 return $node;
261             }
262              
263             # helper function for the <> operator
264             # returns all nodes that have not yet been accessed
265             sub _get_all
266             {
267 0     0     my $self = shift;
268 0           my @retval = ();
269 0           my $node;
270 0           while ( $node = $self->next() )
271             {
272 0           push @retval, $node;
273             }
274 0           return @retval;
275             }
276              
277             1;
278              
279             __END__