File Coverage

lib/XML/Compile/Translate/Reader.pm
Criterion Covered Total %
statement 594 657 90.4
branch 360 502 71.7
condition 119 197 60.4
subroutine 122 133 91.7
pod 0 39 0.0
total 1195 1528 78.2


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