File Coverage

lib/XML/Compile/Translate/Reader.pm
Criterion Covered Total %
statement 595 658 90.4
branch 358 502 71.3
condition 118 197 59.9
subroutine 123 134 91.7
pod 0 39 0.0
total 1194 1530 78.0


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::Translate::Reader;
10 45     45   3553 use vars '$VERSION';
  45         96  
  45         3143  
11             $VERSION = '1.62';
12              
13 45     45   260 use base 'XML::Compile::Translate';
  45         81  
  45         4732  
14              
15 45     45   382 use strict;
  45         112  
  45         1035  
16 45     45   224 use warnings;
  45         118  
  45         1639  
17 45     45   261 no warnings 'once', 'recursion';
  45         134  
  45         2167  
18              
19 45     45   296 use Log::Report 'xml-compile';
  45         91  
  45         434  
20              
21 45     45   15592 use List::Util qw/first/;
  45         111  
  45         3247  
22 45     45   275 use Scalar::Util qw/weaken blessed/;
  45         77  
  45         2678  
23              
24 45     45   283 use XML::Compile::Util qw/pack_type odd_elements type_of_node SCHEMA2001i/;
  45         90  
  45         2894  
25 45     45   295 use XML::Compile::Iterator ();
  45         84  
  45         7419  
