File Coverage

lib/XML/Schema/Type/Builtin.pm
Criterion Covered Total %
statement 392 398 98.4
branch 69 80 86.2
condition 37 42 88.1
subroutine 108 110 98.1
pod n/a
total 606 630 96.1


line stmt bran cond sub pod time code
1             #============================================================= -*-perl-*-
2             #
3             # XML::Schema::Type::Builtin
4             #
5             # DESCRIPTION
6             # Definitions of the various simple types built in to XML Schema.
7             #
8             # AUTHOR
9             # Andy Wardley
10             #
11             # COPYRIGHT
12             # Copyright (C) 2001 Canon Research Centre Europe Ltd.
13             # All Rights Reserved.
14             #
15             # This module is free software; you can redistribute it and/or
16             # modify it under the same terms as Perl itself.
17             #
18             # REVISION
19             # $Id: Builtin.pm,v 1.2 2001/12/20 13:26:27 abw Exp $
20             #
21             # TODO
22             # Not yet implemented
23             # * uriReference - consult RFC 2396 and RFC 2732
24             # * ID - should access document instance to store ID usage
25             # * IDREF - should access document instance to check ID exists
26             # * IDREFS - as above, and requires list functionality
27             # * ENTITY - should access document instance to check ENTITY declared
28             # * ENTITIES - as above, and requires list functionality
29             # * NMTOKENS - requires list
30             # * NOTATION - need document instance to check NOTATION defined
31             #
32             # Incomplete:
33             # * float/double - need validation of mantissa length
34             # * long/unsignedLong - can't validate numbers which exceed bounds
35             # * QName - needs namespace resolution against prefix
36             #
37             #========================================================================
38              
39             package XML::Schema::Type::Builtin;
40              
41 28     28   147 use strict;
  28         49  
  28         942  
42 28     28   971 use XML::Schema::Type::Simple;
  28         55  
  28         839  
43 28     28   139 use vars qw( $VERSION $DEBUG );
  28         166  
  28         8844  
44              
45             $VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
46             $DEBUG = 0 unless defined $DEBUG;
47              
48              
49             #========================================================================
50             # Primitive datatypes
51             #
52             # Based on XML Schema Part 2: Datatypes, W3C Candidate Recommendation,
53             # 24 October 2000, section 3.2.
54             #========================================================================
55              
56             #------------------------------------------------------------------------
57             # string
58             #------------------------------------------------------------------------
59              
60             package XML::Schema::Type::string;
61 28     28   361 use base qw( XML::Schema::Type::Simple );
  28         55  
  28         2665  
62 28     28   140 use vars qw( $ERROR );
  28         51  
  28         1593  
63              
64              
65             #------------------------------------------------------------------------
66             # boolean
67             #------------------------------------------------------------------------
68              
69             package XML::Schema::Type::boolean;
70 28     28   365 use base qw( XML::Schema::Type::Simple );
  28         63  
  28         2104  
71 28     28   149 use vars qw( $ERROR @FACETS );
  28         48  
  28         2185  
72              
73             @FACETS = (
74             whiteSpace => 'collapse',
75             enumeration => {
76             value => [ 'true', 'false' ],
77             errmsg => 'value is not boolean (true/false)',
78             },
79             );
80              
81              
82             #------------------------------------------------------------------------
83             # double
84             # IEEE double precision 64-bit floating point number.
85             #------------------------------------------------------------------------
86              
87             package XML::Schema::Type::double;
88 28     28   134 use base qw( XML::Schema::Type::Simple );
  28         49  
  28         2408  
89 28     28   158 use vars qw( $ERROR @FACETS );
  28         44  
  28         16720  
90              
91             @FACETS = (
92             whiteSpace => 'collapse',
93             \&prepare,
94             );
95              
96             sub prepare {
97 27     27   34 my ($instance, $type) = @_;
98 27         45 my $value = $instance->{ value };
99              
100 27 100       68 return $type->error('value is empty')
101             unless length $value;
102              
103 24 100       151 return $type->error("value is not a valid $type->{ name }")
104             unless $value =~ /
105             ^
106             ([+-])? # sign ($1)
107             (?:
108             (INF) # infinity ($2)
109             | (NaN) # not a number ($3)
110             | (\d+(?:\.\d+)?) # mantissa ($4)
111             (?:[eE] # exponent
112             ([+-])? # sign ($5)
113             (\d+) # value ($6)
114             )?
115             )
116             $
117             /x;
118              
119 19   100     133 $instance->{ sign } = $1 || '';
120 19 100       55 $instance->{ infinity } = $2 ? 1 : 0;
121 19 100       67 $instance->{ nan } = $3 ? 1 : 0;
122 19   100     94 $instance->{ mantissa } = $4 || '';
123 19   100     105 $instance->{ exp_sign } = $5 || '';
124 19   100     81 $instance->{ exp_value } = $6 || '';
125 19   100     159 $instance->{ exponent } = ($5 || '') . ($6 || '');
      100        
126              
127             # TODO: need to test bounds of mantissa ( < 2^53 )
128              
129 19         32 my $exp = $instance->{ exponent };
130 19 100 100     93 return $type->error('double exponent is not valid (-1075 <= e <= 970)')
      66        
131             if $exp && ($exp < -1075 || $exp > 970);
132            
133 17         68 return 1;
134             }
135              
136              
137             #------------------------------------------------------------------------
138             # float
139             # IEEE single precision 32-bit floating point number. Derived from
140             # double with an additional constraint check on the bounds of the
141             # mantissa and exponent.
142             #------------------------------------------------------------------------
143              
144             package XML::Schema::Type::float;
145 28     28   152 use base qw( XML::Schema::Type::double );
  28         53  
  28         17575  
