File Coverage

lib/XML/Compile/Schema/BuiltInTypes.pm
Criterion Covered Total %
statement 79 87 90.8
branch 16 22 72.7
condition 1 3 33.3
subroutine 28 32 87.5
pod 1 9 11.1
total 125 153 81.7


line stmt bran cond sub pod time code
1             # Copyrights 2006-2019 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             # This code is part of distribution XML-Compile. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package XML::Compile::Schema::BuiltInTypes;
10 50     50   288 use vars '$VERSION';
  50         78  
  50         2154  
11             $VERSION = '1.63';
12              
13 50     50   245 use base 'Exporter';
  50         77  
  50         3830  
14              
15 50     50   264 use warnings;
  50         80  
  50         1015  
16 50     50   209 use strict;
  50         77  
  50         1303  
17 50     50   247 use utf8;
  50         75  
  50         334  
18 50     50   1253 no warnings 'recursion';
  50         88  
  50         3670  
19              
20             our @EXPORT = qw/%builtin_types builtin_type_info/;
21              
22             our %builtin_types;
23              
24 50     50   269 use Log::Report 'xml-compile';
  50         86  
  50         495  
25 50     50   11410 use POSIX qw/strftime/;
  50         83  
  50         369  
26 50     50   49453 use Math::BigInt;
  50         1016386  
  50         237  
27 50     50   993455 use Math::BigFloat;
  50         1116992  
  50         291  
28 50     50   55665 use MIME::Base64;
  50         29209  
  50         2678  
29 50     50   18663 use Types::Serialiser;
  50         61527  
  50         1688  
30 50     50   313 use Scalar::Util qw(dualvar);
  50         93  
  50         2490  
31 50     50   299 use POSIX qw/floor log10/;
  50         98  
  50         454  
32              
33 50     50   3856 use XML::Compile::Util qw/pack_type unpack_type/;
  50         107  
  50         2321  
34              
35 50     50   272 use Config '%Config';
  50         91  
  50         29766  
36             my $iv_bits = $Config{ivsize} * 8 -1;
37             my $iv_digits = floor($iv_bits * log10(2));
38             my $fits_iv = qr/^[+-]?[0-9]{1,$iv_digits}$/;
39              
40              
41 0     0 1 0 sub builtin_type_info($) { $builtin_types{$_[0]} }
42              
43              
44             # The XML reader calls
45             # check(parse(value)) or check_read(parse(value))
46              
47             # The XML writer calls
48             # check(format(value)) or check_write(format(value))
49              
50             # Parse has a second argument, only for QNAME: the node
51             # Format has a second argument for QNAME as well.
52              
53 0     0 0 0 sub identity { $_[0] }
54              
55             # already validated, unless that is disabled.
56 548     548 0 1982 sub str2int { $_[0] + 0 }
57              
58             # sprintf returns '0' if non-int, with warning. We need a validation error
59 468 100   468 0 4266 sub int2str { $_[0] =~ m/^\s*([0-9]+)\s*$/ ? $1 : $_[0] }
60              
61 0     0 0 0 sub str { "$_[0]" }
62 0     0   0 sub _replace { $_[0] =~ s/[\t\r\n]/ /g; $_[0]}
  0         0  