26              
27              
28             # Each action implementation returns a code reference, which will be
29             # used to do the run-time work. The mechanism of `closures' is used to
30             # keep the important information. Be sure that you understand closures
31             # before you attempt to change anything.
32              
33             # The returned reader subroutines will always be called
34             # my @pairs = $reader->($tree);
35              
36             # Some error messages are labeled with 'misfit' which is used to indicate
37             # that the structure of found data is not conforming the needs. For optional
38             # blocks, these errors are caught and un-done.
39              
40 1331     1331 0 6230 sub actsAs($) {$_[1] eq 'READER'}
41 935     935 0 2050 sub makeTagUnqualified(@) {$_[3]} # ($self, $path, $node, $local, $ns)
42 118     118 0 261 sub makeTagQualified(@) {$_[3]} # same params
43              
44             sub typemapToHooks($$)
45 396     396 0 840 { my ($self, $hooks, $typemap) = @_;
46 396         1587 while(my($type, $action) = each %$typemap)
47 3 50       9 { defined $action or next;
48 3         4 my $hook;
49 3 100       12 if(!ref $action)
    100          
50 1         2 { my $class = $action;
51 45     45   326 no strict 'refs';
  45         113  
  45         410860  
52 1 50       2 keys %{$class.'::'}
  1         7  
53             or error __x"class {pkg} for typemap {type} is not loaded"
54             , pkg => $class, type => $type;
55              
56 1 50       13 $class->can('fromXML')
57             or error __x"class {pkg} does not implement fromXML(), required for typemap {type}"
58             , pkg => $class, type => $type;
59              
60 1         7 trace "created reader hook for type $type to class $class";
61 1     1   28 $hook = sub { $class->fromXML($_[1], $type) };
  1         5  
62             }
63             elsif(ref $action eq 'CODE')
64 1     1   5 { $hook = sub { $action->(READER => $_[1], $type) };
  1         18  
65 1         7 trace "created reader hook for type $type to CODE";
66             }
67             else
68 1         2 { my $object = $action;
69 1 50       7 $object->can('fromXML')
70             or error __x"object of class {pkg} does not implement fromXML(), required for typemap {type}"
71             , pkg => ref($object), type => $type;
72              
73 1         7 trace "created reader hook for type $type to object";
74 1     1   26 $hook = sub {$object->fromXML($_[1], $type)};
  1         5  
75             }
76              
77 3         43 push @$hooks, +{action => 'READER', type => $type, after => $hook};
78             }
79 396         711 $hooks;
80             }
81              
82             sub makeElementWrapper
83 390     390 0 867 { my ($self, $path, $processor) = @_;
84             # no copy of $_[0], because it may be a large string
85 397     397   200441 sub { my $tree;
86 397 50 33     1927 if(blessed $_[0] && $_[0]->isa('XML::LibXML::Iterator'))
87 0         0 { $tree = $_[0];
88             }
89             else
90 397 100       1937 { my $xml = XML::Compile->dataToXML($_[0])
91             or return ();
92 396 50       3908 $xml = $xml->documentElement
93             if $xml->isa('XML::LibXML::Document');
94             $tree = XML::Compile::Iterator->new($xml, 'top',
95 396         2523 sub { $_[0]->isa('XML::LibXML::Element') } );
  856         2770  
96             }
97              
98 396         1215 my $data = ($processor->($tree))[-1];
99 328 50       887 unless(defined $data)
100 0         0 { my $node = $tree->node;
101 0         0 error __x"data not recognized, found a `{type}' at {where}"
102             , type => type_of_node $node, where => $node->nodePath;
103             }
104 328         1405 $data;
105 390         1985 };
106             }
107              
108             sub makeAttributeWrapper
109 4     4 0 10 { my ($self, $path, $processor) = @_;
110              
111 4     4   1818 sub { my $attr = shift;
112 4 50 0     44 ref $attr && $attr->isa('XML::LibXML::Attr')
      33        
113             or error __x"expects an attribute node, but got `{something}' at {path}"
114             , something => (ref $attr || $attr), path => $path;
115              
116 4         23 my $node = XML::LibXML::Element->new('dummy');
117 4         44 $node->addChild($attr);
118              
119 4         17 $processor->($node);
120 4         18 };
121             }
122              
123             sub makeWrapperNs # no namespaces in the HASH
124 62     62 0 177 { my ($self, $path, $processor, $index, $filter) = @_;
125 62         827 $processor;
126             }
127              
128             #
129             ## Element
130             #
131              
132             sub makeSequence($@)
133 220     220 0 749 { my ($self, $path, @pairs) = @_;
134 220 100       659 if(@pairs==2)
135 86         194 { my ($take, $action) = @pairs;
136             my $code
137             = (ref $action eq 'BLOCK' || ref $action eq 'ANY')
138 6     6   21 ? sub { $action->($_[0]) }
139 86 100 66 68   643 : sub { $action->($_[0] && $_[0]->currentType eq $take ? $_[0]:undef)};
  68 100 66     322  
140 86         535 return bless $code, 'BLOCK';
141             }
142              
143             bless
144 146     146   248 sub { my $tree = shift;
145 146         198 my @res;
146 146         394 my @do = @pairs;
147              
148 146         442 while(@do)
149 331         748 { my ($take, $do) = (shift @do, shift @do);
150 331 100 100     2184 push @res, ref $do eq 'BLOCK'
151             || ref $do eq 'ANY'
152             || (defined $tree && $tree->currentType eq $take)
153             ? $do->($tree) : $do->(undef);
154             }
155              
156 132         636 @res;
157 134         1190 }, 'BLOCK';
158             }
159              
160             sub makeChoice($@)
161 40     40 0 166 { my ($self, $path, %do) = @_;
162 40         57 my @specials;
163 40         153 foreach my $el (keys %do)
164             { push @specials, delete $do{$el}
165 91 100 66     405 if ref $do{$el} eq 'BLOCK' || ref $do{$el} eq 'ANY';
166             }
167              
168 40 100 100     139 if(keys %do==1 && !@specials)
169 4         10 { my ($option, $action) = %do;
170             return bless
171 4     4   5 sub { my $tree = shift;
172 4 50       14 my $type = defined $tree ? $tree->currentType : '';
173 4 100       14 return $action->($tree)
174             if $type eq $option;
175              
176 1         11 try { $action->(undef) }; # minOccurs=0
  1         267  
177 1 50       235 $@ or return ();
178              
179 1 50       11 $type
180             or error __x"element `{tag}' expected for choice at {path}"
181             , tag => $option, path => $path, _class => 'misfit';
182              
183 0         0 error __x"single choice option `{option}' at `{type}' at {path}"
184             , option => $option, type => $type, path => $path
185             , _class => 'misfit';
186 4         51 }, 'BLOCK';
187             }
188              
189             @specials or return bless
190 37     37   65 sub { my $tree = shift;
191 37 50       177 my $type = defined $tree ? $tree->currentType : undef;
192 37 50       111 my $elem = defined $type ? $do{$type} : undef;
193 37 100       113 return $elem->($tree) if $elem;
194              
195             # very silly situation: some people use a minOccurs within
196             # a choice, instead on choice itself. That always succeeds.
197 4         14 foreach my $some (values %do)
198 8         73 { try { $some->(undef) };
  8         2180  
199 8 100       1997 $@ or return ();
200             }
201              
202             $type
203 3 100       31 or error __x"no element left to pick choice at {path}"
204             , path => $path, _class => 'misfit';
205              
206 2         5 trace "choose element from @{[sort keys %do]}";
  2         22  
207 2         105 error __x"no applicable choice for `{tag}' at {path}"
208             , tag => $type, path => $path, _class => 'misfit';
209 36 100       266 }, 'BLOCK';
210              
211             return bless
212 10     10   15 sub { my $tree = shift;
213 10 50       33 my $type = defined $tree ? $tree->currentType : undef;
214 10 50       32 my $elem = defined $type ? $do{$type} : undef;
215 10 100       26 return $elem->($tree) if $elem;
216              
217 6         9 my @special_errors;
218 6         20 foreach (@specials)
219 6         32 { my @d = try { $_->($tree) };
  6         1645  
220 6 50 33     263 return @d if !$@ && @d;
221 0 0       0 push @special_errors, $@->wasFatal->message if $@;
222             }
223              
224 0         0 foreach my $some (values %do, @specials)
225 0         0 { try { $some->(undef) };
  0         0  
226 0 0       0 $@ or return ();
227             }
228              
229             $type
230 0 0       0 or error __x"choice needs more elements at {path}"
231             , path => $path, _class => 'misfit';
232              
233              
234 0         0 my @elems = sort keys %do;
235 0 0       0 trace "choose element from @elems or fix special at $path" if @elems;
236 0         0 trace "failed specials in choice: $_" for @special_errors;
237              
238 0         0 error __x"no applicable choice for `{tag}' at {path}"
239             , tag => $type, path => $path, _class => 'misfit';
240 10         77 }, 'BLOCK';
241             }
242              
243             sub makeAll($@)
244 30     30 0 120 { my ($self, $path, %pairs) = @_;
245 30         75 my %specials;
246 30         129 foreach my $el (keys %pairs)
247             { $specials{$el} = delete $pairs{$el}
248 80 100 66     309 if ref $pairs{$el} eq 'BLOCK' || ref $pairs{$el} eq 'ANY';
249             }
250              
251 30 100 100     115 if(!%specials && keys %pairs==1)
252 5         12 { my ($take, $do) = %pairs;
253             return bless
254 4     4   5 sub { my $tree = shift;
255 4 100 66     26 $do->($tree && $tree->currentType eq $take ? $tree : undef);
256 5         38 }, 'BLOCK';
257             }
258              
259             keys %specials or return bless
260 22     22   31 sub { my $tree = shift;
261 22         104 my %do = %pairs;
262 22         43 my @res;
263 22         28 while(1)
264 67 100 66     187 { my $type = $tree && $tree->currentType or last;
265 46 100       130 my $do = delete $do{$type} or last; # already seen?
266 45         94 push @res, $do->($tree);
267             }
268              
269             # saw all of all?
270             push @res, $_->(undef)
271 22         82 for values %do;
272              
273 9         42 @res;
274 25 100       185 }, 'BLOCK';
275              
276             # an 'all' block with nested structures or any is quite nasty. Don't
277             # forget that 'all' can have maxOccurs > 1 !
278             bless
279 3     3   4 sub { my $tree = shift;
280 3         14 my %do = %pairs;
281 3         7 my %spseen;
282             my @res;
283             PARTICLE:
284 3         5 while(1)
285 11 100       22 { my $type = $tree->currentType or last;
286 9 100       28 if(my $do = delete $do{$type})
287 6         14 { push @res, $do->($tree);
288 6         14 next PARTICLE;
289             }
290              
291 3         10 foreach (keys %specials)
292 3 50       8 { next if $spseen{$_};
293 3         22 my @d = try { $specials{$_}->($tree) };
  3         803  
294 3 100       336 next if $@;
295              
296 2         19 $spseen{$_}++;
297 2         7 push @res, @d;
298 2         5 next PARTICLE;
299             }
300              
301 1         9 last;
302             }
303 3 50       7 @res or return ();
304              
305             # saw all of all?
306             push @res, $_->(undef)
307 3         11 for values %do;
308              
309             push @res, $_->(undef)
310 3 100       10 for map {$spseen{$_} ? () : $specials{$_}} keys %specials;
  3         14  
311              
312 2         13 @res;
313 3         27 }, 'BLOCK';
314             }
315              
316             sub makeBlockHandler
317 299     299 0 852 { my ($self, $path, $label, $min, $max, $process, $kind, $multi) = @_;
318              
319             # flatten the HASH: when a block appears only once, there will
320             # not be an additional nesting in the output tree.
321 299 100 100     1240 if($max ne 'unbounded' && $max==1)
322             {
323 269 100       1397 return ($label => $process) if $min==1;
324              
325             my $code =
326 5 50   5   15 sub { my $tree = shift or return ();
327 5 100       14 my $starter = $tree->currentChild or return ();
328 4         50 my @pairs = try { $process->($tree) };
  4         1227  
329 4 100       599 if($@->wasFatal(class => 'misfit'))
    50          
330 2         127 { my $ending = $tree->currentChild;
331 2 100 66     12 $@->reportAll if !$ending || $ending!=$starter;
332 1         41 return ();
333             }
334 0         0 elsif($@) {$@->reportAll}
335 2         55 @pairs;
336 5         21 };
337 5         35 return ($label => bless($code, 'BLOCK'));
338             }
339              
340 30 50 66     127 if($max ne 'unbounded' && $min>=$max)
341             { my $code =
342 0     0   0 sub { my $tree = shift;
343 0         0 my @res;
344 0         0 while(@res < $min)
345 0         0 { my @pairs = $process->($tree);
346 0         0 push @res, {@pairs};
347             }
348 0         0 ($multi => \@res);
349 0         0 };
350 0         0 return ($label => bless($code, 'BLOCK'));
351             }
352              
353 30 100       91 if($min==0)
354             { my $code =
355 18 50   18   56 sub { my $tree = shift or return ();
356 18         31 my @res;
357 18   100     81 while($max eq 'unbounded' || @res < $max)
358 46 100       151 { my $starter = $tree->currentChild or last;
359 35         318 my @pairs = try { $process->($tree) };
  35         10430  
360 35 100       1737 if($@->wasFatal(class => 'misfit'))
    50          
361             { # misfit error is ok, if nothing consumed
362 3         263 trace "misfit $label ($min..$max) ".$@->wasFatal->message;
363 3         295 my $ending = $tree->currentChild;
364 3 50 33     11 $@->reportAll if !$ending || $ending!=$starter;
365 3         106 last;
366             }
367 0         0 elsif($@) {$@->reportAll}
368              
369 32 100       510 @pairs or last;
370 29         153 push @res, {@pairs};
371             }
372              
373 18 100       95 @res ? ($multi => \@res) : ();
374 18         95 };
375 18         135 return ($label => bless($code, 'BLOCK'));
376             }
377              
378             my $code =
379 10 50   10   36 sub { my $tree = shift or error __xn
380             "block with `{name}' is required at least once at {path}"
381             , "block with `{name}' is required at least {_count} times at {path}"
382             , $min, name => $label, path => $path;
383              
384 10         23 my @res;
385 10         31 while(@res < $min)
386 10         25 { my @pairs = $process->($tree);
387 8         46 push @res, {@pairs};
388             }
389 8   100     43 while($max eq 'unbounded' || @res < $max)
390 18 100       67 { my $starter = $tree->currentChild or last;
391 12         107 my @pairs = try { $process->($tree) };
  12         3499  
392 12 50       246 if($@->wasFatal(class => 'misfit'))
    50          
393             { # misfit error is ok, if nothing consumed
394 0         0 trace "misfit $label ($min..) ".$@->wasFatal->message;
395 0         0 my $ending = $tree->currentChild;
396 0 0 0     0 $@->reportAll if !$ending || $ending!=$starter;
397 0         0 last;
398             }
399 0         0 elsif($@) {$@->reportAll};
400              
401 12 50       239 @pairs or last;
402 12         65 push @res, {@pairs};
403             }
404 8         35 ($multi => \@res);
405 12         64 };
406              
407 12         79 ($label => bless($code, 'BLOCK'));
408             }
409              
410             sub makeElementHandler
411 522     522 0 1526 { my ($self, $path, $label, $min, $max, $required, $optional) = @_;
412 522 100   1   1172 $max eq "0" and return sub {}; # max can be "unbounded", hence strcmp
413              
414 521 100 100     2014 if($max ne 'unbounded' && $max==1)
415             { return $min==1
416 374     374   580 ? sub { my $tree = shift;
417 374 100       3020 my @pairs = $required->(defined $tree ? $tree->descend :undef);
418 339 100       1524 $tree->nextChild if defined $tree;
419 339         1245 ($label => $pairs[1]);
420             }
421 83 100   83   254 : sub { my $tree = shift or return ();
422 53 50       135 $tree->currentChild or return ();
423 53         317 my @pairs = $optional->($tree->descend);
424 52         239 $tree->nextChild;
425 52 50       136 @pairs or return ();
426 52         211 ($label => $pairs[1]);
427 495 100       4592 };
428             }
429            
430 26 100 100     127 if($max ne 'unbounded' && $min>=$max)
431             { return
432 2     2   4 sub { my $tree = shift;
433 2         3 my @res;
434 2         7 while(@res < $min)
435 4 50       39 { my @pairs = $required->(defined $tree ? $tree->descend:undef);
436 3         11 push @res, $pairs[1];
437 3 50       13 $tree->nextChild if defined $tree;
438             }
439 1 50       8 @res ? ($label => \@res) : ();
440 2         18 };
441             }
442              
443 24 100       60 if(!defined $required)
444             { return
445 22 100   22   69 sub { my $tree = shift or return ();
446 16         28 my @res;
447 16   66     65 while($max eq 'unbounded' || @res < $max)
448 50 100       126 { $tree->currentChild or last;
449 40         227 my @pairs = $optional->($tree->descend);
450 40 100       134 @pairs or last;
451 34         227 push @res, $pairs[1];
452 34         75 $tree->nextChild;
453             }
454 16 50       119 @res ? ($label => \@res) : ();
455 22         224 };
456             }
457              
458 2     2   5 sub { my $tree = shift;
459 2         4 my @res;
460 2         6 while(@res < $min)
461 2 50       31 { my @pairs = $required->(defined $tree ? $tree->descend : undef);
462 2         8 push @res, $pairs[1];
463 2 50       9 $tree->nextChild if defined $tree;
464             }
465 2   66     14 while(defined $tree && ($max eq 'unbounded' || @res < $max))
      66        
466 2 50       6 { $tree->currentChild or last;
467 2         19 my @pairs = $optional->($tree->descend);
468 2 100       8 @pairs or last;
469 1         2 push @res, $pairs[1];
470 1         4 $tree->nextChild;
471             }
472 2         10 ($label => \@res);
473 2         17 };
474             }
475              
476             sub makeRequired
477 429     429 0 956 { my ($self, $path, $label, $do) = @_;
478              
479             my $req =
480 380     380   582 sub { my $tree = shift; # can be undef
481 380         717 my @pairs = $do->($tree);
482             @pairs
483 375 100       958 or error __x"data for element or block starting with `{tag}' missing at {path}"
484             , tag => $label, path => $path, _class => 'misfit';
485 344         823 @pairs;
486 429         1645 };
487 429 50       1556 ref $do eq 'BLOCK' ? bless($req, 'BLOCK') : $req;
488             }
489              
490             sub makeElementHref
491 0     0 0 0 { my ($self, $path, $ns, $childname, $do) = @_;
492              
493 0     0   0 sub { my $tree = shift;
494              
495 0 0 0     0 return ($childname => $tree->node)
      0        
496             if defined $tree
497             && $tree->nodeType eq $childname
498             && $tree->node->hasAttribute('href');
499              
500 0         0 $do->($tree);
501 0         0 };
502             }
503              
504             sub makeElement
505 900     900 0 2484 { my ($self, $path, $ns, $childname, $do) = @_;
506 854     854   1195 sub { my $tree = shift;
507 854 100 100     2961 my $value = defined $tree && $tree->nodeType eq $childname
508             ? $do->($tree) : $do->(undef);
509 781 100       2461 defined $value ? ($childname => $value) : ();
510 900         3291 };
511             }
512              
513             sub makeElementDefault
514 19     19 0 65 { my ($self, $path, $ns, $childname, $do, $default) = @_;
515              
516 19         31 my $mode = $self->{default_values};
517             $mode eq 'IGNORE'
518             and return sub
519 2 50   2   8 { my $tree = shift or return ();
520 2 50 33     5 return () if $tree->nodeType ne $childname
521             || $tree->node->textContent eq '';
522 2         6 $do->($tree);
523 19 100       51 };
524              
525 17         42 my $def = $do->($default);
526              
527             $mode eq 'EXTEND'
528             and return sub
529 15     15   24 { my $tree = shift;
530 15 100 66     53 return ($childname => $def)
      100        
531             if !defined $tree
532             || $tree->nodeType ne $childname
533             || $tree->node->textContent eq '';
534              
535 7         20 $do->($tree);
536 17 100       88 };
537              
538             $mode eq 'MINIMAL'
539             and return sub
540 3 50   3   10 { my $tree = shift or return ();
541 3 50 33     9 return () if $tree->nodeType ne $childname
542             || $tree->node->textContent eq '';
543 3         8 my $v = $do->($tree);
544 3 100 66     19 undef $v if defined $v && $v eq $def;
545 3         9 ($childname => $v);
546 3 50       20 };
547              
548 0         0 error __x"illegal default_values mode `{mode}'", mode => $mode;
549             }
550              
551             sub makeElementFixed
552 3     3 0 10 { my ($self, $path, $ns, $childname, $do, $fixed) = @_;
553 3         6 my ($tag, $fix) = $do->($fixed);
554              
555 3     3   5 sub { my $tree = shift;
556 3 100 66     16 my ($label, $value)
557             = $tree && $tree->nodeType eq $childname ? $do->($tree) : ();
558              
559 3 100       10 defined $value
560             or return ($tag => $fix);
561              
562 2 50       6 $value eq $fix
563             or error __x"element `{name}' must have fixed value `{fixed}', got `{value}' at {path}"
564             , name => $childname, fixed => $fix, value => $value
565             , path => $path;
566              
567 2         61 ($label => $value);
568 3         733 };
569             }
570              
571             sub makeElementAbstract
572 9     9 0 26 { my ($self, $path, $ns, $childname, $do, $tag) = @_;
573 3 100   3   19 sub { my $tree = shift or return ();
574 2 50       13 $tree->nodeType eq $childname or return ();
575              
576 2         8 error __x"abstract element `{name}' used at {path}"
577             , name => $childname, path => $path;
578 9         42 };
579             }
580              
581             #
582             # complexType and complexType/ComplexContent
583             #
584              
585             # Be warned that the location reported in 'path' may not be the actual
586             # location, caused by the cashing of compiled schema components. The
587             # path you see is the first path where that element was encountered.
588             sub _not_processed($$)
589 4     4   14 { my ($child, $path) = @_;
590 4         16 error __x"element `{name}' not processed for {path} at {where}"
591             , name => type_of_node($child), path => $path
592             , _class => 'misfit', where => $child->nodePath;
593             }
594              
595             sub makeComplexElement
596 262     262 0 818 { my ($self, $path, $tag, $elems, $attrs, $attrs_any,undef,$is_nillable) = @_;
597             #my @e = @$elems; my @a = @$attrs;
598              
599 262         850 my @elems = odd_elements @$elems;
600 262         588 my @attrs = (odd_elements(@$attrs), @$attrs_any);
601              
602             $is_nillable and return
603 10 50   10   31 sub { my $tree = shift or return ();
604 10         23 my $node = $tree->node;
605 10 100       28 my %complex =
606             ( ($tree->nodeNil ? (_ => 'NIL') : (map $_->($tree), @elems))
607             , (map $_->($node), @attrs)
608             );
609              
610 10 50       29 _not_processed $tree->currentChild, $path
611             if $tree->currentChild;
612              
613 10         25 ($tag => \%complex);
614 262 100       2128 };
615              
616             @elems > 1 || @attrs and return
617 61 100   61   199 sub { my $tree = shift or return ();
618 60         124 my $node = $tree->node;
619 60         187 my %complex = ((map $_->($tree), @elems), (map $_->($node), @attrs));
620              
621 56 50       180 _not_processed $tree->currentChild, $path
622             if $tree->currentChild;
623              
624 56         143 ($tag => \%complex);
625 256 100 100     1395 };
626              
627             @elems || return
628 8 50   8   28 sub { my $tree = shift or return ();
629 8 50       22 _not_processed $tree->currentChild, $path
630             if $tree->currentChild;
631              
632 8         20 ($tag => {});
633 199 100       538 };
634              
635 189         309 my $el = shift @elems;
636 185 50   185   479 sub { my $tree = shift or return ();
637 185         449 my %complex = $el->($tree);
638              
639 156 100       525 _not_processed $tree->currentChild, $path
640             if $tree->currentChild;
641              
642 152         350 ($tag => \%complex);
643 189         1162 };
644             }
645              
646             #
647             # complexType/simpleContent
648             #
649              
650             sub makeTaggedElement
651 10     10 0 36 { my ($self, $path, $tag, $st, $attrs, $attrs_any,undef,$is_nillable) = @_;
652 10         41 my @attrs = (odd_elements(@$attrs), @$attrs_any);
653              
654 11   50 11   29 sub { my $tree = shift // return ();
655 11 100 66     49 my $simple = $is_nillable && ref $tree && $tree->nodeNil ? 'NIL' : $st->($tree);
656 11 100       42 ref $tree or return ($tag => {_ => $simple});
657 10         28 my $node = $tree->node;
658 10         33 my @pairs = map $_->($node), @attrs;
659 10 50 33     68 defined $simple || @pairs ? ($tag => {_ => $simple, @pairs}) : ();
660 10         69 };
661             }
662              
663             #
664             # complexType mixed or complexContent mixed
665             #
666              
667             sub makeMixedElement
668 6     6 0 22 { my ($self, $path, $tag, $elems, $attrs, $attrs_any,undef,$is_nillable) = @_;
669 6         22 my @attrs = (odd_elements(@$attrs), @$attrs_any);
670             my $mixed = $self->{mixed_elements}
671 6 50       17 or panic "how to handle mixed?";
672 6 50       15 $is_nillable and panic "nillable mixed not yet supported";
673              
674             ref $mixed eq 'CODE'
675 1 50   1   7 ? sub { my $tree = shift or return;
676 1 50       4 my $node = $tree->node or return;
677 1         10 my @v = $mixed->($path, $node);
678 1 50       9 @v ? ($tag => $v[0]) : ();
679             }
680              
681             : $mixed eq 'XML_NODE'
682 1 50   1   7 ? sub {$_[0] ? ($tag => $_[0]->node) : () }
683              
684             : $mixed eq 'ATTRIBUTES'
685 2 50   2   7 ? sub { my $tree = shift or return;
686 2         5 my $node = $tree->node;
687 2         8 my @pairs = map $_->($node), @attrs;
688 2         11 ($tag => { _ => $node, @pairs
689             , _MIXED_ELEMENT_MODE => 'ATTRIBUTES'});
690             }
691             : $mixed eq 'TEXTUAL'
692 1 50   1   5 ? sub { my $tree = shift or return;
693 1         4 my $node = $tree->node;
694 1         6 my @pairs = map $_->($node), @attrs;
695 1         18 ($tag => { _ => $node->textContent, @pairs
696             , _MIXED_ELEMENT_MODE => 'TEXTUAL'});
697             }
698             : $mixed eq 'XML_STRING'
699 1 50   1   6 ? sub { my $tree = shift or return;
700 1 50       4 my $node = $tree->node or return;
701 1         26 ($tag => $node->toString);
702             }
703 6 0       54 : $mixed eq 'STRUCTURAL'
    50          
    100          
    100          
    100          
    100          
704              
705             # this cannot be reached, because handled somewhere else
706             ? panic "mixed structural handled as normal element"
707              
708             : error __x"unknown mixed_elements value `{value}'", value => $mixed;
709             }
710              
711             #
712             # simpleType
713             #
714              
715             sub makeSimpleElement
716 653     653 0 1901 { my ( $self, $path, $tag, $st, undef, undef, $comptype, $is_nillable) = @_;
717              
718             $is_nillable
719 15   100 15   35 ? sub { my $tree = shift // return $st->(undef);
720 14 100 66     51 my $value = (ref $tree && $tree->nodeNil) ? 'NIL' : $st->($tree);
721 14 50       39 defined $value ? ($tag => $value) : ();
722             }
723 592     592   1291 : sub { my $value = $st->(@_);
724 556 100       1814 defined $value ? ($tag => $value) : ();
725 653 100       3210 };
726              
727             }
728              
729             sub default_anytype_handler($$)
730 1     1 0 7 { my ($path, $node) = @_;
731 1 50       5 ref $node or return $node;
732 1 50   1   6 (first{ UNIVERSAL::isa($_, 'XML::LibXML::Element') } $node->childNodes)
  1         27  
733             ? $node : $node->textContent;
734             }
735              
736             sub makeBuiltin
737 796     796 0 1878 { my ($self, $path, $node, $type, $def, $check_values) = @_;
738              
739 796 100       2138 if($type =~ m/}anyType$/)
740             {
741 8 100       23 if(my $a = $self->{any_type})
742             { return sub {
743 1 50 33 1   13 my $node
744             = ref $_[0] && UNIVERSAL::isa($_[0], 'XML::Compile::Iterator')
745             ? $_[0]->node : $_[0];
746 1         9 $a->( $path, $node, \&default_anytype_handler)};
  1         6  
747             }
748             else
749             { return sub
750 7 50   7   25 { ref $_[0] or return $_[0];
751 7 100       37 my $node = UNIVERSAL::isa($_[0], 'XML::Compile::Iterator')
752             ? $_[0]->node : $_[0];
753 5         105 (first{ UNIVERSAL::isa($_, 'XML::LibXML::Element') }
754 7 100       44 $node->childNodes) ? $node : $node->textContent;
755 7         49 };
756             }
757             }
758              
759 788 50       1866 my $check = $check_values ? $def->{check} : undef;
760 788         1142 my $parse = $def->{parse};
761 788 100       2894 my $err = $path eq $type
762             ? N__"illegal value `{value}' for type {type}"
763             : N__"illegal value `{value}' for type {type} at {path}";
764              
765             $check
766             ? ( defined $parse
767 665 100   665   2256 ? sub { my $value = ref $_[0] ? $_[0]->textContent : $_[0];
768 665 100       1505 defined $value or return undef;
769 629 100 100     1620 return $parse->($value, $_[1]||$_[0])
770             if $check->($value);
771 12         46 error __x$err, value => $value, type => $type, path => $path;
772             }
773 0 0   0   0 : sub { my $value = ref $_[0] ? $_[0]->textContent : $_[0];
774 0 0       0 defined $value or return undef;
775 0 0       0 return $value if $check->($value);
776 0         0 error __x$err, value => $value, type => $type, path => $path;
777             }
778             )
779              
780             : ( defined $parse
781 13 100   13   52 ? sub { my $value = ref $_[0] ? $_[0]->textContent : $_[0];
782 13 50       39 defined $value or return undef;
783 13   66     64 $parse->($value, $_[1]||$_[0]);
784             }
785 55 100   55   251 : sub { ref $_[0] ? shift->textContent : $_[0] }
786 788 50       6878 );
    100          
    100          