146 28     28   186 use vars qw( $ERROR @FACETS );
  28         47  
  28         4183  
147              
148             @FACETS = (
149             \&prepare,
150             );
151              
152             sub prepare {
153 11     11   19 my ($instance, $type) = @_;
154              
155             # TODO: need to test bounds of mantissa ( < 2^24 )
156              
157 11         22 my $exp = $instance->{ exponent };
158              
159 11 100 100     93 return $type->error('float exponent is not valid (-149 <= e <= 104)')
      66        
160             if $exp && ($exp < -149 || $exp > 104);
161              
162 9         39 return 1;
163             }
164              
165              
166             #------------------------------------------------------------------------
167             # decimal
168             # Arbitrary precision decimal number.
169             #------------------------------------------------------------------------
170              
171             package XML::Schema::Type::decimal;
172 28     28   174 use base qw( XML::Schema::Type::Simple );
  28         66  
  28         2644  
173 28     28   150 use vars qw( $ERROR @FACETS );
  28         50  
  28         22979  
174              
175             @FACETS = (
176             whiteSpace => 'collapse',
177             \&prepare,
178             );
179              
180             sub prepare {
181 146     146   198 my ($instance, $type) = @_;
182 146         240 my $value = $instance->{ value };
183              
184 146 100       365 return $type->error('value is empty')
185             unless length $value;
186              
187 141 100       731 return $type->error("value is not a decimal")
188             unless $value =~ /
189             ^
190             ([+-])? # sign ($1)
191             0*(\d+) # integer ($2)
192             (?:\.(\d+)0*)? # fraction ($3)
193             $
194             /x;
195              
196 130         646 @$instance{ qw( sign integer fraction ) } = ($1, $2, $3);
197 130         272 $instance->{ scale } = length $3;
198 130         7114 $instance->{ precision } = $instance->{ scale } + length $2;
199              
200 130         623 return 1;
201             }
202              
203              
204             #------------------------------------------------------------------------
205             # timeDuration
206             # A duration of time as in the extended format as defined in [ISO 8601
207             # Date and Time Formats]. e.g. P7Y1M4DT7H3M12.8S: 7 years, 1 month, 4
208             # days, 7 hours, 3 minutes and 12.8 seconds.
209             #------------------------------------------------------------------------
210              
211             package XML::Schema::Type::timeDuration;
212 28     28   162 use base qw( XML::Schema::Type::Simple );
  28         63  
  28         2819  
213 28     28   138 use vars qw( $ERROR @FACETS );
  28         50  
  28         13100  
214              
215             @FACETS = (
216             whiteSpace => 'collapse',
217             \&prepare, # install direct call to subroutine
218             );
219              
220             sub prepare {
221 62     62   116 my ($instance, $type) = @_;
222 62         110 my $value = $instance->{ value };
223              
224 62 100       140 return $type->error('value is empty')
225             unless length $value;
226              
227 61 100       339 return $type->error("value is not a valid timeDuration")
228             unless $value =~ /
229             ^
230             (-)? # sign ($1)
231             P([^T]*) # date ($2)
232             (?:T(.+))? # time ($3)
233             $
234             /x;
235              
236 55 100 66     185 return $type->error("value must specify at least one date/time item")
237             unless length $2 or $3;
238              
239 54         136 $instance->{ sign } = $1;
240 54   100     233 $instance->{ date } = $2 || '';
241 54   100     239 $instance->{ time } = $3 || '';
242              
243             return $type->error("value contains an invalid date element")
244 54 50       338 unless $instance->{ date } =~ /
245             ^
246             (?:(\d+)Y)? # years ($1)
247             (?:(\d+)M)? # months ($2)
248             (?:(\d+)D)? # days ($3)
249             $
250             /x;
251 54         312 @$instance{ qw( years months days ) } = ($1, $2, $3);
252 54 100 66     465 $instance->{ zero_date } = ($1 || $2 || $3) ? 0 : 1;
253              
254             return $type->error("value contains an invalid time element")
255 54 50       262 unless $instance->{ time } =~ /
256             ^
257             (?:(\d+)H)? # hours ($1)
258             (?:(\d+)M)? # minutes ($2)
259             (?:(\d(?:\.\d+)?)S)? # seconds ($3)
260             $
261             /x;
262 54         215 @$instance{ qw( hours minutes seconds ) } = ($1, $2, $3);
263 54 100 66     380 $instance->{ zero_time } = ($1 || $2 || $3) ? 0 : 1;
264              
265             $instance->{ zero } = $instance->{ zero_date }
266 54   100     373 && $instance->{ zero_time };
267              
268 54         253 return 1;
269             }
270              
271            
272             #------------------------------------------------------------------------
273             # recurringDuration
274             # Note that period and duration do not affect the parser implemented in
275             # the prepare() method. Derived types that specify an alternate or
276             # truncated lexical format should implement their own prepare()
277             # method.
278             #------------------------------------------------------------------------
279              
280             package XML::Schema::Type::recurringDuration;
281 28     28   166 use base qw( XML::Schema::Type::Simple );
  28         54  
  28         2195  
