File Coverage

blib/lib/Types/XSD.pm
Criterion Covered Total %
statement 72 82 87.8
branch 6 10 60.0
condition 4 9 44.4
subroutine 21 23 91.3
pod 4 5 80.0
total 107 129 82.9


line stmt bran cond sub pod time code
1              
2             use 5.008003;
3 41     41   4759027 use strict;
  41         520  
4 41     41   213 use warnings;
  41         91  
  41         837  
5 41     41   198 use utf8;
  41         102  
  41         1341  
6 41     41   1873  
  41         137  
  41         343  
7             BEGIN {
8             $Types::XSD::AUTHORITY = 'cpan:TOBYINK';
9 41     41   1959 $Types::XSD::VERSION = '0.008';
10 41         983 }
11              
12             use B qw(perlstring);
13 41     41   267 use Carp;
  41         79  
  41         2342  
14 41     41   241 use DateTimeX::Auto qw( dt dur );
  41         95  
  41         2264  
15 41     41   17082 use DateTime::Incomplete ();
  41         26337833  
  41         775  
16 41     41   41004 use Types::XSD::Lite 0.007 -base, -utils, -declare => qw(
  41         2295247  
  41         2382  
17 41         634 Name NmToken NmTokens NCName Id IdRef IdRefs Entity Entities
18             QName Notation Duration DateTime Time Date GYearMonth
19             GYear GMonthDay GDay GMonth
20             DateTimeStamp YearMonthDuration DayTimeDuration
21             );
22 41     41   23403 use Types::Standard 2.000000 qw( StrMatch );
  41         8098820  
23 41     41   815370 use XML::RegExp;
  41         888  
  41         254  
24 41     41   112646  
  41         20025  
  41         4714  
25             push( our(@EXPORT_OK), qw( dt_cmp dur_cmp dt_parse dur_parse ) );
26              
27             BEGIN {
28             *create_range_check = \&Types::XSD::Lite::create_range_check;
29 41     41   206 *quick_range_check = \&Types::XSD::Lite::quick_range_check;
30 41         131 *hex_length = \&Types::XSD::Lite::hex_length;
31 41         111 *b64_length = \&Types::XSD::Lite::b64_length;
32 41         92 *with_facets = \&Types::XSD::Lite::with_facets;
33 41         1725 };
34              
35             use constant MAGIC_DATES => map dt($_), qw( 1696-09-01 1697-02-01 1903-03-01 1903-07-01 );
36 41     41   283 use constant MAGIC_TABLE => +{ "-1-1-1-1" => -1, "0000" => 0, "1111" => 1 };
  41         80  
  41         284  
37 41     41   62105  
  41         104  
  41         94464  