63 17     17   41 sub _collapse { local $_ = $_[0]; s/[\t\r\n]+/ /g; s/^ +//; s/ +$//; $_}
  17         39  
  17         32  
  17         33  
  17         45  
64              
65              
66             # format not useful, because xsi:type not supported
67             $builtin_types{anySimpleType} =
68             { example => 'anySimple'
69             , parse => sub {shift}
70             , extends => 'anyType'
71             };
72              
73             $builtin_types{anyType} =
74             { example => 'anything'
75             , parse => sub {shift}
76             , extends => undef # the root type
77             };
78              
79             $builtin_types{anyAtomicType} =
80             { example => 'anyAtomic'
81             , parse => sub {shift}
82             , extends => 'anySimpleType'
83             };
84              
85              
86             $builtin_types{error} = {example => '[some error structure]'};
87              
88             #----------------
89              
90              
91             $builtin_types{boolean} =
92             { parse => sub { $_[0] =~ m/^\s*false|0\s*/i ? 0 : 1 }
93             , format => sub { $_[0] eq 'false' || $_[0] eq 'true' ? $_[0]
94             : $_[0] ? 1 : 0 }
95             , check => sub { $_[0] =~ m/^\s*(?:false|true|0|1)\s*$/i }
96             , example => 'true'
97             , extends => 'anyAtomicType'
98             };
99              
100             $builtin_types{boolean_with_Types_Serialiser} =
101             { %{$builtin_types{boolean}}
102             , parse => sub {
103 50     50   360 no warnings 'once';
  50         118  
  50         80532  
104             $_[0] =~ m/^\s*(false|0)\s*/i
105             ? $Types::Serialiser::false
106             : $Types::Serialiser::true;
107             }
108             };
109              
110              
111             $builtin_types{pattern} =
112             { example => '*.exe'
113             };
114              
115              
116             sub bigint
117 15     15 0 27 { my $v = shift;
118 15         39 $v =~ s/\s+//g;
119              
120             # The automatic rewrite into JSON wants real ints, not strings. Therefore,
121             # we need to numify. On the other hand, pattern matching/enumeration
122             # requires the original string. Regression tests prove this trick works.
123 15 100       148 return dualvar($v+0, $v) if $v =~ $fits_iv;
124              
125 8         30 my $big = Math::BigInt->new($v);
126 8 50       416 error __x"Value `{val}' is not a (big) integer", val => $big
127             if $big->is_nan;
128 8         71 $big;
129             }
130              
131             $builtin_types{integer} =
132             { parse => \&bigint
133             , check => sub { $_[0] =~ m/^\s*[-+]?\s*[0-9][\s0-9]*$/ }
134             , example => 42
135             , extends => 'decimal'
136             };
137              
138              
139             $builtin_types{negativeInteger} =
140             { parse => \&bigint
141             , check => sub { $_[0] =~ m/^\s*\-\s*[0-9][\s0-9]*$/ }
142             , example => '-1'
143             , extends => 'nonPositiveInteger'
144             };
145              
146              
147             $builtin_types{nonNegativeInteger} =
148             { parse => \&bigint
149             , check => sub { $_[0] =~ m/^\s*(?:\+\s*)?[0-9][\s0-9]*$/ }
150             , example => '17'
151             , extends => 'integer'
152             };
153              
154              
155             $builtin_types{positiveInteger} =
156             { parse => \&bigint
157             , check => sub { $_[0] =~ m/^\s*(?:\+\s*)?[0-9][\s0-9]*$/ && $_[0] =~ m/[1-9]/ }
158             , example => '+3'
159             , extends => 'nonNegativeInteger'
160             };
161              
162              
163             $builtin_types{nonPositiveInteger} =
164             { parse => \&bigint
165             , check => sub { $_[0] =~ m/^\s*(?:\-\s*)?[0-9][\s0-9]*$/
166             || $_[0] =~ m/^\s*(?:\+\s*)0[0\s]*$/ }
167             , example => '-42'
168             , extends => 'integer'
169             };
170              
171              
172             $builtin_types{long} =
173             { parse => \&bigint
174             , check =>
175             sub { $_[0] =~ m/^\s*[-+]?\s*[0-9][\s0-9]*$/ && ($_[0] =~ tr/0-9//) < 20 }
176             , example => '-100'
177             , extends => 'integer'
178             };
179              
180              
181             $builtin_types{unsignedLong} =
182             { parse => \&bigint
183             , check => sub {$_[0] =~ m/^\s*\+?\s*[0-9][\s0-9]*$/ && ($_[0] =~ tr/0-9//) < 21}
184             , example => '100'
185             , extends => 'nonNegativeInteger'
186             };
187              
188              
189             $builtin_types{unsignedInt} =
190             { parse => \&bigint
191             , check => sub {$_[0] =~ m/^\s*\+?\s*[0-9][\s0-9]*$/ && ($_[0] =~ tr/0-9//) <=10}
192             , example => '42'
193             , extends => 'unsignedLong'
194             };
195              
196             # Used when 'sloppy_integers' was set: the size of the values
197             # is illegally limited to the size of Perl's 32-bit signed integers.
198              
199             $builtin_types{non_pos_int} =
200             { parse => \&str2int
201             , format => \&int2str
202             , check => sub {$_[0] =~ m/^\s*[+-]?\s*[0-9][0-9\s]*$/ && $_[0] <= 0}
203             , example => '-12'
204             };
205              
206             $builtin_types{positive_int} =
207             { parse => \&str2int
208             , format => \&int2str
209             , check => sub {$_[0] =~ m/^\s*(?:\+\s*)?[0-9][0-9\s]*$/ }
210             , example => '+42'
211             };
212              
213             $builtin_types{negative_int} =
214             { parse => \&str2int
215             , format => \&int2str
216             , check => sub {$_[0] =~ m/^\s*\-\s*[0-9][0-9\s]*$/ }
217             , example => '-12'
218             };
219              
220             $builtin_types{unsigned_int} =
221             { parse => \&str2int
222             , format => \&int2str
223             , check => sub {$_[0] =~ m/^\s*(?:\+\s*)?[0-9][0-9\s]*$/ && $_[0] >= 0}
224             , example => '42'
225             };
226              
227              
228             $builtin_types{int} =
229             { parse => \&str2int
230             , format => \&int2str
231             , check => sub {$_[0] =~ m/^\s*[+-]?[0-9]+\s*$/}
232             , example => '42'
233             , extends => 'long'
234             };
235              
236              
237             $builtin_types{short} =
238             { parse => \&str2int
239             , format => \&int2str
240             , check =>
241             sub { $_[0] =~ m/^\s*[+-]?[0-9]+\s*$/ && $_[0] >= -32768 && $_[0] <= 32767 }
242             , example => '-7'
243             , extends => 'int'
244             };
245              
246              
247             $builtin_types{unsignedShort} =
248             { parse => \&str2int
249             , format => \&int2str
250             , check =>
251             sub { $_[0] =~ m/^\s*[+-]?[0-9]+\s*$/ && $_[0] >= 0 && $_[0] <= 65535 }
252             , example => '7'
253             , extends => 'unsignedInt'
254             };
255              
256              
257             $builtin_types{byte} =
258             { parse => \&str2int
259             , format => \&int2str
260             , check => sub {$_[0] =~ m/^\s*[+-]?[0-9]+\s*$/ && $_[0] >= -128 && $_[0] <=127}
261             , example => '-2'
262             , extends => 'short'
263             };
264              
265              
266             $builtin_types{unsignedByte} =
267             { parse => \&str2int
268             , format => \&int2str
269             , check => sub {$_[0] =~ m/^\s*[+-]?[0-9]+\s*$/ && $_[0] >= 0 && $_[0] <= 255}
270             , example => '2'
271             , extends => 'unsignedShort'
272             };
273              
274              
275             $builtin_types{decimal} =
276             { parse => sub {$_[0] =~ s/\s+//g; Math::BigFloat->new($_[0]) },
277             , check => sub {$_[0] =~ m/^(\+|\-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/}
278             , example => '3.1415'
279             , extends => 'anyAtomicType'
280             };
281              
282              
283             sub str2num
284 13     13 0 19 { my $s = shift;
285 13         31 $s =~ s/\s//g;
286              
287 13 100       92 $s =~ m/[^0-9]/ ? Math::BigFloat->new($s eq 'NaN' ? $s : lc $s) # INF->inf
    50          
    100          
288             : length $s < 9 ? dualvar($s+0, $s)
289             : Math::BigInt->new($s);
290             }
291              
292             sub num2str
293 15     15 0 22 { my $f = shift;
294             !ref $f ? $f
295             : !(UNIVERSAL::isa($f,'Math::BigInt') || UNIVERSAL::isa($f,'Math::BigFloat'))
296 50 100 33 50   1769 ? eval {use warnings FATAL => 'all'; $f + 0.0}
  50 50       118  
  50 100       11070  
  15         58  
  0         0  
297             : $f->is_nan ? 'NaN'
298             : uc $f->bstr; # [+-]inf -> [+-]INF, e->E doesn't matter
299             }
300              
301             sub numcheck($)
302 29     29 0 208 { $_[0] =~
303             m# [+-]? (?: [0-9]+(?:\.[0-9]*)?|\.[0-9]+) (?:[Ee][+-]?[0-9]+)?
304             | [+-]? INF
305             | NaN #x
306             }
307              
308             $builtin_types{precisionDecimal} =
309             $builtin_types{float} =
310             $builtin_types{double} =
311             { parse => \&str2num
312             , format => \&num2str
313             , check => \&numcheck
314             , example => '3.1415'
315             , extends => 'anyAtomicType'
316             };
317              
318             $builtin_types{sloppy_float} =
319             { parse => sub { $_[0] }
320             , check => sub {
321 50     50   354 my $v = eval {use warnings FATAL => 'all'; $_[0] + 0.0};
  50         120  
  50         132379  
322             $@ ? undef : 1;
323             }
324             , example => '3.1415'
325             , extends => 'anyAtomicType'
326             };
327              
328             $builtin_types{sloppy_float_force_NV} =
329             { %{$builtin_types{sloppy_float}}
330             , parse => sub { $_[0] + 0 }
331             };
332              
333              
334             $builtin_types{base64Binary} =
335             { parse => sub { eval { decode_base64 $_[0] }; }
336             , format => sub {
337             my $a = $_[0];
338             eval { utf8::downgrade($a) };
339             if($@)
340             { error __x"use Encode::encode() for base64Binary field at {path}"
341             , path => $_[2];
342             }
343             encode_base64 $a, '';
344             }
345             , check => sub { !$@ }
346             , example => 'decoded bytes'
347             , extends => 'anyAtomicType'
348             };
349              
350              
351             # (Use of) an XS implementation would be nice
352             $builtin_types{hexBinary} =
353             { parse => sub { (my $v = $_[0]) =~ s/\s+//g; pack 'H*', $v }
354             , format => sub { uc unpack 'H*', $_[0]}
355             , check => sub { (my $v = $_[0]) !~ m/[^0-9a-fA-F\s]/ or return 0;
356             ($v =~ tr/0-9a-fA-F//) % 2 == 0}
357             , example => 'F00F'
358             , extends => 'anyAtomicType'
359             };
360              
361              
362             my $yearFrag = qr/ \-? (?: [1-9][0-9]{3,} | 0[0-9][0-9][0-9] ) /x;
363             my $monthFrag = qr/ 0[1-9] | 1[0-2] /x;
364             my $dayFrag = qr/ 0[1-9] | [12][0-9] | 3[01] /x;
365             my $hourFrag = qr/ [01][0-9] | 2[0-3] /x;
366             my $minuteFrag = qr/ [0-5][0-9] /x;
367             my $secondFrag = qr/ [0-5][0-9] (?: \.[0-9]+)? /x;
368             my $endOfDayFrag = qr/24\:00\:00 (?: \.[0-9]+)? /x;
369             my $timezoneFrag = qr/Z | [+-] (?: 0[0-9] | 1[0-4] ) \: $minuteFrag/x;
370             my $timeFrag = qr/ (?: $hourFrag \: $minuteFrag \: $secondFrag )
371             | $endOfDayFrag
372             /x;
373              
374             my $date = qr/^ $yearFrag \- $monthFrag \- $dayFrag $timezoneFrag? $/x;
375              
376             $builtin_types{date} =
377             { parse => \&_collapse
378             , format => sub { $_[0] =~ /^[0-9]+$/ ? strftime("%Y-%m-%d", gmtime $_[0]) : $_[0]}
379             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $date }
380             , example => '2006-10-06'
381             , extends => 'anyAtomicType'
382             };
383              
384              
385             my $time = qr /^ $timeFrag $timezoneFrag? $/x;
386              
387             $builtin_types{time} =
388             { parse => \&_collapse
389             , format => sub { return $_[0] if $_[0] =~ /[^0-9.]/;
390             my $subsec = $_[0] =~ /(\.[0-9]+)/ ? $1 : '';
391             strftime "%T$subsec", gmtime $_[0] }
392             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $time }
393             , example => '11:12:13'
394             , extends => 'anyAtomicType'
395             };
396              
397              
398             my $dateTime
399             = qr/^ $yearFrag \- $monthFrag \- $dayFrag T $timeFrag $timezoneFrag? $/x;
400             my $dateTimeStamp
401             = qr/^ $yearFrag \- $monthFrag \- $dayFrag T $timeFrag $timezoneFrag $/x;
402              
403             sub _dt_format
404 5 50   5   28 { return $_[0] if $_[0] =~ /[^0-9.]/; # already formated
405 0 0       0 my $subsec = $_[0] =~ /(\.[0-9]+)/ ? $1 : '';
406 0         0 strftime "%Y-%m-%dT%H:%M:%S${subsec}Z", gmtime $_[0];
407             }
408              
409             $builtin_types{dateTime} =
410             { parse => \&_collapse
411             , format => \&_dt_format
412             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $dateTime }
413             , example => '2006-10-06T00:23:02Z'
414             , extends => 'anyAtomicType'
415             };
416              
417              
418             $builtin_types{dateTimeStamp} =
419             { parse => \&_collapse
420             , format => \&_dt_format
421             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $dateTimeStamp }
422             , example => '2006-10-06T00:23:02Z'
423             , extends => 'dateTime'
424             };
425              
426              
427             my $gDay = qr/^ \- \- \- $dayFrag $timezoneFrag? $/x;
428             $builtin_types{gDay} =
429             { parse => \&_collapse
430             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $gDay }
431             , example => '---12+09:00'
432             , extends => 'anyAtomicType'
433             };
434              
435              
436             my $gMonth = qr/^ \- \- $monthFrag $timezoneFrag? $/x;
437             $builtin_types{gMonth} =
438             { parse => \&_collapse
439             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $gMonth }
440             , example => '--09+07:00'
441             , extends => 'anyAtomicType'
442             };
443              
444              
445             my $gMonthDay = qr/^ \- \- $monthFrag \- $dayFrag $timezoneFrag? /x;
446             $builtin_types{gMonthDay} =
447             { parse => \&_collapse
448             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $gMonthDay }
449             , example => '--09-12+07:00'
450             , extends => 'anyAtomicType'
451             };
452              
453              
454             my $gYear = qr/^ $yearFrag $timezoneFrag? $/x;
455             $builtin_types{gYear} =
456             { parse => \&_collapse
457             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $gYear }
458             , example => '2006+07:00'
459             , extends => 'anyAtomicType'
460             };
461              
462              
463             my $gYearMonth = qr/^ $yearFrag \- $monthFrag $timezoneFrag? $/x;
464             $builtin_types{gYearMonth} =
465             { parse => \&_collapse
466             , check => sub { (my $val = $_[0]) =~ s/\s+//g; $val =~ $gYearMonth }
467             , example => '2006-11+07:00'
468             , extends => 'anyAtomicType'
469             };
470              
471              
472             $builtin_types{duration} =
473             { parse => \&_collapse
474             , check => sub { my $val = $_[0]; $val =~ s/\s+//g;
475             $val =~ m/^\-?P(?:[0-9]+Y)?(?:[0-9]+M)?(?:[0-9]+D)?
476             (?:T(?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?)?$/x }
477              
478             , example => 'P9M2DT3H5M'
479             };
480              
481              
482             $builtin_types{dayTimeDuration} =
483             { parse => \&_collapse
484             , check => sub { my $val = $_[0]; $val =~ s/\s+//g; $val =~
485             m/^\-?P(?:[0-9]+D)?(?:T(?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?)?$/ }
486             , example => 'P2DT3H5M10S'
487             , extends => 'duration'
488             };
489              
490              
491             $builtin_types{yearMonthDuration} =
492             { parse => \&_collapse
493             , check => sub { my $val = $_[0]; $val =~ s/\s+//g; $val =~
494             m/^\-?P(?:[0-9]+Y)?(?:[0-9]+M)?$/ }
495             , example => 'P40Y5M'
496             , extends => 'duration'
497             };
498              
499             #-------------
500              
501              
502             $builtin_types{string} =
503             { example => 'example'
504             , extends => 'anyAtomicType'
505             };
506              
507              
508             $builtin_types{normalizedString} =
509             { parse => \&_replace
510             , example => 'example'
511             , extends => 'string'
512             };
513              
514              
515             $builtin_types{language} =
516             { parse => \&_collapse
517             , check => sub { my $v = $_[0]; $v =~ s/\s+//g; $v =~
518             m/^[a-zA-Z]{1,8}(?:\-[a-zA-Z0-9]{1,8})*$/ }
519             , example => 'nl-NL'
520             , extends => 'token'
521             };
522              
523              
524             # NCName matches pattern [\i-[:]][\c-[:]]*
525             sub _ncname($)
526 2134     2134   5692 { (my $name = $_[0]) =~ s/\s//;
527 2134         11150 $name =~ m/^[[:alpha:]_](?:[\w.-]*)$/;
528             }
529              
530             my $ids = 0;
531             $builtin_types{ID} =
532             { parse => \&_collapse
533             , check => \&_ncname
534             , example => 'id_'.$ids++
535             , extends => 'NCName'
536             };
537              
538             $builtin_types{IDREF} =
539             { parse => \&_collapse
540             , check => \&_ncname
541             , example => 'id-ref'
542             , extends => 'NCName'
543             };
544              
545              
546             $builtin_types{NCName} =
547             { parse => \&_collapse
548             , check => \&_ncname
549             , example => 'label'
550             , extends => 'Name'
551             };
552              
553             $builtin_types{ENTITY} =
554             { parse => \&_collapse
555             , check => \&_ncname
556             , example => 'entity'
557             , extends => 'NCName'
558             };
559              
560             $builtin_types{IDREFS} =
561             $builtin_types{ENTITIES} =
562             { parse => sub { [ split ' ', shift ] }
563             , format => sub { my $v = shift; ref $v eq 'ARRAY' ? join(' ',@$v) : $v }
564             , check => sub { $_[0] !~ m/\:/ }
565             , example => 'labels'
566             , is_list => 1
567             , extends => 'anySimpleType'
568             };
569              
570              
571             $builtin_types{Name} =
572             { parse => \&_collapse
573             , example => 'name'
574             , extends => 'token'
575             };
576              
577              
578             $builtin_types{token} =
579             { parse => \&_collapse
580             , example => 'token'
581             , extends => 'normalizedString'
582             };
583              
584             # check required! \c
585             $builtin_types{NMTOKEN} =
586             { parse => sub { $_[0] =~ s/\s+//g; $_[0] }
587             , example => 'nmtoken'
588             , extends => 'token'
589             };
590              
591             $builtin_types{NMTOKENS} =
592             { parse => sub { [ split ' ', shift ] }
593             , check => sub { $_[0] =~ /\S/ }
594             , format => sub { my $v = shift; ref $v eq 'ARRAY' ? join(' ',@$v) : $v }
595             , example => 'nmtokens'
596             , is_list => 1
597             , extends => 'anySimpleType'
598             };
599              
600              
601             # relative uri's are also correct, so even empty strings... it
602             # cannot be checked without context.
603             # use Regexp::Common qw/URI/;
604             # check => sub { $_[0] =~ $RE{URI} }
605              
606             $builtin_types{anyURI} =
607             { parse => \&_collapse
608             , example => 'http://example.com'
609             , extends => 'anyAtomicType'
610             };
611              
612              
613             $builtin_types{QName} =
614             { parse =>
615             sub { my ($qname, $node) = @_;
616             $qname =~ s/\s//g;
617             my $prefix = $qname =~ s/^([^:]*)\:// ? $1 : '';
618              
619             $node = $node->node if $node->isa('XML::Compile::Iterator');
620             my $ns = $node->lookupNamespaceURI($prefix) || '';
621             pack_type $ns, $qname;
622             }
623             , format =>
624             sub { my ($type, $trans) = @_;
625             my ($ns, $local) = unpack_type $type;
626             length $ns or return $local;
627              
628             my $def = $trans->{$ns};
629             # let's hope that the namespace will get used somewhere else as
630             # well, to make it into the xmlns.
631             defined $def && exists $def->{used}
632             or error __x"QName formatting only works if the namespace is used for an element, not found {ns} for {local}", ns => $ns, local => $local;
633              
634             length $def->{prefix} ? "$def->{prefix}:$local" : $local;
635             }
636             , example => 'myns:local'
637             , extends => 'anyAtomicType'
638             };
639              
640              
641             $builtin_types{NOTATION} =
642             {
643             extends => 'anyAtomicType'
644             };
645              
646             #-------------
647              
648              
649             $builtin_types{binary} = { example => 'binary string' };
650              
651              
652             $builtin_types{timeDuration} = $builtin_types{duration};
653              
654              
655             $builtin_types{uriReference} = $builtin_types{anyURI};
656              
657             # These constants where removed from the spec in 2001. Probably
658             # no-one is using these (anymore)
659             # century = period => 'P100Y'
660             # recurringDate = duration => 'P24H', period => 'P1Y'
661             # recurringDay = duration => 'P24H', period => 'P1M'
662             # timeInstant = duration => 'P0Y', period => 'P0Y'
663             # timePeriod = duration => 'P0Y'
664             # year = period => 'P1Y'
665             # recurringDuration = ??
666              
667             # only in 2000/10 schemas
668             $builtin_types{CDATA} =
669             { parse => \&_replace
670             , example => 'CDATA'
671             };
672              
673             1;