282 28     28   143 use vars qw( $ERROR @FACETS );
  28         87  
  28         13337  
283              
284             @FACETS = (
285             whiteSpace => 'collapse',
286             sub { $_[1]->prepare($_[0]) }, # install hook to call object method
287             );
288              
289             sub init {
290 21     21   44 my $self = shift;
291             return undef
292 21 100       114 unless $self->SUPER::init(@_);
293 20 100       176 return $self->error('duration not defined')
294             unless $self->facet('duration');
295 18 100       61 return $self->error('period not defined')
296             unless $self->facet('period');
297 17         136 return $self;
298             }
299              
300             sub prepare {
301 10     10   16 my ($self, $instance) = @_;
302 10         16 my $value = $instance->{ value };
303              
304 10 50       25 return $self->error('value is empty')
305             unless length $value;
306              
307 10 50       81 return $self->error("value is not a valid recurringDuration")
308             unless $value =~ /
309             ^
310             ([+-])? # sign ($1)
311             (\d{2,}) # century ($2)
312             (\d{2}) - # year ($3)
313             (\d{2}) - # month ($4)
314             (\d{2}) T # day ($5)
315             (\d{2}) : # hour ($6)
316             (\d{2}) : # minute ($7)
317             (\d{2}(?:.\d+)?) # second ($8)
318             (?: # optional time zone
319             (Z) # UTC ($9)
320             | ([-+]) # sign ($10)
321             (\d{2}) : # hours ($11)
322             (\d{2}) # minutes ($12)
323             )?
324             $
325             /x;
326              
327 10         104 @$instance{ qw( sign century year month day hour minute second ) }
328             = ($1, $2, $3, $4, $5, $6, $7, $8 );
329 10 100       39 $instance->{ UTC } = $9 ? 1 : 0;
330 10         30 my $zone = $instance->{ zone } = { };
331 10         44 @$zone{ qw( sign hour minute ) } = ($10, $11, $12);
332              
333 10         62 return 1;
334             }
335              
336              
337             #------------------------------------------------------------------------
338             # binary
339             # Arbitrary binary data. Must be derived to specify encoding.
340             #------------------------------------------------------------------------
341              
342             package XML::Schema::Type::binary;
343 28     28   183 use base qw( XML::Schema::Type::Simple );
  28         68  
  28         2449  
344 28     28   157 use vars qw( $ERROR @FACETS );
  28         50  
  28         9990  
345              
346             @FACETS = (
347             whiteSpace => 'collapse',
348             );
349              
350             sub init {
351 3     3   7 my $self = shift;
352             return undef
353 3 100       13 unless $self->SUPER::init(@_);
354 2 100       17 return $self->error('encoding not defined')
355             unless $self->facet('encoding');
356 1         6 return $self;
357             }
358              
359              
360             #------------------------------------------------------------------------
361             # uriReference
362             # Uniform Resource Identifier as defined in Section 4 of [RFC 2396] and
363             # amended by [RFC 2732].
364             #------------------------------------------------------------------------
365              
366             package XML::Schema::Type::uriReference;
367 28     28   159 use base qw( XML::Schema::Type::Simple );
  28         69  
  28         2608  
368 28     28   147 use vars qw( $ERROR @FACETS );
  28         64  
  28         3082  
369              
370             @FACETS = (
371             whiteSpace => 'collapse',
372             sub { die "uriReference not yet implemented\n" },
373             );
374              
375              
376             #------------------------------------------------------------------------
377             # ENTITY
378             #------------------------------------------------------------------------
379              
380             package XML::Schema::Type::ENTITY;
381 28     28   140 use base qw( XML::Schema::Type::Simple );
  28         46  
  28         2310  
382 28     28   136 use vars qw( $ERROR @FACETS );
  28         50  
  28         4665  
383              
384             @FACETS = (
385             whiteSpace => 'collapse',
386             sub { die "ENTITY not yet implemented\n" },
387             );
388              
389              
390             #------------------------------------------------------------------------
391             # QName
392             #------------------------------------------------------------------------
393              
394             package XML::Schema::Type::QName;
395 28     28   242 use base qw( XML::Schema::Type::Simple );
  28         53  
  28         3001  
396 28     28   145 use vars qw( $ERROR @FACETS );
  28         89  
  28         8664  