38             my @durations = do {
39             local $SIG{__WARN__} = sub {};
40 880     880 1 674299 map ref($_) ? $_ : dur($_), @_[0,1];
41 880     3520   6302 };
42 880 50       5599 my $result = join q[], map "DateTime::Duration"->compare(@durations, $_), MAGIC_DATES;
43             return MAGIC_TABLE->{$result} if exists MAGIC_TABLE->{$result};
44 880         268268 return undef;
45 880 50       5923028 }
46 0         0  
47             our @patterns; my $pattern_i = -1;
48             our @assertions; my $assertion_i = -1;
49             my %facets = (
50             explicitTimezone => sub {
51             my ($o, $var) = @_;
52             return unless exists $o->{explicitTimezone};
53             my $etz = delete $o->{explicitTimezone};
54             return sprintf('%s =~ m/(?:Z|(?:[+-]\d{2}:?\d{2}))$/xism', $var)
55             if lc($etz) eq 'required';
56             return sprintf('%s !~ m/(?:Z|(?:[+-]\d{2}:?\d{2}))$/xism', $var)
57             if lc($etz) eq 'prohibited';
58             return '!!1'
59             if lc($etz) eq 'optional';
60             croak "explicitTimezone facet expected to be 'required', 'prohibited' or 'optional'"
61             },
62             maxInclusiveDuration => sub {
63             my ($o, $var) = @_;
64             return unless exists $o->{maxInclusive};
65             sprintf('(Types::XSD::dur_cmp(%s, %s)||0) <= 0', $var, perlstring delete $o->{maxInclusive});
66             },
67             minInclusiveDuration => sub {
68             my ($o, $var) = @_;
69             return unless exists $o->{minInclusive};
70             sprintf('(Types::XSD::dur_cmp(%s, %s)||0) >= 0', $var, perlstring delete $o->{minInclusive});
71             },
72             maxExclusiveDuration => sub {
73             my ($o, $var) = @_;
74             return unless exists $o->{maxExclusive};
75             sprintf('(Types::XSD::dur_cmp(%s, %s)||0) < 0', $var, perlstring delete $o->{maxExclusive});
76             },
77             minExclusiveDuration => sub {
78             my ($o, $var) = @_;
79             return unless exists $o->{minExclusive};
80             sprintf('(Types::XSD::dur_cmp(%s, %s)||0) > 0', $var, perlstring delete $o->{minExclusive});
81             },
82             maxInclusiveDT => sub {
83             my ($o, $var) = @_;
84             return unless exists $o->{maxInclusive};
85             sprintf('(Types::XSD::dt_cmp(%s, %s, %s)||0) <= 0', perlstring($Types::XSD::Lite::T), $var, perlstring delete $o->{maxInclusive});
86             },
87             minInclusiveDT => sub {
88             my ($o, $var) = @_;
89             return unless exists $o->{minInclusive};
90             sprintf('(Types::XSD::dt_cmp(%s, %s, %s)||0) >= 0', perlstring($Types::XSD::Lite::T), $var, perlstring delete $o->{minInclusive});
91             },
92             maxExclusiveDT => sub {
93             my ($o, $var) = @_;
94             return unless exists $o->{maxExclusive};
95             sprintf('(Types::XSD::dt_cmp(%s, %s, %s)||0) < 0', perlstring($Types::XSD::Lite::T), $var, perlstring delete $o->{maxExclusive});
96             },
97             minExclusiveDT => sub {
98             my ($o, $var) = @_;
99             return unless exists $o->{minExclusive};
100             sprintf('(Types::XSD::dt_cmp(%s, %s, %s)||0) > 0', perlstring($Types::XSD::Lite::T), $var, perlstring delete $o->{minExclusive});
101             },
102             );
103              
104             $Types::XSD::Lite::facets{$_} = $facets{$_} for keys %facets;
105              
106             our @dtarr;
107             my $i = -1;
108             our $base_datetime = "DateTime"->new(year => 2000, month => 1, day => 1); # leap year, 31 day month
109             our %dt_regexps;
110              
111             my ( $name, $regexp, @fields ) = @_;
112             my $j = ++$i;
113             $dtarr[$j] = $regexp;
114 369     369 0 2400
115 369         588 my $inlined = sub {
116 369         702 my $var = $_[1];
117             my @code;
118             push @code, "do { my \$ok = 1;";
119 6619     6619   639087 push @code, sprintf(
120 6619         9101 'my (%s) = (%s =~ $Types::XSD::dtarr[%d]) or --$ok;',
121 6619         10855 join(', ', map "\$$_", @fields),
122 6619         39920 $var,
123             $j,
124             );
125             push @code, sprintf(
126             '$ok and eval { "DateTime::Incomplete"->new(%s)->to_datetime(base => $Types::XSD::base_datetime) };',
127             join(', ', map "$_ => \$$_", @fields),
128 6619         35069 );
129             push @code, "}";
130             "@code";
131             };
132 6619         12296  
133 6619         74899 my $type = declare $name,
134 369         1333 with_facets [qw( pattern whiteSpace enumeration maxInclusiveDT maxExclusiveDT minInclusiveDT minExclusiveDT explicitTimezone )],
135             constraint => eval sprintf( 'sub { %s }', $inlined->(undef, '$_') ),
136 369         1277 inlined => $inlined;
137              
138             $dt_regexps{$type} = [ $regexp, @fields ];
139             }
140              
141 369         192404 my ($type, $a) = @_;
142             my ($re, @fields) = @{ $dt_regexps{$type} };
143             my %d;
144             @d{@fields} = ($a =~ $re);
145 0     0 1 0 !defined($d{$_}) && delete($d{$_}) for @fields;
146 0         0 "DateTime::Incomplete"->new(%d);
  0         0  