787             }
788              
789             sub makeList
790 28     28 0 57 { my ($self, $path, $st) = @_;
791 27   50 27   65 sub { my $tree = shift // return undef;
792 27 100       148 my $node
    50          
793             = UNIVERSAL::isa($tree, 'XML::LibXML::Node') ? $tree
794             : ref $tree ? $tree->node : undef;
795 27 100       81 my $v = ref $tree ? $tree->textContent : $tree;
796 27         117 [ grep defined, map $st->($_, $node), split " ", $v ];
797 28         150 };
798             }
799              
800             sub makeFacetsList
801 11     11 0 27 { my ($self, $path, $st, $info, $early, $late) = @_;
802 11         28 my @e = grep defined, @$early;
803 11         35 my @l = grep defined, @$late;
804              
805             # enumeration and pattern are probably rare
806             @e or return sub {
807 7   50 7   19 my $values = $st->(@_) // return;
808 7         32 $_->($values) for @l;
809 4         9 $values;
810 11 100       61 };
811              
812 4 50   4   10 sub { defined $_[0] or return undef;
813 4 50       27 my $list = ref $_[0] ? $_[0]->textContent : $_[0];
814 4         13 $_->($list) for @e;
815 3   50     7 my $values = $st->($_[0]) // return;
816 3         8 $_->($values) for @l;
817 3         5 $values;
818 4         20 };
819             }
820              
821             sub makeFacets
822 94     94 0 242 { my ($self, $path, $st, $info, $early, $late) = @_;
823 94 100 100     402 @$early || @$late or return $st;
824              
825 93 100       205 unless(@$early)
826             { return sub {
827 73     73   170 my $v = $st->(shift);
828 72 50       1683 defined $v or return undef;
829 72         253 $v = $_->($v) for @$late;
830 47         152 $v;
831 79         516 };
832             }
833              
834             sub {
835 12     12   20 my $v = shift;
836 12 50       34 if(@$early)
837 12 50       35 { return if !defined $v;
838 12         44 $v = $_->($v) for @$early;
839             }
840 9   50     24 $v = $st->($v) // return undef;
841 9         21 $v = $_->($v) for @$late;
842 9         18 $v;
843 14         92 };
844             }
845              
846             sub makeUnion
847 19     19 0 53 { my ($self, $path, @types) = @_;
848 26   50 26   112 sub { my $tree = shift // return undef;
849 26 100       53 for(@types) { my $v = try { $_->($tree) }; $@ or return $v }
  39         289  
  39         10800  
  39         4537  
850 3 100       32 my $text = ref $tree ? $tree->textContent : $tree;
851              
852 3 50       13 substr $text, 20, -5, '...' if length($text) > 50;
853 3         11 error __x"no match for `{text}' in union at {path}"
854             , text => $text, path => $path;
855 19         78 };
856             }
857              
858             # Attributes
859              
860             sub makeAttributeRequired
861 12     12 0 34 { my ($self, $path, $ns, $tag, $label, $do) = @_;
862 12     12   62 sub { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
863 12 100       39 defined $node
864             or error __x"attribute `{name}' is required at {path}"
865             , name => $tag, path => $path;
866              
867 11 50       63 defined $node or return ();
868 11         39 my $value = $do->($node);
869 11 50       109 defined $value ? ($label => $value) : ();
870 12         56 };
871             }
872              
873             sub makeAttributeProhibited
874 3     3 0 8 { my ($self, $path, $ns, $tag, $label, $do) = @_;
875 3     3   10 sub { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
876 3 100       8 defined $node or return ();
877 1         4 error __x"attribute `{name}' is prohibited at {path}"
878             , name => $tag, path => $path;
879 0         0 ();
880 3         9 };
881             }
882              
883             sub makeAttribute
884 93     93 0 274 { my ($self, $path, $ns, $tag, $label, $do) = @_;
885 92     92   527 sub { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
886 92 100       265 defined $node or return ();
887 70         166 my $val = $do->($node);
888 68 50       450 defined $val ? ($label => $val) : ();
889 93         404 };
890             }
891              
892             sub makeAttributeDefault
893 7     7 0 26 { my ($self, $path, $ns, $tag, $label, $do, $default) = @_;
894              
895 7         13 my $mode = $self->{default_values};
896             $mode eq 'IGNORE'
897             and return sub
898 3     3   19 { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
899 7 100       32 defined $node ? ($label => $do->($node)) : () };
  3 100       14  
900              
901 5         10 my $def = $do->($default);
902              
903             $mode eq 'EXTEND'
904             and return sub
905 4     4   20 { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
906 4 100       17 ($label => ($node ? $do->($node) : $def))
907 5 100       33 };
908              
909             $mode eq 'MINIMAL'
910             and return sub
911 3     3   12 { my $node = $_[0]->getAttributeNodeNS($ns, $tag);
912 3 100       6 my $v = $node ? $do->($node) : $def;
913 3 100 66     27 !defined $v || $v eq $def ? () : ($label => $v);
914 2 50       15 };
915              
916 0         0 error __x"illegal default_values mode `{mode}'", mode => $mode;
917             }
918              
919             sub makeAttributeFixed
920 5     5 0 15 { my ($self, $path, $ns, $tag, $label, $do, $fixed) = @_;
921 5         9 my $def = $do->($fixed);
922              
923 5 100   5   31 sub { my $node = $_[0]->getAttributeNodeNS($ns, $tag)
924             or return ($label => $def);
925              
926 4         24 my $value = $do->($node);
927 4 100 66     39 defined $value && $value eq $def
928             or error __x"value of attribute `{tag}' is fixed to `{fixed}', not `{value}' at {path}"
929             , tag => $tag, fixed => $def, value => $value, path => $path;
930              
931 3         19 ($label => $def);
932 5         24 };
933             }
934              
935             # SubstitutionGroups
936              
937             sub makeSubstgroup
938 9     9 0 43 { my ($self, $path, $base, %do) = @_;
939 9 50   0   30 keys %do or return bless sub { () }, 'BLOCK';
  0         0  
940              
941             bless
942 14     14   28 sub { my $tree = shift;
943 14 50       54 my $type = ($tree ? $tree->currentType : undef)
    50          
944             or error __x"no data for substitution group {type} at {path}"
945             , type => $base, path => $path, class => 'misfit';
946              
947 14 100       51 my $do = $do{$type} or return ();
948 11         28 my @subst = $do->[1]($tree->descend);
949 10 50       38 @subst or return ();
950              
951 10         120 $tree->nextChild;
952 10         39 ($do->[0] => $subst[1]); # key-rewrite
953 9         62 }, 'BLOCK';
954             }
955              
956             # anyAttribute
957              
958             sub makeAnyAttribute
959 5     5 0 21 { my ($self, $path, $handler, $yes, $no, $process) = @_;
960 5 100       18 return () unless defined $handler;
961              
962 4 100       9 my %yes = map +($_ => 1), @{$yes || []};
  4         26  
963 4 100       11 my %no = map +($_ => 1), @{$no || []};
  4         25  
964              
965             # Takes all, before filtering
966             my $all =
967 4     4   11 sub { my @result;
968 4         25 foreach my $attr ($_[0]->attributes)
969 16 100       148 { $attr->isa('XML::LibXML::Attr') or next;
970 8   50     57 my $ns = $attr->namespaceURI || $_[0]->namespaceURI || '';
971 8 100 100     36 next if keys %yes && !$yes{$ns};
972 7 100 100     26 next if keys %no && $no{$ns};
973              
974 6         30 push @result, pack_type($ns, $attr->localName) => $attr;
975             }
976 4         40 @result;
977 4         25 };
978              
979 4         18 weaken $self;
980              
981             # Create filter if requested
982             my $run = $handler eq 'TAKE_ALL' ? $all
983             : ref $handler ne 'CODE'
984             ? error(__x"any_attribute handler `{got}' not understood", got => $handler)
985 1     1   5 : sub { my @attrs = $all->(@_);
986 1         3 my @result;
987 1         4 while(@attrs)
988 2         9 { my ($type, $data) = (shift @attrs, shift @attrs);
989 2         9 my ($label, $out) = $handler->($type, $data, $path, $self);
990 2 100       1678 push @result, $label, $out if defined $label;
991             }
992 1         9 @result;
993 4 50       21 };
    100          
994              
995 4         19 bless $run, 'ANY';
996             }
997              
998             # anyElement
999              
1000             sub makeAnyElement
1001 5     5 0 24 { my ($self, $path, $handler, $yes, $no, $process, $min, $max) = @_;
1002 5   100     16 $handler ||= 'SKIP_ALL';
1003              
1004 5 100       10 my %yes = map +($_ => 1), @{$yes || []};
  5         30  
1005 5 100       10 my %no = map +($_ => 1), @{$no || []};
  5         24  
1006              
1007             # Takes all, before filtering
1008             my $any = ($max eq 'unbounded' || $max > 1)
1009             ? sub
1010 5 50   5   26 { my $tree = shift or return ();
1011 5         9 my $count = 0;
1012 5         17 my %result;
1013 5   33     17 while( (my $child = $tree->currentChild)
      66        
1014             && ($max eq 'unbounded' || $count < $max))
1015 2   50     31 { my $ns = $child->namespaceURI || '';
1016 2 100 50     10 $yes{$ns} or last if keys %yes;
1017 2 100 50     10 $no{$ns} and last if keys %no;
1018              
1019 2         11 my $k = pack_type $ns, $child->localName;
1020 2         6 push @{$result{$k}}, $child;
  2         7  
1021 2         4 $count++;
1022 2         9 $tree->nextChild;
1023             }
1024              
1025 5 50       19 $count >= $min
1026             or error __x"too few any elements, requires {min} and got {found}"
1027             , min => $min, found => $count;
1028              
1029 5         22 %result;
1030             }
1031             : sub
1032 0 0   0   0 { my $tree = shift or return ();
1033 0 0       0 my $child = $tree->currentChild or return ();
1034 0   0     0 my $ns = $child->namespaceURI || '';
1035              
1036 0 0 0     0 (!keys %yes || $yes{$ns}) && !(keys %no && $no{$ns})
      0        
      0        
1037             or return ();
1038              
1039 0         0 $tree->nextChild;
1040 0         0 (type_of_node($child), $child);
1041 5 50 33     51 };
1042            
1043 5         20 bless $any, 'ANY';
1044              
1045             # I would like to weaken here, but "ANY" needs the whole compiler structure
1046             # intact: someone has to catch it.
1047             # weaken $self;
1048              
1049             # Create filter if requested
1050             my $run
1051             = $handler eq 'TAKE_ALL' ? $any
1052 1     1   3 : $handler eq 'SKIP_ALL' ? sub { $any->(@_); () }
  1         3  
1053             : ref $handler ne 'CODE'
1054             ? error(__x"any_element handler `{got}' not understood", got => $handler)
1055 0     0   0 : sub { my @elems = $any->(@_);
1056 0         0 my @result;
1057 0         0 while(@elems)
1058 0         0 { my ($type, $data) = (shift @elems, shift @elems);
1059 0         0 my ($label, $out) = $handler->($type, $data, $path, $self);
1060 0 0       0 push @result, $label, $out if defined $label;
1061             }
1062 0         0 @result;
1063 5 0       17 };
    50          
    100          
1064              
1065 5         39 bless $run, 'ANY';
1066             }
1067              
1068             # xsi:type handling
1069              
1070             sub makeXsiTypeSwitch($$$$)
1071 3     3 0 10 { my ($self, $where, $elem, $default_type, $types) = @_;
1072              
1073             sub {
1074 7 50   7   16 my $tree = shift or return;
1075 7 50       15 my $node = $tree->node or return;
1076 7         46 my $type = $node->getAttributeNS(SCHEMA2001i, 'type');
1077 7         107 my ($alt, $code);
1078 7 100       16 if($type)
1079 6 50       23 { my ($pre, $local) = $type =~ /(.*?)\:(.*)/ ? ($1, $2) : ('',$type);
1080 6         50 $alt = pack_type $node->lookupNamespaceURI($pre), $local;
1081 6 50       27 $code = $types->{$alt}
1082             or error __x"specified xsi:type list for `{default}' does not contain `{got}'"
1083             , default => $default_type, got => $type;
1084             }
1085             else
1086 1         3 { ($alt, $code) = ($default_type, $types->{$default_type});
1087             }
1088              
1089 7         18 my ($t, $d) = $code->($tree);
1090 7 100       17 defined $t or return ();
1091              
1092 6 50       22 $d = { _ => $d } if ref $d ne 'HASH';
1093 6   33     26 $d->{XSI_TYPE} ||= $alt;
1094 6         21 ($t, $d);
1095 3         17 };
1096             }
1097              
1098             # any kind of hook
1099              
1100             sub makeHook($$$$$$$)
1101 11     11 0 32 { my ($self, $path, $r, $tag, $before, $replace, $after, $fulltype) = @_;
1102 11 50 100     46 return $r unless $before || $replace || $after;
      66        
1103              
1104 1     1   4 return sub { ($_[0]->node->localName => 'SKIPPED') }
1105 11 100 66     47 if $replace && grep $_ eq 'SKIP', @$replace;
1106              
1107 10 50       20 my @replace = $replace ? map $self->_decodeReplace($path,$_),@$replace : ();
1108 10 100       31 my @before = $before ? map $self->_decodeBefore($path,$_), @$before : ();
1109 10 50       46 my @after = $after ? map $self->_decodeAfter($path,$_), @$after : ();
1110              
1111 10         82 weaken $self;
1112              
1113             sub
1114 10 50   10   27 { my $tree = shift or return ();
1115 10         25 my $xml = $tree->node;
1116 10         25 foreach (@before)
1117 3         7 { $xml = $_->($xml, $path, $fulltype);
1118 3 50       15 defined $xml or return ();
1119             }
1120              
1121 10         45 my $process = sub { $r->($tree->descend($xml)) };
  10         27  
1122 10 50       29 my @h = @replace
1123             ? map $_->($xml, $self, $path, $tag, $process, $fulltype), @replace
1124             : $process->();
1125              
1126 10 50       35 @h or return ();
1127 10 50       98 my $h = @h==1 ? $h[0] : $h[1]; # detect simpleType
1128 10         22 foreach my $after (@after)
1129 13         32 { $h = $after->($xml, $h, $path, $fulltype);
1130 13 50       3540 defined $h or return ();
1131             }
1132 10         50 ($tag => $h);
1133 10         69 };
1134             }
1135              
1136             sub _decodeBefore($$)
1137 3     3   8 { my ($self, $path, $call) = @_;
1138 3 50       13 return $call if ref $call eq 'CODE';
1139              
1140 0     0   0 $call eq 'PRINT_PATH' ? sub {print "$_[1]\n"; $_[0] }
  0         0  
1141 0 0       0 : error __x"labeled before hook `{call}' undefined for READER", call=>$call;
1142             }
1143              
1144             sub _decodeReplace($$)
1145 0     0   0 { my ($self, $path, $call) = @_;
1146 0 0       0 return $call if ref $call eq 'CODE';
1147              
1148 0     0   0 $call eq 'XML_NODE' ? sub { ($_[3] => $_[0]) } # don't parse XML
1149 0 0       0 : error __x"labeled replace hook `{call}' undefined for READER",call=>$call;
1150             }
1151              
1152             my %after =
1153             ( PRINT_PATH => sub {print "$_[2]\n"; $_[1] }
1154             , INCLUDE_PATH => sub { my $h = $_[1];
1155             $h = { _ => $h } if ref $h ne 'HASH';
1156             $h->{_PATH} = $_[0];
1157             $h;
1158             }
1159             , XML_NODE => sub { my $h = $_[1];
1160             $h = { _ => $h } if ref $h ne 'HASH';
1161             $h->{_XML_NODE} = $_[0];
1162             $h;
1163             }
1164             , ELEMENT_ORDER => sub { my ($xml, $h) = @_;
1165             $h = { _ => $h } if ref $h ne 'HASH';
1166             my @order = map type_of_node($_)
1167             , grep $_->isa('XML::LibXML::Element'), $xml->childNodes;
1168             $h->{_ELEMENT_ORDER} = \@order;
1169             $h;
1170             }
1171             , ATTRIBUTE_ORDER => sub { my ($xml, $h) = @_;
1172             $h = { _ => $h } if ref $h ne 'HASH';
1173             my @order = map $_->nodeName, $xml->attributes;
1174             $h->{_ATTRIBUTE_ORDER} = \@order;
1175             $h;
1176             }
1177             , NODE_TYPE => sub { my ($xml, $h) = @_;
1178             $h = { _ => $h } if ref $h ne 'HASH';
1179             $h->{_NODE_TYPE} = type_of_node $xml;
1180             $h;
1181             }
1182             );
1183              
1184             sub _decodeAfter($$)
1185 13     13   27 { my ($self, $path, $call) = @_;
1186 13 100       36 return $call if ref $call eq 'CODE';
1187              
1188             # The 'after' can be called on a single. In that case, turn it into
1189             # a HASH for additional information.
1190 6 50       15 my $dec = $after{$call}
1191             or error __x"labeled after hook `{call}' undefined for READER"
1192             , call=> $call;
1193              
1194 6         14 $dec;
1195             }
1196              
1197             sub makeBlocked($$$)
1198 19     19 0 64 { my ($self, $where, $class, $type) = @_;
1199 19   33     58 my $err_type = $self->prefixed($type) || $type;
1200              
1201             # errors are produced in class=misfit to allow other choices to succeed.
1202             $class eq 'anyType'
1203 5     5   25 ? { st => sub { error __x"use of `{type}' blocked at {where}"
1204             , type => $err_type, where => $where, _class => 'misfit';
1205             }}
1206             : $class eq 'simpleType'
1207 2     2   11 ? { st => sub { error __x"use of {class} `{type}' blocked at {where}"
1208             , class => $class, type => $err_type, where => $where
1209             , _class => 'misfit';
1210             }}
1211             : $class eq 'complexType'
1212             ? { elems => [] }
1213             : $class eq 'ref'
1214 0     0     ? { st => sub { error __x"use of referenced `{type}' blocked at {where}"
1215             , type => $err_type, where => $where, _class => 'misfit';
1216             }}
1217 19 50       227 : panic "blocking of $class for $type not implemented";
    100          
    100          
    100          
1218             }
1219              
1220             #-----------------------------------
1221              
1222              
1223             1;