397              
398             @FACETS = (
399             whiteSpace => 'collapse',
400             \&prepare,
401             );
402              
403             sub prepare {
404 5     5   9 my ($instance, $type) = @_;
405 5         10 my $value = $instance->{ value };
406              
407 5 100       17 return $type->error('value is empty')
408             unless length $value;
409              
410 4 100       29 return $type->error("value is not a valid QName")
411             unless $value =~ /
412             ^
413             (?:
414             ([a-zA-Z_][\w\-.]*?) # prefix ($1)
415             :
416             )?
417             ([a-zA-Z_][\w\-.]*?) # local ($2)
418             $
419             /x;
420              
421 3   100     18 $instance->{ prefix } = $1 || '';
422 3         12 $instance->{ local } = $2;
423              
424             # TODO: need to validate prefix to a namespace
425 3         6 $instance->{ namespace } = '???';
426              
427 3         16 return 1;
428             }
429              
430              
431              
432              
433             #========================================================================
434             # Derived datatypes
435             #
436             # Based on XML Schema Part 2: Datatypes, W3C Candidate Recommendation,
437             # 24 October 2000, section 3.3.
438             #========================================================================
439              
440             #------------------------------------------------------------------------
441             # CDATA
442             # As per string but with newlines, carriage returns and tabs converted
443             # to spaces.
444             #------------------------------------------------------------------------
445              
446             package XML::Schema::Type::CDATA;
447 28     28   157 use base qw( XML::Schema::Type::string );
  28         52  
  28         14784  
448 28     28   163 use vars qw( $ERROR @FACETS );
  28         58  
  28         2050  
449              
450             @FACETS = (
451             whiteSpace => 'replace'
452             );
453              
454              
455             #------------------------------------------------------------------------
456             # token
457             # As per CDATA but with adjacent spaces collapsed to a single space
458             # and leading and trailing spaces removed. Note derivation from
459             # string rather than CDATA.
460             #------------------------------------------------------------------------
461              
462             package XML::Schema::Type::token;
463 28     28   139 use base qw( XML::Schema::Type::string );
  28         50  
  28         12320  
464 28     28   196 use vars qw( $ERROR @FACETS );
  28         79  
  28         2141  
465              
466             @FACETS = (
467             whiteSpace => 'collapse'
468             );
469              
470              
471             #------------------------------------------------------------------------
472             # language
473             # Derived from token, with a pattern constraint to represent natural
474             # language identifiers as defined by RFC 1766.
475             #------------------------------------------------------------------------
476              
477             package XML::Schema::Type::language;
478 28     28   167 use base qw( XML::Schema::Type::token );
  28         80  
  28         14080  
479 28     28   168 use vars qw( $ERROR @FACETS );
  28         63  
  28         3354  
480              
481             @FACETS = (
482             pattern => {
483             value => '^([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]+)(-[a-zA-Z]+)*$',
484             errmsg => 'value is not a language',
485             }
486             );
487              
488              
489             #------------------------------------------------------------------------
490             # IDREFS
491             #------------------------------------------------------------------------
492              
493             package XML::Schema::Type::IDREFS;
494 28     28   147 use base qw( XML::Schema::Type::Simple );
  28         56  
  28         2395  
495 28     28   142 use vars qw( $ERROR @FACETS );
  28         54  
  28         2602  
496              
497             @FACETS = (
498             sub { die "IDREFS not yet implemented\n" },
499             );
500              
501              
502             #------------------------------------------------------------------------
503             # ENTITIES
504             #------------------------------------------------------------------------
505              
506             package XML::Schema::Type::ENTITIES;
507 28     28   145 use base qw( XML::Schema::Type::Simple );
  28         68  
  28         2343  
508 28     28   905 use vars qw( $ERROR @FACETS );
  28         54  
  28         4844  
509              
510             @FACETS = (
511             sub { die "ENTITIES not yet implemented\n" },
512             );
513              
514              
515             #------------------------------------------------------------------------
516             # NMTOKEN
517             # String matching the NMTOKEN attribute type from [XML 1.0
518             # Recommendation (Second Edition)].
519             #------------------------------------------------------------------------
520              
521             package XML::Schema::Type::NMTOKEN;
522 28     28   167 use base qw( XML::Schema::Type::token );
  28         105  
  28         15218  
523 28     28   157 use vars qw( $ERROR @FACETS );
  28         54  
  28         2388  
524              
525             @FACETS = (
526             pattern => {
527             value => '^[\w\-_.:]+$',
528             errmsg => 'value is not a valid NMTOKEN',
529             }
530             );
531              
532              
533             #------------------------------------------------------------------------
534             # NMTOKENS
535             #------------------------------------------------------------------------
536              
537             package XML::Schema::Type::NMTOKENS;
538 28     28   139 use base qw( XML::Schema::Type::Simple );
  28         61  
  28         2272  
539 28     28   154 use vars qw( $ERROR @FACETS );
  28         61  
  28         2720  