147 0         0 }
148 0         0  
149 0   0     0 goto \&DateTimeX::Auto::dur;
150 0         0 }
151              
152             {
153             my %cache;
154 0     0 1 0 my ($lib, $v) = @_;
155             for my $type (qw(DateTime Time Date GYearMonth GYear GMonthDay GDay GMonth)) {
156             return $type if $lib->get_type($type)->check($v);
157             }
158             return $lib->get_type('DateTime');
159             }
160 6935     6935   14578 my ($type, $a, $b) = @_;
161 6935         15322 $type = __PACKAGE__->_detect_type($a) unless $type;
162 30905 100       539834 $type = __PACKAGE__->get_type($type) unless ref $type;
163             my $A = eval($cache{"$type;a"} ||= $type->inline_check('$a'));
164 0         0 my $B = eval($cache{"$type;b"} ||= $type->inline_check('$b'));
165             $A <=> $B;
166             }
167 6935     6935 1 8659116 }
168 6935 50       31493  
169 6935 50       3404854 declare Name,
170 6935   66     93179 with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
171 6935   66     3362098 as StrMatch[qr{\A(?:$XML::RegExp::Name)\z}sm];
172 6935         3342939  
173             declare NmToken,
174             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
175             as StrMatch[qr{\A(?:$XML::RegExp::NmToken)\z}sm];
176              
177             declare NmTokens,
178             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
179             as StrMatch[qr{\A(?:$XML::RegExp::NmToken)(?:\s+$XML::RegExp::NmToken)*\z}sm];
180              
181             declare NCName,
182             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
183             as StrMatch[qr{\A(?:$XML::RegExp::NCName)\z}sm];
184              
185             declare Id,
186             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
187             as NCName;
188              
189             declare IdRef,
190             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
191             as NCName;
192              
193             declare IdRefs,
194             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
195             as StrMatch[qr{\A(?:$XML::RegExp::NCName)(?:\s+$XML::RegExp::NCName)*\z}sm];
196              
197             declare Entity,
198             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
199             as NCName;
200              
201             declare Entities,
202             with_facets [qw( length minLength maxLength pattern enumeration whiteSpace )],
203             as StrMatch[qr{\A(?:$XML::RegExp::NCName)(?:\s+$XML::RegExp::NCName)*\z}sm];
204              
205             declare QName,
206             with_facets [qw( lengthQName minLengthQName maxLengthQName pattern enumeration whiteSpace )],
207             as StrMatch[qr{\A(?:$XML::RegExp::QName)\z}sm];
208              
209             declare Notation,
210             with_facets [qw( lengthQName minLengthQName maxLengthQName pattern enumeration whiteSpace )],
211             as QName;
212              
213             declare Duration,
214             with_facets [qw( pattern whiteSpace enumeration maxInclusiveDuration maxExclusiveDuration minInclusiveDuration minExclusiveDuration )],
215             as StrMatch[
216             qr{\A
217             -?
218             P
219             (?:[0-9]+Y)?
220             (?:[0-9]+M)?
221             (?:[0-9]+D)?
222             (?:T
223             (?:[0-9]+H)?
224             (?:[0-9]+M)?
225             (?:[0-9]+(?:\.[0-9]+)?S)?
226             )?
227             \z}xism
228             ];
229              
230             declare YearMonthDuration,
231             with_facets [qw( pattern whiteSpace enumeration maxInclusiveDuration maxExclusiveDuration minInclusiveDuration minExclusiveDuration )],
232             as Duration->parameterize(pattern => qr{\A[^DT]*\z}i);
233              
234             declare DayTimeDuration,
235             with_facets [qw( pattern whiteSpace enumeration maxInclusiveDuration maxExclusiveDuration minInclusiveDuration minExclusiveDuration )],
236             as Duration->parameterize(pattern => qr{\A[^YM]*[DT].*\z}i);
237              
238             dt_maker(
239             DateTime => qr{\A
240             (-?[0-9]{4,})
241             -
242             ([0-9]{2})
243             -
244             ([0-9]{2})
245             T
246             ([0-9]{2})
247             :
248             ([0-9]{2})
249             :
250             ([0-9]{2}(?:\.[0-9]+)?)
251             (Z | (?: [+-]\d{2}:?\d{2} ))?
252             \z}xism,
253             qw( year month day hour minute second time_zone ),
254             );
255              
256             dt_maker(
257             DateTimeStamp => qr{\A
258             (-?[0-9]{4,})
259             -
260             ([0-9]{2})
261             -
262             ([0-9]{2})
263             T
264             ([0-9]{2})
265             :
266             ([0-9]{2})
267             :
268             ([0-9]{2}(?:\.[0-9]+)?)
269             (Z | (?: [+-]\d{2}:?\d{2} ))
270             \z}xism,
271             qw( year month day hour minute second time_zone ),
272             );
273              
274             dt_maker(
275             Time => qr{\A
276             ([0-9]{2})
277             :
278             ([0-9]{2})
279             :
280             ([0-9]{2}(?:\.[0-9]+)?)
281             (Z | (?: [+-]\d{2}:?\d{2} ))?
282             \z}xism,
283             qw( hour minute second time_zone ),
284             );
285              
286             dt_maker(
287             Date => qr{\A
288             (-?[0-9]{4,})
289             -
290             ([0-9]{2})
291             -
292             ([0-9]{2})
293             (Z | (?: [+-]\d{2}:?\d{2} ))?
294             \z}xism,
295             qw( year month day time_zone ),
296             );
297              
298             dt_maker(
299             GYearMonth => qr{\A
300             (-?[0-9]{4,})
301             -
302             ([0-9]{2})
303             (Z | (?: [+-]\d{2}:?\d{2} ))?
304             \z}xism,
305             qw( year month time_zone ),
306             );
307              
308             dt_maker(
309             GYear => qr{\A
310             (-?[0-9]{4,})
311             (Z | (?: [+-]\d{2}:?\d{2} ))?
312             \z}xism,
313             qw( year time_zone ),
314             );
315              
316             dt_maker(
317             GMonthDay => qr{\A
318             -
319             -
320             ([0-9]{2})
321             -
322             ([0-9]{2})
323             (Z | (?: [+-]\d{2}:?\d{2} ))?
324             \z}xism,
325             qw( month day time_zone ),
326             );
327              
328             dt_maker(
329             GDay => qr{\A
330             -
331             -
332             -
333             ([0-9]{2})
334             (Z | (?: [+-]\d{2}:?\d{2} ))?
335             \z}xism,
336             qw( day time_zone ),
337             );
338              
339             dt_maker(
340             GMonth => qr{\A
341             -
342             -
343             ([0-9]{2})
344             (Z | (?: [+-]\d{2}:?\d{2} ))?
345             \z}xism,
346             qw( month time_zone ),
347             );
348              
349             __PACKAGE__->meta->make_immutable;
350              
351              
352             =pod
353              
354             =encoding utf-8
355              
356             =head1 NAME
357              
358             Types::XSD - type constraints based on XML schema datatypes
359              
360             =head1 SYNOPSIS
361              
362             package Person;
363            
364             use Moo;
365             use Types::XSD qw( PositiveInteger String );
366            
367             has name => (is => "ro", isa => String[ minLength => 1 ]);
368             has age => (is => "ro", isa => PositiveInteger);
369              
370             =head1 DESCRIPTION
371              
372             Types::XSD is a type constraint library inspired by XML Schema, and built
373             with L<Type::Library>. It can be used as a type constraint library for
374             L<Moo>, L<Mouse> or L<Moose>, or used completely independently of any OO
375             framework.
376              
377             This module is an extension of L<Types::XSD::Lite> (which has fewer type
378             constraints, but fewer dependencies). For completeness, the type constraints
379             and other features inherited from Types::XSD::Lite are documented below
380             too.
381              
382             =head2 Type Constraints
383              
384             This module defines the following type constraints based on the data types
385             defined in L<XML Schema|http://www.w3.org/TR/xmlschema-2/>. (The names of
386             the type constraints are the same as the XML Schema data types, but
387             capitalization often differs.)
388              
389             I've added some quick explainations of what each type is, but for details,
390             see the XML Schema specification.
391              
392             =over
393              
394             =item C<< AnyType >>
395              
396             As per C<Any> from L<Types::Standard>.
397              
398             =item C<< AnySimpleType >>
399              
400             As per C<Value> from L<Types::Standard>.
401              
402             =item C<< String >>
403              
404             As per C<Str> from L<Types::Standard>.
405              
406             =item C<< NormalizedString >>
407              
408             A string containing no line breaks, carriage returns or tabs.
409              
410             =item C<< Token >>
411              
412             Like C<NormalizedString>, but also no leading or trailing space, and no
413             doubled spaces (i.e. not C<< /\s{2,}/ >>).
414              
415             =item C<< Language >>
416              
417             An RFC 3066 language code.
418              
419             =item C<< Name >>
420              
421             Something that could be a valid XML element or attribute name. These roughly
422             correspond to Perl identifiers but may also contain colons, hyphens and stops.
423             (Digits, hyphens and stops are not allowed as the first character.)
424              
425             =item C<< NmToken >>
426              
427             Slightly looser version of C<Name>; allows digits, hyphens and stops in the
428             first character.
429              
430             =item C<< NmTokens >>
431              
432             Space-separated list of C<NmToken>.
433              
434             =item C<< NCName >>
435              
436             Slightly tighter vesion of C<Name>; disallows colons.
437              
438             =item C<< Id >>
439              
440             Effectively the same as C<NCName>.
441              
442             =item C<< IdRef >>
443              
444             Effectively the same as C<NCName>.
445              
446             =item C<< IdRefs >>
447              
448             Space-separated list of C<IdRef>.
449              
450             =item C<< Entity >>
451              
452             Effectively the same as C<NCName>.
453              
454             =item C<< Entities >>
455              
456             Space-separated list of C<Entity>.
457              
458             =item C<< Boolean >>
459              
460             Allows C<< "true" >>, C<< "false" >>, C<< "1" >> and C<< "0" >>
461             (case-insensitively).
462              
463             Gotcha: The string C<< "false" >> evaluates to true in Perl. You probably
464             want to use C<< Bool >> from L<Types::Standard> instead.
465              
466             =item C<< Base64Binary >>
467              
468             Strings which are valid Base64 data. Allows whitespace.
469              
470             Gotcha: If you parameterize this with C<length>, C<maxLength> or C<minLength>,
471             it is the length of the I<decoded> string which will be checked.
472              
473             =item C<< HexBinary >>
474              
475             Strings which are valid hexadecimal data. Disallows whitespace; disallows
476             leading C<< 0x >>.
477              
478             Gotcha: If you parameterize this with C<length>, C<maxLength> or C<minLength>,
479             it is the length of the I<decoded> string which will be checked.
480              
481             =item C<< Float >>
482              
483             As per C<Num> from L<Types::Standard>.
484              
485             =item C<< Double >>
486              
487             As per C<Num> from L<Types::Standard>.
488              
489             =item C<< AnyURI >>
490              
491             Any absolute I<< or relative >> URI. Effectively, any string at all!
492              
493             =item C<< QName >>
494              
495             An XML QName; something that could be used as a valid element name in a
496             namespaced XML document.
497              
498             Gotcha: while C<length>, C<maxLength> and C<minLength> are allowed facets for
499             parameterization, they are silently ignored, as per the specification!
500              
501             =item C<< Notation >>
502              
503             Effectively the same as C<QName>. According to XML Schema, this is I<always>
504             supposed to be parameterized with an enumeration. But we don't enforce that.
505              
506             Gotcha: while C<length>, C<maxLength> and C<minLength> are allowed facets for
507             parameterization, they are silently ignored, as per the specification!
508              
509             =item C<< Decimal >>
510              
511             Numbers possibly including a decimal point, but not allowing exponential
512             notation (e.g. C<< "3.14e-3" >>).
513              
514             =item C<< Integer >>
515              
516             As per C<Int> from L<Types::Standard>.
517              
518             =item C<< NonPositiveInteger >>
519              
520             An C<Integer> 0 or below.
521              
522             =item C<< NegativeInteger >>
523              
524             An C<Integer> -1 or below.
525              
526             =item C<< Long >>
527              
528             An C<Integer> between -9223372036854775808 and 9223372036854775807 (inclusive).
529              
530             =item C<< Int >>
531              
532             An C<Integer> between -2147483648 and 2147483647 (inclusive).
533              
534             =item C<< Short >>
535              
536             An C<Integer> between -32768 and 32767 (inclusive).
537              
538             =item C<< Byte >>
539              
540             An C<Integer> between -128 and 127 (inclusive).
541              
542             =item C<< NonNegativeInteger >>
543              
544             An C<Integer> 0 or above.
545              
546             =item C<< PositiveInteger >>
547              
548             An C<Integer> 1 or above.
549              
550             =item C<< UnsignedLong >>
551              
552             A C<NonNegativeInteger> between 0 and 18446744073709551615 (inclusive).
553              
554             =item C<< UnsignedInt >>
555              
556             A C<NonNegativeInteger> between 0 and 4294967295 (inclusive).
557              
558             =item C<< UnsignedShort >>
559              
560             A C<NonNegativeInteger> between 0 and 65535 (inclusive).
561              
562             =item C<< UnsignedByte >>
563              
564             A C<NonNegativeInteger> between 0 and 255 (inclusive).
565              
566             =item C<< Duration >>
567              
568             An ISO 8601 duration.
569              
570             =item C<< YearMonthDuration >>
571              
572             An ISO 8601 duration restricted to cover only years and months.
573              
574             =item C<< DayTimeDuration >>
575              
576             An ISO 8601 duration restricted to cover only days, hours, minutes and
577             seconds. (Note that this still permits durations of many years, as the
578             days component is an arbitrary non-negative integer.)
579              
580             =item C<< DateTime >>
581              
582             An ISO 8601 datetime with optional timezone.
583              
584             =item C<< DateTimeStamp >>
585              
586             An ISO 8601 datetime with required timezone.
587              
588             =item C<< Time >>
589              
590             An ISO 8601 time with optional timezone.
591              
592             =item C<< Date >>
593              
594             An ISO 8601 date with optional timezone.
595              
596             =item C<< GYearMonth >>
597              
598             An year-month pair with optional timezone.
599              
600             =item C<< GYear >>
601              
602             An year with optional timezone.
603              
604             =item C<< GMonthDay >>
605              
606             An month-day pair with optional timezone.
607              
608             =item C<< GDay >>
609              
610             An day with optional timezone.
611              
612             =item C<< GMonth >>
613              
614             An month with optional timezone.
615              
616             =back
617              
618             =head2 Parameters
619              
620             Datatypes can be parameterized using the facets defined by XML Schema. For
621             example:
622              
623             use Types::XSD qw( String Decimal PositiveInteger Token );
624            
625             my @sizes = qw( XS S M L XL XXL );
626            
627             has name => (is => "ro", isa => String[ minLength => 1 ]);
628             has price => (is => "ro", isa => Decimal[ fractionDigits => 2 ]);
629             has rating => (is => "ro", isa => PositiveInteger[ maxInclusive => 5 ]);
630             has size => (is => "ro", isa => Token[ enumeration => \@sizes ]);
631              
632             The following facets exist, but not all facets are supported for all
633             datatypes. (The module will croak if you try to use an unsupported facet.)
634              
635             =over
636              
637             =item C<< enumeration >>
638              
639             An arrayref of allowable values. You should probably use L<Type::Tiny::Enum>
640             instead.
641              
642             =item C<< pattern >>
643              
644             A regular expression that the value is expected to conform to. Use a normal
645             Perl quoted regexp:
646              
647             Token[ pattern => qr{^[a-z]+$} ]
648              
649             =item C<< whiteSpace >>
650              
651             The C<whiteSpace> facet is ignored as I'm not entirely sure what it should
652             do. It perhaps makes sense for coercions, but this module doesn't define any
653             coercions.
654              
655             =item C<< assertions >>
656              
657             An arrayref of arbitrary additional restrictions, expressed as strings of
658             Perl code or coderefs operating on C<< $_ >>.
659              
660             For example:
661              
662             Integer[
663             assertions => [
664             '$_ % 3 == 0', # multiple of three, and...
665             sub { is_nice($_) }, # is nice (whatever that means)
666             ],
667             ],
668              
669             Strings of Perl code will result in faster-running type constraints.
670              
671             =item C<< length >>, C<< maxLength >>, C<< minLength >>
672              
673             Restrict the length of a value. For example C<< Integer[length=>2] >> allows
674             C<10>, C<99> and C<-1>, but not C<100>, C<9> or C<-10>.
675              
676             Types::XSD won't prevent you from making ridiculous constraints such as
677             C<< String[ maxLength => 1, minLength => 2 ] >>.
678              
679             Note that on C<HexBinary> and C<Base64Binary> types, the lengths apply to
680             the decoded string. Length restrictions are silently ignored for C<QName>
681             and C<Notation> because the W3C doesn't think you should care what length
682             these datatypes are.
683              
684             =item C<< maxInclusive >>, C<< minInclusive >>, C<< maxExclusive >>, C<< minExclusive >>
685              
686             Supported for numeric types and datetime/duration-related types.
687              
688             Note that to be super-correct, the C<< {max,min}{Inclusive,Exclusive} >>
689             facets for numeric types are performed by passing the numbers through
690             L<Math::BigInt> or L<Math::BigFloat>, so may be a little slow.
691              
692             =item C<< totalDigits >>
693              
694             For a decimal (or type derived from decimals) specifies that the total number
695             of digits for the value must be at most this number. Given
696             C<< Decimal[ totalDigits => 3 ] >>, C<1.23>, C<12.3>, C<123>, C<1.2> and C<1>
697             are all allowable; C<1.234> is not. C<1.230> is also not, but this may change
698             in a future version.
699              
700             =item C<< fractionDigits >>
701              
702             Like C<totalDigits> but ignores digits before the decimal point.
703              
704             =item C<< explicitTimezone >>
705              
706             May be C<< "optional" >>, C<< "prohibited" >> or C<< "required" >>. For
707             example:
708              
709             Time[ explicitTimezone => "prohibited" ]
710              
711             =back
712              
713             =head2 Functions
714              
715             This module also exports some convenience functions:
716              
717             =over
718              
719             =item C<< dur_parse($str) >>
720              
721             Parse an xsd:duration string, returning a L<DateTime::Duration>.
722              
723             =item C<< dur_cmp($a, $b) >>
724              
725             Compare two strings conforming to the xsd:duration datatype to indicate
726             which is the longer duration.
727              
728             Returns -1 if $a is shorter. Returns 1 if $b is shorter. Returns 0 if the
729             durations are identical. Returns undef if the comparison is indeterminate;
730             for example, "P1Y" (one year) and "P365D" (365 days) are not necessarily
731             identical - in leap years "P365D" is shorter.
732              
733             =item C<< dt_cmp($type, $a, $b) >>
734              
735             Compare two datetime-like strings. For example, two C<gYearMonth> strings
736             can be compared using:
737              
738             dt_cmp(GYearMonth, "2009-02", "2010-10");
739              
740             Both strings are expected to conform to the same datatype. It doesn't make
741             much sense to compare them otherwise.
742              
743             =item C<< dt_parse($type, $str) >>
744              
745             Parse a datetime-like string, returning a L<DateTime::Incomplete> object.
746             Note that L<DateTime::Incomplete> objects are always returned, even if the
747             datetime is potentially complete.
748              
749             =back
750              
751             =head1 BUGS
752              
753             Please report any bugs to
754             L<http://rt.cpan.org/Dist/Display.html?Queue=Types-XSD>.
755              
756             =head1 SEE ALSO
757              
758             L<Type::Tiny>, L<Types::XSD::Lite>, L<Types::Standard>.
759              
760             =over
761              
762             =item *
763              
764             L<http://www.w3.org/TR/xmlschema-2/> Datatypes in XML Schema 1.0
765              
766             =item *
767              
768             L<http://www.w3.org/TR/xmlschema11-2/> Datatypes in XML Schema 1.1
769              
770             =back
771              
772             =head1 AUTHOR
773              
774             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
775              
776             =head1 COPYRIGHT AND LICENCE
777              
778             This software is copyright (c) 2013-2014, 2021 by Toby Inkster.
779              
780             This is free software; you can redistribute it and/or modify it under
781             the same terms as the Perl 5 programming language system itself.
782              
783             =head1 DISCLAIMER OF WARRANTIES
784              
785             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
786             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
787             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
788