File Coverage

blib/lib/XML/LibXML/Iterator.pm
Criterion Covered Total %
statement 105 141 74.4
branch 34 58 58.6
condition 8 20 40.0
subroutine 14 23 60.8
pod 14 14 100.0
total 175 256 68.3


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