540              
541             @FACETS = (
542             sub { die "NMTOKENS not yet implemented\n" },
543             );
544              
545              
546             #------------------------------------------------------------------------
547             # Name
548             # String matching the 'Name' production of [XML 1.0 Recommendation
549             # (Second Edition)].
550             #------------------------------------------------------------------------
551              
552             package XML::Schema::Type::Name;
553 28     28   156 use base qw( XML::Schema::Type::token );
  28         56  
  28         11171  
554 28     28   185 use vars qw( $ERROR @FACETS );
  28         55  
  28         2725  
555              
556             @FACETS = (
557             pattern => {
558             value => '^[a-zA-Z_:][\w\-_.:]*$',
559             errmsg => 'value is not a valid Name',
560             }
561             );
562              
563              
564             #------------------------------------------------------------------------
565             # NCName
566             # Non-colonized name, a string matching the 'NCName' production of
567             # [Namespaces in XML].
568             #------------------------------------------------------------------------
569              
570             package XML::Schema::Type::NCName;
571 28     28   160 use base qw( XML::Schema::Type::token );
  28         56  
  28         11806  
572 28     28   157 use vars qw( $ERROR @FACETS );
  28         65  
  28         2162  
573              
574             @FACETS = (
575             pattern => {
576             value => '^[a-zA-Z_][\w\-.]*$',
577             errmsg => 'value is not a valid NCName',
578             }
579             );
580              
581             #------------------------------------------------------------------------
582             # ID
583             # String matching the ID attribute type from [XML 1.0 Recommendation
584             # (Second Edition)].
585             #------------------------------------------------------------------------
586              
587             package XML::Schema::Type::ID;
588 28     28   206 use base qw( XML::Schema::Type::Name );
  28         58  
  28         14791  
589 28     28   156 use vars qw( $ERROR @FACETS );
  28         56  
  28         4364  
590              
591             @FACETS = (
592             \&prepare,
593             );
594              
595             sub prepare {
596 0     0   0 my ($instance, $type) = @_;
597 0         0 $instance->{ magic } = [ ID => $instance->{ value } ];
598 0         0 return 1;
599             }
600              
601              
602             #------------------------------------------------------------------------
603             # IDREF
604             #------------------------------------------------------------------------
605              
606             package XML::Schema::Type::IDREF;
607 28     28   156 use base qw( XML::Schema::Type::Name );
  28         69  
  28         14817  
608 28     28   193 use vars qw( $ERROR @FACETS );
  28         54  
  28         3157  
609              
610             @FACETS = (
611             \&prepare,
612             );
613              
614             sub prepare {
615 0     0   0 my ($instance, $type) = @_;
616 0         0 $instance->{ magic } = [ IDREF => $instance->{ value } ];
617 0         0 return 1;
618             }
619              
620              
621             #------------------------------------------------------------------------
622             # NOTATION
623             #------------------------------------------------------------------------
624              
625             package XML::Schema::Type::NOTATION;
626 28     28   147 use base qw( XML::Schema::Type::Simple );
  28         61  
  28         2010  
627 28     28   166 use vars qw( $ERROR @FACETS );
  28         73  
  28         2976  
628              
629             @FACETS = (
630             sub { die "NOTATION not yet implemented\n" },
631             );
632              
633              
634             #------------------------------------------------------------------------
635             # integer
636             #------------------------------------------------------------------------
637              
638             package XML::Schema::Type::integer;
639 28     28   136 use base qw( XML::Schema::Type::decimal );
  28         59  
  28         16004  
640 28     28   171 use vars qw( $ERROR @FACETS );
  28         49  
  28         2515  
641              
642             @FACETS = (
643             scale => {
644             value => 0,
645             fixed => 1,
646             errmsg => 'value is not an integer',
647             },
648             );
649              
650              
651             #------------------------------------------------------------------------
652             # nonPositiveInteger
653             # An integer value less than or equal to 0
654             #------------------------------------------------------------------------
655              
656             package XML::Schema::Type::nonPositiveInteger;
657 28     28   167 use base qw( XML::Schema::Type::integer );
  28         56  
  28         14284  
658 28     28   168 use vars qw( $ERROR @FACETS );
  28         58  
  28         2531  
659              
660             @FACETS = (
661             maxInclusive => {
662             value => 0,
663             errmsg => 'value is positive',
664             },
665             );
666              
667              
668             #------------------------------------------------------------------------
669             # negativeInteger
670             # An integer value less than 0
671             #------------------------------------------------------------------------
672              
673             package XML::Schema::Type::negativeInteger;
674 28     28   167 use base qw( XML::Schema::Type::integer );
  28         68  
  28         12117  
675 28     28   166 use vars qw( $ERROR @FACETS );
  28         51  
  28         2444  
676              
677             @FACETS = (
678             maxInclusive => {
679             value => -1,
680             errmsg => 'value is not negative'
681             },
682             );
683              
684              
685             #------------------------------------------------------------------------
686             # long
687             # An integer in the range -9223372036854775808 to 9223372036854775807.
688             # See comments in docs/nonconform relating to failure to correctly
689             # validate long numbers.
690             #------------------------------------------------------------------------
691              
692             package XML::Schema::Type::long;
693 28     28   394 use base qw( XML::Schema::Type::integer );
  28         62  
  28         11952  
