File Coverage

lib/XML/Schema/Particle/Choice.pm
Criterion Covered Total %
statement 43 60 71.6
branch 11 38 28.9
condition 3 8 37.5
subroutine 7 8 87.5
pod 1 5 20.0
total 65 119 54.6


line stmt bran cond sub pod time code
1             #============================================================= -*-perl-*-
2             #
3             # XML::Schema::Particle::Choice.pm
4             #
5             # DESCRIPTION
6             # Subclassed particle to contain a choice of other particles
7             # which can be matched in any order.
8             #
9             # AUTHOR
10             # Andy Wardley
11             #
12             # COPYRIGHT
13             # Copyright (C) 2001 Canon Research Centre Europe Ltd.
14             # All Rights Reserved.
15             #
16             # This module is free software; you can redistribute it and/or
17             # modify it under the same terms as Perl itself.
18             #
19             # REVISION
20             # $Id: Choice.pm,v 1.1.1.1 2001/08/29 14:30:17 abw Exp $
21             #
22             #========================================================================
23              
24             package XML::Schema::Particle::Choice;
25              
26 1     1   452 use strict;
  1         2  
  1         31  
27 1     1   5 use base qw( XML::Schema::Particle );
  1         1  
  1         423  
28 1     1   6 use vars qw( $VERSION $DEBUG $ERROR $ETYPE );
  1         1  
  1         769  
29              
30             $VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
31             $DEBUG = 0 unless defined $DEBUG;
32             $ERROR = '';
33             $ETYPE = 'ChoiceParticle';
34              
35              
36             #------------------------------------------------------------------------
37             # init()
38             #
39             # Called automatically by base class new() method.
40             #------------------------------------------------------------------------
41              
42             sub init {
43 3     3 1 6 my ($self, $config) = @_;
44              
45 3 50       11 $self->TRACE("config => ", $config) if $DEBUG;
46              
47             my $choice = $config->{ choice }
48 3   50     11 || return $self->error("no choice defined");
49              
50 3 50       9 return $self->error("choice expects an array ref")
51             unless ref $choice eq 'ARRAY';
52              
53 3         5 my ($p, @particles);
54             my $factory = $self->{ _FACTORY } = $config->{ FACTORY }
55 3   33     22 || $XML::Schema::FACTORY;
56              
57 3         5 foreach $p (@$choice) {
58 6         22 my $particle = $factory->create( particle => $p );
59 6 100       14 unless (defined $particle) {
60 1         5 return $self->error("error in choice item ", scalar @particles,
61             ': ', $factory->error());
62             }
63            
64 5         14 push(@particles, $particle);
65             }
66 2         7 $self->{ particles } = \@particles;
67 2         3 $self->{ type } = 'choice';
68              
69 2 50       10 $self->constrain($config)
70             || return;
71              
72 2         22 return $self;
73             }
74              
75              
76             sub particles {
77 1     1 0 3 my $self = shift;
78             return $self->{ particles }
79 1   33     11 || $self->error("empty particle choice");
80             }
81              
82              
83             sub start {
84 1     1 0 6 my $self = shift;
85              
86 1 50       5 $self->TRACE() if $DEBUG;
87              
88 1         3 $self->{ occurs } = 0;
89 1         3 $self->{ _pnow } = undef;
90              
91 1         5 return 1;
92             }
93              
94              
95             #------------------------------------------------------------------------
96             # element($name)
97             #
98             # Iterates through the list of particles to find one which can accept
99             # a <$name> element. Each particle is started via a call to start()
100             # (e.g. to initialise a sequence particle) and then its element($name)
101             # method is called. If it returns a true value (an element ref) then
102             # that particle is latched in as the current target particle (_pnow)
103             # and will be given first refusal on subsequent element() calls. If
104             # the particle does not accept the element() call then its end()
105             # method is called and the process continues onto the next particle in
106             # the choice.
107             #------------------------------------------------------------------------
108              
109             sub element {
110 1     1 0 2 my ($self, $name) = @_;
111 1         8 my $particles = $self->{ particles };
112 1         3 my $pnow = $self->{ _pnow };
113 1         8 my $element;
114              
115 1 50       4 $self->TRACE("name => ", $name) if $DEBUG;
116              
117             # if there is an active particle (i.e. one previously selected by
118             # this element() method) then we first give it the opportunity to
119             # handle this new element.
120              
121 1 50       3 if ($pnow) {
122             # true value returned indicates success
123 0 0       0 return $element
124             if ($element = $pnow->element($name));
125              
126             # undefined value returned indicates error
127 0 0       0 return $self->error($pnow->error())
128             unless defined $element;
129              
130             # defined but false value (0) indicates particle
131             # declined to accept element but was otherwise
132             # satisfied according to min/max constraints so
133             # we move on to try the next particle
134 0         0 $self->TRACE("ending $pnow because it declined");
135 0 0       0 $pnow->end()
136             || return $self->error($pnow->error());
137              
138 0         0 my $occurs = ++$self->{ occurs };
139              
140             # if we've reached our max occurences then we must decline
141             return $self->decline("unexpected <$name> element")
142 0 0       0 if $occurs >= $self->{ max };
143             }
144              
145             # iterate through each particle to see if any can accept it
146 1         2 foreach $pnow (@$particles) {
147 2 50       12 $pnow->start()
148             || return $self->error($pnow->error());
149              
150 2 100       7 if ($element = $pnow->element($name)) {
151             # save reference to active particle for next time
152 1         2 $self->{ _pnow } = $pnow;
153 1         4 return $element;
154             }
155              
156             # ignore errors that are likely to be "min expected"
157 1         8 $pnow->end();
158             }
159              
160             # didn't find anything to handle this element so we return an
161             # error or decline depending on us having any minimum occurence
162             # requirements
163             return $self->{ occurs } >= $self->{ min }
164 0 0         ? $self->decline("unexpected <$name> element")
165             : $self->error("unexpected <$name> element");
166             }
167              
168              
169              
170             #------------------------------------------------------------------------
171             # end()
172             #
173             # If we've got an active particle on the go then we call its end() method
174             # to give it a chance to perform its own sanity check. Then we go on
175             # to inspect our own min/max constraints and return an appropriate
176             # true (ok) or false (not ok) value.
177             #------------------------------------------------------------------------
178              
179             sub end {
180 0     0 0   my $self = shift;
181 0           my $pnow = $self->{ _pnow };
182              
183 0 0         $self->TRACE if $DEBUG;
184              
185             # if there is an active particle (i.e. one previously selected by
186             # this element() method) then we must end() it and make sure it is
187             # a happy particle
188 0 0         if ($pnow) {
189 0 0         $pnow->end()
190             || return $self->error($pnow->error());
191              
192             # chalk up another one
193 0           ++$self->{ occurs };
194             }
195              
196             # make sure that we're a happy particle
197 0           my ($min, $max, $occurs) = @$self{ qw( min max occurs ) };
198              
199 0 0         return $self->error("minimum of $min choice expected")
200             if $occurs < $min;
201              
202 0 0         return $self->error("maximum of $max choice exceeded")
203             if $occurs > $max;
204              
205 0           return 1;
206             }
207              
208            
209             1;
210              
211              
212              
213              
214              
215