File Coverage

blib/lib/XML/LibXML/Iterator.pm
Criterion Covered Total %
statement 12 138 8.7
branch 0 58 0.0
condition 0 20 0.0
subroutine 4 22 18.1
pod 11 14 78.5
total 27 252 10.7


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