694 28     28   172 use vars qw( $ERROR @FACETS );
  28         55  
  28         3489  
695              
696             @FACETS = (
697             minInclusive => -9223372036854775808,
698             maxInclusive => 9223372036854775807,
699             );
700              
701              
702             #------------------------------------------------------------------------
703             # int
704             # An integer value in the range -2147483648 to 2147483647. Note that
705             # we derive directly from integer rather than long.
706             #------------------------------------------------------------------------
707              
708             package XML::Schema::Type::int;
709 28     28   144 use base qw( XML::Schema::Type::integer );
  28         51  
  28         11705  
710 28     28   171 use vars qw( $ERROR @FACETS );
  28         64  
  28         2192  
711              
712             @FACETS = (
713             minInclusive => -2147483648,
714             maxInclusive => 2147483647,
715             );
716              
717              
718             #------------------------------------------------------------------------
719             # short
720             # An integer value in the range -32768 to 32767. Note that
721             # we derive directly from integer rather than int.
722             #------------------------------------------------------------------------
723              
724             package XML::Schema::Type::short;
725 28     28   155 use base qw( XML::Schema::Type::integer );
  28         61  
  28         12545  
726 28     28   157 use vars qw( $ERROR @FACETS );
  28         54  
  28         3954  
727              
728             @FACETS = (
729             minInclusive => -32768,
730             maxInclusive => 32767,
731             );
732              
733              
734             #------------------------------------------------------------------------
735             # byte
736             # An integer in the range -128 to 127. Again, this is derived
737             # directly from integer rather than via short.
738             #------------------------------------------------------------------------
739              
740             package XML::Schema::Type::byte;
741 28     28   142 use base qw( XML::Schema::Type::integer );
  28         49  
  28         13054  
742 28     28   155 use vars qw( $ERROR @FACETS );
  28         56  
  28         2066  
743              
744             @FACETS = (
745             minInclusive => -128,
746             maxInclusive => 127,
747             );
748              
749              
750             #------------------------------------------------------------------------
751             # nonNegativeInteger
752             # An integer value greater than or equal to 0
753             #------------------------------------------------------------------------
754              
755             package XML::Schema::Type::nonNegativeInteger;
756 28     28   259 use base qw( XML::Schema::Type::integer );
  28         76  
  28         12891  
757 28     28   394 use vars qw( $ERROR @FACETS );
  28         72  
  28         2133  
758              
759             @FACETS = (
760             minInclusive => {
761             value => 0,
762             errmsg => 'value is negative',
763             },
764             );
765              
766              
767             #------------------------------------------------------------------------
768             # unsignedLong
769             # An integer in the range 0 to 18446744073709551615
770             # See comments in docs/nonconform relating to failure to correctly
771             # validate long numbers.
772             #------------------------------------------------------------------------
773              
774             package XML::Schema::Type::unsignedLong;
775 28     28   148 use base qw( XML::Schema::Type::nonNegativeInteger );
  28         65  
  28         13779  
776 28     28   155 use vars qw( $ERROR @FACETS );
  28         52  
  28         2240  
777              
778             @FACETS = (
779             maxInclusive => 18446744073709551615,
780             );
781              
782              
783             #------------------------------------------------------------------------
784             # unsignedInt
785             # An integer in the range 0 to 4294967295. This is derived directly
786             # from nonNegativeInteger rather than via unsignedLong.
787             #------------------------------------------------------------------------
788              
789             package XML::Schema::Type::unsignedInt;
790 28     28   143 use base qw( XML::Schema::Type::nonNegativeInteger );
  28         53  
  28         11796  
791 28     28   155 use vars qw( $ERROR @FACETS );
  28         65  
  28         2056  
792              
793             @FACETS = (
794             maxInclusive => 4294967295,
795             );
796              
797              
798             #------------------------------------------------------------------------
799             # unsignedShort
800             # An integer in the range 0 to 65535. This is derived directly
801             # from nonNegativeInteger rather than via unsignedInt.
802             #------------------------------------------------------------------------
803              
804             package XML::Schema::Type::unsignedShort;
805 28     28   155 use base qw( XML::Schema::Type::nonNegativeInteger );
  28         58  
  28         11856  
806 28     28   163 use vars qw( $ERROR @FACETS );
  28         57  
  28         1968  
807              
808             @FACETS = (
809             maxInclusive => 65535,
810             );
811              
812              
813             #------------------------------------------------------------------------
814             # unsignedByte
815             # An unsigned byte in the range 0 to 255. Again, this is derived
816             # directly from nonNegativeInteger rather than via unsignedShort.
817             #------------------------------------------------------------------------
818              
819             package XML::Schema::Type::unsignedByte;
820 28     28   137 use base qw( XML::Schema::Type::nonNegativeInteger );
  28         47  
  28         11348  
821 28     28   154 use vars qw( $ERROR @FACETS );
  28         55  
  28         1955  
822              
823             @FACETS = (
824             maxInclusive => 255,
825             );
826              
827              
828             #------------------------------------------------------------------------
829             # positiveInteger
830             # An integer value greater than 0
831             #------------------------------------------------------------------------
832              
833             package XML::Schema::Type::positiveInteger;
834 28     28   285 use base qw( XML::Schema::Type::integer );
  28         48  
  28         12933  
835 28     28   155 use vars qw( $ERROR @FACETS );
  28         63  
  28         2175  
836              
837             @FACETS = (
838             minInclusive => {
839             value => 1,
840             errmsg => 'value is not positive',
841             },
842             );
843              
844              
845             #------------------------------------------------------------------------
846             # timeInstant
847             #------------------------------------------------------------------------
848              
849             package XML::Schema::Type::timeInstant;
850 28     28   152 use base qw( XML::Schema::Type::recurringDuration );
  28         90  
  28         16674  
851 28     28   150 use vars qw( $ERROR @FACETS );
  28         96  
  28         2131  
852              
853             @FACETS = (
854             period => { value => 'P0Y', fixed => 1 },
855             duration => { value => 'P0Y', fixed => 1 },
856             );
857              
858              
859             #------------------------------------------------------------------------
860             # time
861             #------------------------------------------------------------------------
862              
863             package XML::Schema::Type::time;
864 28     28   154 use base qw( XML::Schema::Type::recurringDuration );
  28         66  
  28         11636  
865 28     28   151 use vars qw( $ERROR @FACETS );
  28         54  
  28         9124  
866              
867             @FACETS = (
868             period => { value => 'P1D', fixed => 1 },
869             duration => { value => 'P0Y', fixed => 1 },
870             );
871              
872             sub prepare {
873 28     28   40 my ($self, $instance) = @_;
874 28         41 my $value = $instance->{ value };
875              
876 28 100       59 return $self->error('value is empty')
877             unless length $value;
878              
879 27 100       140 return $self->error("value is not a valid date")
880             unless $value =~ /
881             ^
882             (\d{2}) : # hour ($1)
883             (\d{2}) : # minute ($2)
884             (\d{2}(?:.\d+)?) # second ($3)
885             (?: # optional time zone
886             (Z) # UTC ($4)
887             | ([-+]) # sign ($5)
888             (\d{2}) : # hours ($6)
889             (\d{2}) # minutes ($7)
890             )?
891             $
892             /x;
893              
894 24         118 @$instance{ qw( hour minute second ) } = ($1, $2, $3);
895 24 100       73 $instance->{ UTC } = $4 ? 1 : 0;
896 24         80 my $zone = $instance->{ zone } = { };
897 24         88 @$zone{ qw( sign hour minute ) } = ($5, $6, $7);
898              
899 24         114 return 1;
900             }
901              
902              
903             #------------------------------------------------------------------------
904             # timePeriod
905             #------------------------------------------------------------------------
906              
907             package XML::Schema::Type::timePeriod;
908 28     28   168 use base qw( XML::Schema::Type::recurringDuration );
  28         70  
  28         12334  
909 28     28   164 use vars qw( $ERROR @FACETS );
  28         55  
  28         2230  
910              
911             @FACETS = (
912             period => { value => 'P0Y', fixed => 1 },
913             );
914              
915              
916             #------------------------------------------------------------------------
917             # date
918             #------------------------------------------------------------------------
919              
920             package XML::Schema::Type::date;
921 28     28   146 use base qw( XML::Schema::Type::timePeriod );
  28         51  
  28         13056  
922 28     28   210 use vars qw( $ERROR @FACETS );
  28         81  
  28         8378  
923              
924             @FACETS = (
925             duration => { value => 'P1D', fixed => 1 },
926             );
927              
928             sub prepare {
929 5     5   6 my ($self, $instance) = @_;
930 5         7 my $value = $instance->{ value };
931              
932 5 50       13 return $self->error('value is empty')
933             unless length $value;
934              
935 5 100       29 return $self->error("value is not a valid date")
936             unless $value =~ /
937             ^
938             ([-+]?) # sign ($1)
939             (\d{2,}) # century ($2)
940             (\d{2}) - # year ($3)
941             (\d{2}) - # month ($4)
942             (\d{2}) # day ($5)
943             $
944             /x;
945              
946 4         67 @$instance{ qw( sign century year month day ) } = ( $1, $2, $3, $4, $5 );
947              
948 4         20 return 1;
949             }
950              
951              
952             #------------------------------------------------------------------------
953             # month
954             #------------------------------------------------------------------------
955              
956             package XML::Schema::Type::month;
957 28     28   172 use base qw( XML::Schema::Type::timePeriod );
  28         58  
  28         12427  
958 28     28   177 use vars qw( $ERROR @FACETS );
  28         66  
  28         6543  
959              
960             @FACETS = (
961             duration => { value => 'P1M', fixed => 1 },
962             );
963              
964             sub prepare {
965 6     6   8 my ($self, $instance) = @_;
966 6         11 my $value = $instance->{ value };
967              
968 6 50       15 return $self->error('value is empty')
969             unless length $value;
970              
971 6 100       39 return $self->error("value is not a valid month")
972             unless $value =~ /
973             ^
974             ([-+]?) # sign ($1)
975             (\d{2,}) # century ($2)
976             (\d{2}) - # year ($3)
977             (\d{2}) # month ($4)
978             $
979             /x;
980              
981 4         26 @$instance{ qw( sign century year month ) } = ( $1, $2, $3, $4 );
982              
983 4         23 return 1;
984             }
985              
986              
987             #------------------------------------------------------------------------
988             # year
989             #------------------------------------------------------------------------
990              
991             package XML::Schema::Type::year;
992 28     28   180 use base qw( XML::Schema::Type::timePeriod );
  28         87  
  28         13009  
993 28     28   158 use vars qw( $ERROR @FACETS );
  28         2266  
  28         6157  
994              
995             @FACETS = (
996             duration => { value => 'P1Y', fixed => 1 },
997             );
998              
999             sub prepare {
1000 7     7   11 my ($self, $instance) = @_;
1001 7         10 my $value = $instance->{ value };
1002              
1003 7 50       16 return $self->error('value is empty')
1004             unless length $value;
1005              
1006 7 100       36 return $self->error("value is not a valid year")
1007             unless $value =~ /
1008             ^
1009             ([-+]?) # sign ($1)
1010             (\d{2,}) # century ($2)
1011             (\d{2}) # year ($3)
1012             $
1013             /x;
1014              
1015 5         27 @$instance{ qw( sign century year ) } = ( $1, $2, $3 );
1016              
1017 5         25 return 1;
1018             }
1019              
1020              
1021             #------------------------------------------------------------------------
1022             # century
1023             #------------------------------------------------------------------------
1024              
1025             package XML::Schema::Type::century;
1026 28     28   1479 use base qw( XML::Schema::Type::timePeriod );
  28         1648  
  28         14795  
1027 28     28   167 use vars qw( $ERROR @FACETS );
  28         2925  
  28         10678  
1028              
1029             @FACETS = (
1030             duration => { value => 'P100Y', fixed => 1 },
1031             );
1032              
1033             sub prepare {
1034 7     7   10 my ($self, $instance) = @_;
1035 7         10 my $value = $instance->{ value };
1036              
1037 7 50       18 return $self->error('value is empty')
1038             unless length $value;
1039              
1040 7 100       33 return $self->error("value is not a valid century")
1041             unless $value =~ /
1042             ^
1043             ([-+]?) # sign ($1)
1044             (\d{2,}) # century ($2)
1045             $
1046             /x;
1047              
1048 5         24 @$instance{ qw( sign century ) } = ( $1, $2 );
1049              
1050 5         26 return 1;
1051             }
1052              
1053              
1054             #------------------------------------------------------------------------
1055             # recurringDate
1056             #------------------------------------------------------------------------
1057              
1058             package XML::Schema::Type::recurringDate;
1059 28     28   1478 use base qw( XML::Schema::Type::recurringDuration );
  28         52  
  28         15853  
1060 28     28   1744 use vars qw( $ERROR @FACETS );
  28         1499  
  28         6630  
1061              
1062             @FACETS = (
1063             duration => { value => 'P1D', fixed => 1 },
1064             period => { value => 'P1Y', fixed => 1 },
1065             );
1066              
1067             sub prepare {
1068 5     5   8 my ($self, $instance) = @_;
1069 5         10 my $value = $instance->{ value };
1070              
1071 5 50       12 return $self->error('value is empty')
1072             unless length $value;
1073              
1074 5 100       26 return $self->error("value is not a valid recurringDate")
1075             unless $value =~ /
1076             ^
1077             --
1078             (\d{2}) - # month ($1)
1079             (\d{2}) # day ($2)
1080             $
1081             /x;
1082              
1083 3         15 @$instance{ qw( month day ) } = ( $1, $2 );
1084              
1085 3         17 return 1;
1086             }
1087              
1088              
1089             #------------------------------------------------------------------------
1090             # recurringDay
1091             #------------------------------------------------------------------------
1092              
1093             package XML::Schema::Type::recurringDay;
1094 28     28   153 use base qw( XML::Schema::Type::recurringDuration );
  28         44  
  28         17647  
1095 28     28   164 use vars qw( $ERROR @FACETS );
  28         2670  
  28         18713  
1096              
1097             @FACETS = (
1098             duration => { value => 'P1D', fixed => 1 },
1099             period => { value => 'P1M', fixed => 1 },
1100             );
1101              
1102             sub prepare {
1103 2     2   5 my ($self, $instance) = @_;
1104 2         5 my $value = $instance->{ value };
1105              
1106 2 50       6 return $self->error('value is empty')
1107             unless length $value;
1108              
1109 2 50       11 return $self->error("value is not a valid recurringDay")
1110             unless $value =~ /
1111             ^
1112             ---
1113             (\d{2}) # day ($1)
1114             $
1115             /x;
1116              
1117 2         8 $instance->{ day } = $1;
1118              
1119 2         10 return 1;
1120             }
1121              
1122             1;
1123              
1124             __END__