File Coverage

lib/XML/Compile/Cache.pm
Criterion Covered Total %
statement 193 317 60.8
branch 99 244 40.5
condition 28 44 63.6
subroutine 29 44 65.9
pod 23 26 88.4
total 372 675 55.1


line stmt bran cond sub pod time code
1             # Copyrights 2008-2018 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::Cache;
10 3     3   337178 use vars '$VERSION';
  3         22  
  3         178  
11             $VERSION = '1.06';
12              
13 3     3   18 use base 'XML::Compile::Schema';
  3         6  
  3         1531  
14              
15 3     3   571264 use warnings;
  3         7  
  3         86  
16 3     3   18 use strict;
  3         9  
  3         82  
17              
18 3     3   17 use Log::Report 'xml-compile-cache';
  3         11  
  3         17  
19              
20 3     3   920 use XML::Compile::Util qw/pack_type unpack_type/;
  3         7  
  3         200  
21 3     3   19 use List::Util qw/first/;
  3         7  
  3         173  
22 3     3   20 use Scalar::Util qw/weaken/;
  3         5  
  3         142  
23 3     3   1650 use XML::LibXML::Simple qw/XMLin/;
  3         11111  
  3         13832  
24              
25              
26             sub init($)
27 2     2 0 317 { my ($self, $args) = @_;
28 2         13 $self->addPrefixes($args->{prefixes});
29              
30 2         20 $self->SUPER::init($args);
31              
32 2   50     833 $self->{XCC_opts} = delete $args->{opts_rw} || [];
33 2   50     11 $self->{XCC_ropts} = delete $args->{opts_readers} || [];
34 2   50     14 $self->{XCC_wopts} = delete $args->{opts_writers} || [];
35 2   50     19 $self->{XCC_undecl} = delete $args->{allow_undeclared} || 0;
36              
37 2         6 $self->{XCC_dropts} = {}; # declared opts
38 2         4 $self->{XCC_dwopts} = {};
39 2         8 $self->{XCC_uropts} = {}; # undeclared opts
40 2         5 $self->{XCC_uwopts} = {};
41              
42 2         5 $self->{XCC_readers} = {}; # compiled code refs;
43 2         4 $self->{XCC_writers} = {};
44              
45 2         10 $self->typemap($args->{typemap});
46 2         23 $self->xsiType($args->{xsi_type});
47 2   50     22 $self->anyElement($args->{any_element} || 'ATTEMPT');
48              
49 2         8 $self;
50             }
51              
52             #----------------------
53              
54              
55             sub typemap(@)
56 2     2 1 5 { my $self = shift;
57 2   50     11 my $t = $self->{XCC_typemap} ||= {};
58             my @d = @_ > 1 ? @_ : !defined $_[0] ? ()
59 2 0       13 : ref $_[0] eq 'HASH' ? %{$_[0]} : @{$_[0]};
  0 50       0  
  0 50       0  
60 2         9 while(@d) { my $k = $self->findName(shift @d); $t->{$k} = shift @d }
  0         0  
  0         0  
61 2         4 $t;
62             }
63              
64              
65             sub addXsiType(@)
66 3     3 1 14 { my $self = shift;
67 3   100     16 my $x = $self->{XCC_xsi_type} ||= {};
68             my @d = @_ > 1 ? @_ : !defined $_[0] ? ()
69 3 0       18 : ref $_[0] eq 'HASH' ? %{$_[0]} : @{$_[0]};
  0 50       0  
  0 100       0  
70              
71 3         11 while(@d)
72 1         5 { my $k = $self->findName(shift @d);
73 1         9 my $a = shift @d;
74 1 50 50     6 $a = $self->namespaces->autoexpand_xsi_type($k) || []
75             if $a eq 'AUTO';
76              
77 1 50       594 push @{$x->{$k}}
  1         12  
78             , ref $a eq 'ARRAY' ? (map $self->findName($_), @$a)
79             : $self->findName($a);
80             }
81              
82 3         7 $x;
83             }
84             *xsiType = \&addXsiType;
85              
86              
87             sub allowUndeclared(;$)
88 7     7 1 1298 { my $self = shift;
89 7 100       34 @_ ? ($self->{XCC_undecl} = shift) : $self->{XCC_undecl};
90             }
91              
92              
93             sub anyElement($)
94 2     2 1 8 { my ($self, $anyelem) = @_;
95              
96             # the "$self" in XCC_ropts would create a ref-cycle, causing a
97             # memory leak.
98 2         6 my $s = $self; weaken $s;
  2         9  
99              
100             my $code
101 0     0   0 = $anyelem eq 'ATTEMPT' ? sub {$s->_convertAnyTyped(@_)}
102 0     0   0 : $anyelem eq 'SLOPPY' ? sub {$s->_convertAnySloppy(@_)}
103 2 0       16 : $anyelem;
    50          
104            
105 2         10 $self->addCompileOptions(READERS => any_element => $code);
106 2         3 $code;
107             }
108              
109             #----------------------
110              
111              
112             sub addPrefixes(@)
113 4     4 1 7 { my $self = shift;
114 4   100     26 my $p = $self->{XCC_namespaces} ||= {};
115 4         25 my $first = shift;
116 4 100 100     21 @_ or defined $first
117             or return $p;
118              
119             my @pairs
120 3 0       17 = @_ ? ($first, @_)
    50          
    100          
121             : ref $first eq 'ARRAY' ? @$first
122             : ref $first eq 'HASH' ? %$first
123             : error __x"prefixes() expects list of PAIRS, an ARRAY or a HASH";
124              
125 3   100     11 my $a = $self->{XCC_prefixes} ||= {};
126 3         9 while(@pairs)
127 3         8 { my ($prefix, $ns) = (shift @pairs, shift @pairs);
128 3   100     23 $p->{$ns} ||= { uri => $ns, prefix => $prefix, used => 0 };
129              
130 3 100       9 if(my $def = $a->{$prefix})
131 1 50       6 { if($def->{uri} ne $ns)
132             { error __x"prefix `{prefix}' already refers to {uri}, cannot use it for {ns}"
133 0         0 , prefix => $prefix, uri => $def->{uri}, ns => $ns;
134             }
135             }
136             else
137 2         6 { $a->{$prefix} = $p->{$ns};
138 2         15 trace "register prefix $prefix for '$ns'";
139             }
140             }
141 3         72 $p;
142             }
143              
144              
145              
146             sub prefixes(@)
147 3     3 1 585 { my $self = shift;
148 3 100       13 return $self->addPrefixes(@_) if @_;
149 2 50       12 $self->{XCC_namespaces} || {};
150             }
151              
152              
153 1     1 1 5 sub prefix($) { $_[0]->{XCC_prefixes}{$_[1]} }
154              
155             # [0.995] should this be public?
156 0     0 0 0 sub byPrefixTable() { shift->{XCC_prefixes} }
157              
158              
159             sub prefixFor($)
160 0 0   0 1 0 { my $def = $_[0]->{XCC_namespaces}{$_[1]} or return ();
161 0         0 $def->{used}++;
162 0         0 $def->{prefix};
163             }
164              
165              
166             sub addNicePrefix($$)
167 0     0 1 0 { my ($self, $base, $ns) = @_;
168 0 0       0 if(my $def = $self->prefix($base))
169 0 0       0 { return $base if $def->{uri} eq $ns;
170             }
171             else
172 0         0 { $self->addPrefixes($base => $ns);
173 0         0 return $base;
174             }
175              
176 0 0       0 $base .= '01' if $base !~ m/[0-9]$/;
177 0         0 while(my $def = $self->prefix($base))
178 0 0       0 { return $base if $def->{uri} eq $ns;
179 0         0 $base++;
180             }
181 0         0 $self->addPrefixes($base => $ns);
182 0         0 $base;
183             }
184              
185              
186             sub learnPrefixes($)
187 2     2 1 6 { my ($self, $node) = @_;
188 2         10 my $namespaces = $self->prefixes;
189              
190             PREFIX:
191 2         28 foreach my $ns ($node->getNamespaces) # learn preferred ns
192 4         27 { my ($prefix, $uri) = ($ns->getLocalName, $ns->getData);
193 4 100 100     30 next if !defined $prefix || $namespaces->{$uri};
194              
195 1 50       4 if(my $def = $self->prefix($prefix))
196 0 0       0 { next PREFIX if $def->{uri} eq $uri;
197             }
198             else
199 1         4 { $self->addPrefixes($prefix => $uri);
200 1         4 next PREFIX;
201             }
202              
203 0         0 $prefix =~ s/0?$/0/;
204 0         0 while(my $def = $self->prefix($prefix))
205 0 0       0 { next PREFIX if $def->{uri} eq $uri;
206 0         0 $prefix++;
207             }
208 0         0 $self->addPrefixes($prefix => $uri);
209             }
210             }
211              
212             sub addSchemas($@)
213 2     2 1 2232 { my ($self, $xml) = (shift, shift);
214 2         10 $self->learnPrefixes($xml);
215 2         40 $self->SUPER::addSchemas($xml, @_);
216             }
217              
218              
219             sub prefixed($;$)
220 0     0 1 0 { my $self = shift;
221 0 0       0 my ($ns, $local) = @_==2 ? @_ : unpack_type(shift);
222 0 0       0 $ns or return $local;
223 0         0 my $prefix = $self->prefixFor($ns);
224 0 0       0 defined $prefix
225             or error __x"no prefix known for namespace `{ns}', use addPrefixes()"
226             , ns => $ns;
227              
228 0 0       0 length $prefix ? "$prefix:$local" : $local;
229             }
230              
231             #----------------------
232              
233              
234             sub compileAll(;$$)
235 0     0 1 0 { my ($self, $need, $usens) = @_;
236 0   0     0 my ($need_r, $need_w) = $self->_need($need || 'RW');
237              
238 0 0       0 if($need_r)
239 0         0 { foreach my $type (keys %{$self->{XCC_dropts}})
  0         0  
240 0 0       0 { if(defined $usens)
241 0         0 { my ($myns, $local) = unpack_type $type;
242 0 0       0 next if $usens eq $myns;
243             }
244 0         0 $self->reader($type);
245             }
246             }
247              
248 0 0       0 if($need_w)
249 0         0 { foreach my $type (keys %{$self->{XCC_dwopts}})
  0         0  
250 0 0       0 { if(defined $usens)
251 0         0 { my ($myns, $local) = unpack_type $type;
252 0 0       0 next if $usens eq $myns;
253             }
254 0         0 $self->writer($type);
255             }
256             }
257             }
258              
259              
260             sub _same_params($$)
261 2     2   6 { my ($f, $s) = @_;
262 2 50       8 @$f==@$s or return 0;
263 2         8 for(my $i=0; $i<@$f; $i++)
264 0 0       0 { return 0 if !defined $f->[$i] ? defined $s->[$i]
    0          
    0          
265             : !defined $s->[$i] ? 1 : $f->[$i] ne $s->[$i];
266             }
267 2         8 1;
268             }
269              
270             sub reader($@)
271 8     8 1 25228 { my ($self, $name) = (shift, shift);
272 8         15 my %args = @_;
273 8         19 my $type = $self->findName($name);
274 8         56 my $readers = $self->{XCC_readers};
275              
276 8 100       23 if(exists $self->{XCC_dropts}{$type})
    100          
    100          
277 4 50       10 { trace __x"ignoring options to pre-declared reader {name}"
278             , name => $name if @_;
279              
280             return $readers->{$type}
281 4 100       13 if $readers->{$type};
282             }
283             elsif($self->allowUndeclared)
284 2 100       6 { if(my $ur = $self->{XCC_uropts}{$type})
285             { # do not use cached version when options differ
286             _same_params $ur, \@_
287             or return $args{is_type}
288 1 0       6 ? $self->compileType(READER => $type, @_)
    50          
289             : $self->compile(READER => $type, @_);
290             }
291             else
292 1         4 { $self->{XCC_uropts}{$type} = \@_;
293             }
294             }
295             elsif(exists $self->{XCC_dwopts}{$type})
296 1         11 { error __x"type {name} is only declared as writer", name => $name }
297 1         11 else { error __x"type {name} is not declared", name => $name }
298              
299             $readers->{$type} ||= $args{is_type}
300 4 50 66     25 ? $self->compileType(READER => $type, @_)
301             : $self->compile(READER => $type, @_);
302             }
303              
304              
305             sub writer($%)
306 8     8 1 24264 { my ($self, $name) = (shift, shift);
307 8         12 my %args = @_;
308 8         18 my $type = $self->findName($name);
309 8         57 my $writers = $self->{XCC_writers};
310              
311 8 100       26 if(exists $self->{XCC_dwopts}{$type})
    100          
    100          
312 4 50       15 { trace __x"ignoring options to pre-declared writer {name}"
313             , name => $name if @_;
314              
315             return $writers->{$type}
316 4 100       15 if $writers->{$type};
317             }
318             elsif($self->{XCC_undecl})
319 2 100       8 { if(my $ur = $self->{XCC_uwopts}{$type})
320             { # do not use cached version when options differ
321             _same_params $ur, \@_
322             or return $args{is_type}
323 1 0       6 ? $self->compileType(WRITER => $type, @_)
    50          
324             : $self->compile(WRITER => $type, @_);
325             }
326             else
327 1         5 { $self->{XCC_uwopts}{$type} = \@_;
328             }
329             }
330             elsif(exists $self->{XCC_dropts}{$type})
331 1         6 { error __x"type {name} is only declared as reader", name => $name;
332             }
333             else
334 1         4 { error __x"type {name} is not declared", name => $name;
335             }
336              
337             $writers->{$type} ||= $args{is_type}
338 4 50 66     28 ? $self->compileType(WRITER => $type, @_)
339             : $self->compile(WRITER => $type, @_);
340              
341             }
342              
343             sub template($$@)
344 0     0 1 0 { my ($self, $action, $name) = (shift, shift, shift);
345 0 0       0 $action =~ m/^[A-Z]*$/
346             or error __x"missing or illegal action parameter to template()";
347              
348 0         0 my $type = $self->findName($name);
349 0         0 my @opts = $self->mergeCompileOptions($action, $type, \@_);
350 0         0 $self->SUPER::template($action, $type, @opts);
351             }
352              
353              
354             sub addCompileOptions(@)
355 2     2 1 3 { my $self = shift;
356 2 50       9 my $need = @_%2 ? shift : 'RW';
357              
358             my $set
359             = $need eq 'RW' ? $self->{XCC_opts}
360             : $need eq 'READERS' ? $self->{XCC_ropts}
361             : $need eq 'WRITERS' ? $self->{XCC_wopts}
362 2 0       11 : error __x"addCompileOptions() requires option set name, not {got}"
    50          
    50          
363             , got => $need;
364              
365 2 50       9 if(ref $set eq 'HASH')
366 0         0 { while(@_) { my $k = shift; $set->{$k} = shift } }
  0         0  
  0         0  
367 2         13 else { push @$set, @_ }
368 2         3 $set;
369             }
370              
371             # Create a list with options for X::C::Schema::compile(), from a list of ARRAYs
372             # and HASHES with options. The later options overrule the older, but in some
373             # cases, the new values are added. This method knows how some of the options
374             # of ::compile() behave. [last update X::C v0.98]
375              
376             sub mergeCompileOptions($$$)
377 6     6 0 13 { my ($self, $action, $type, $opts) = @_;
378              
379             my @action_opts
380             = ($action eq 'READER' || $action eq 'PERL')
381             ? ($self->{XCC_ropts}, $self->{XCC_dropts}{$type})
382 6 100 66     34 : ($self->{XCC_wopts}, $self->{XCC_dwopts}{$type});
383              
384 6         10 my %p = %{$self->{XCC_namespaces}};
  6         22  
385 6         10 my %t = %{$self->{XCC_typemap}};
  6         11  
386 6         8 my %x = %{$self->{XCC_xsi_type}};
  6         9  
387 6         21 my %opts = (prefixes => \%p, hooks => [], typemap => \%t, xsi_type => \%x);
388              
389             # flatten list of parameters
390 24 50       83 my @take = map {!defined $_ ? () : ref $_ eq 'ARRAY' ? @$_ : %$_ }
    100          
391 6         15 $self->{XCC_opts}, @action_opts, $opts;
392              
393 6         13 while(@take)
394 3         7 { my ($opt, $val) = (shift @take, shift @take);
395 3 50       8 defined $val or next;
396              
397 3 50 33     35 if($opt eq 'prefixes')
    50          
    50          
    50          
    50          
    50          
398 0         0 { my $t = $self->_namespaceTable($val, 1, 0); # expand
399 0         0 @p{keys %$t} = values %$t; # overwrite old def if exists
400             }
401             elsif($opt eq 'hooks' || $opt eq 'hook')
402 0         0 { my $hooks = $self->_cleanup_hooks($val);
403 0 0       0 unshift @{$opts{hooks}}, ref $hooks eq 'ARRAY' ? @$hooks : $hooks
  0 0       0  
404             if $hooks;
405             }
406             elsif($opt eq 'typemap')
407 0   0     0 { $val ||= {};
408 0 0       0 if(ref $val eq 'ARRAY')
409 0         0 { while(@$val)
410 0         0 { my $k = $self->findName(shift @$val);
411 0         0 $t{$k} = shift @$val;
412             }
413             }
414             else
415 0         0 { while(my($k, $v) = each %$val)
416 0         0 { $t{$self->findName($k)} = $v;
417             }
418             }
419             }
420             elsif($opt eq 'key_rewrite')
421 0 0       0 { unshift @{$opts{key_rewrite}}, ref $val eq 'ARRAY' ? @$val : $val;
  0         0  
422             }
423             elsif($opt eq 'xsi_type')
424 0         0 { while(my ($t, $a) = each %$val)
425 0 0       0 { my @a = ref $a eq 'ARRAY' ? map($self->findName($_), @$a)
426             : $self->findName($a);
427 0         0 push @{$x{$self->findName($t)}}, @a;
  0         0  
428             }
429             }
430             elsif($opt eq 'ignore_unused_tags')
431 0 0       0 { $opts{$opt} = defined $opts{$opt} ? qr/$opts{$opt}|$val/ : $val;
432             }
433             else
434 3         12 { $opts{$opt} = $val;
435             }
436             }
437              
438 6         46 %opts;
439             }
440              
441             # rewrite hooks
442             sub _cleanup_hooks($)
443 0     0   0 { my ($self, $hooks) = @_;
444 0 0       0 $hooks or return;
445              
446             # translate prefixed type names into full names
447 0 0       0 foreach my $hook (ref $hooks eq 'ARRAY' ? @$hooks : $hooks)
448 0 0       0 { if(my $types = $hook->{type})
    0          
449             { $hook->{type} =
450 0 0       0 [ map {ref $_ eq 'Regexp' ? $_ : $self->findName($_)}
  0 0       0  
451             ref $types eq 'ARRAY' ? @$types : $types ];
452             }
453             elsif(my $ext = $hook->{extends})
454 0         0 { $hook->{extends} = $self->findName($ext);
455             }
456             }
457 0         0 $hooks;
458             }
459              
460             my %need = (READER => [1,0], WRITER => [0,1], RW => [1,1]);
461             $need{READERS} = $need{READER};
462             $need{WRITERS} = $need{WRITER};
463              
464             sub _need($)
465 3 50   3   10 { my $need = $need{$_[1]}
466             or error __x"use READER, WRITER or RW, not {dir}", dir => $_[1];
467 3         10 @$need;
468             }
469              
470             # support prefixes on types
471             sub addHook(@)
472 0     0 1 0 { my $self = shift;
473 0 0       0 my $hook = @_ > 1 ? {@_} : shift;
474 0         0 $self->_cleanup_hooks($hook);
475 0         0 $self->SUPER::addHook($hook);
476             }
477              
478             sub compile($$@)
479 6     6 1 16 { my ($self, $action, $elem) = splice @_, 0, 3;
480 6 50       12 defined $elem
481             or error __x"compile() requires action and type parameters";
482              
483 6         12 $self->SUPER::compile
484             ( $action => $self->findName($elem)
485             , $self->mergeCompileOptions($action, $elem, \@_)
486             );
487             }
488              
489             sub compileType($$@)
490 0     0 1 0 { my ($self, $action, $type) = splice @_, 0, 3;
491 0 0       0 defined $type
492             or error __x"compileType() requires action and type parameters";
493              
494 0         0 $self->SUPER::compileType
495             ( $action => $self->findName($type)
496             , $self->mergeCompileOptions($action, $type, \@_)
497             );
498             }
499              
500             #----------------------
501              
502              
503             sub declare($$@)
504 3     3 1 697 { my ($self, $need, $names, @opts) = @_;
505 3 50       25 my $opts = @opts==1 ? shift @opts : \@opts;
506 3 50       10 $opts = [ %$opts ] if ref $opts eq 'HASH';
507              
508 3         9 my ($need_r, $need_w) = $self->_need($need);
509              
510 3 50       9 foreach my $name (ref $names eq 'ARRAY' ? @$names : $names)
511 3         7 { my $type = $self->findName($name);
512 3         14 trace "declare $type $need";
513              
514 3 100       69 if($need_r)
515 2 50       5 { defined $self->{XCC_dropts}{$type}
516             and warning __x"reader {name} declared again", name => $name;
517 2         4 $self->{XCC_dropts}{$type} = $opts;
518             }
519              
520 3 100       10 if($need_w)
521 2 50       5 { defined $self->{XCC_dwopts}{$type}
522             and warning __x"writer {name} declared again", name => $name;
523 2         5 $self->{XCC_dwopts}{$type} = $opts;
524             }
525             }
526              
527 3         6 $self;
528             }
529              
530              
531             sub findName($)
532 28     28 1 48 { my ($self, $name) = @_;
533 28 50       61 defined $name
534             or panic "findName called without name";
535              
536 28 100       92 return $name
537             if substr($name, 0, 1) eq '{';
538              
539 18 50       144 my ($prefix,$local) = $name =~ m/^([\w-]*)\:(\S*)$/ ? ($1,$2) : ('',$name);
540 18         44 my $def = $self->{XCC_prefixes}{$prefix};
541 18 50       34 unless($def)
542 0 0       0 { return $name if $prefix eq ''; # namespace-less
543             trace __x"known prefixes: {prefixes}"
544 0         0 , prefixes => [ sort keys %{$self->{XCC_prefixes}} ];
  0         0  
545 0         0 error __x"unknown name prefix `{prefix}' for `{name}'"
546             , prefix => $prefix, name => $name;
547             }
548              
549 18 50       71 length $local ? pack_type($def->{uri}, $local) : $def->{uri};
550             }
551              
552              
553             sub printIndex(@)
554 3     3 1 1944 { my $self = shift;
555 3 50       12 my $fh = @_ % 2 ? shift : select;
556 3         11 my %args = @_;
557 3 50       9 my $decl = exists $args{show_declared} ? delete $args{show_declared} : 1;
558              
559 3 50       8 return $self->SUPER::printIndex($fh, %args)
560             unless $decl;
561              
562 3         6 my $output = '';
563 3         21 open my($out), '>', \$output;
564              
565 3         22 $self->SUPER::printIndex($out, %args);
566              
567 3         932 close $out;
568 3         44 my @output = split /(?<=\n)/, $output;
569 3         7 my $ns = '';
570 3         8 foreach (@output)
571 18 100       41 { $ns = $1 if m/^namespace\:\s+(\S+)/;
572 18 100       62 my $local = m/^\s+(\S+)\s*$/ ? $1 : next;
573 12         24 my $type = pack_type $ns, $local;
574              
575             substr($_, 1, 1)
576             = $self->{XCC_readers}{$type} ? 'R'
577 12 100       77 : $self->{XCC_dropts}{$type} ? 'r' : ' ';
    100          
578              
579             substr($_, 2, 1)
580             = $self->{XCC_writers}{$type} ? 'W'
581 12 100       38 : $self->{XCC_dwopts}{$type} ? 'w' : ' ';
    100          
582             }
583 3         11 $fh->print(@output);
584             }
585              
586             #---------------
587             # Convert ANY elements and attributes
588              
589             sub _convertAnyTyped(@)
590 0     0     { my ($self, $type, $nodes, $path, $read) = @_;
591              
592 0           my $key = $read->keyRewrite($type);
593 0 0         if(defined(my $blocked = $read->blocked($path, complexType => $type)))
594 0           { trace "skipping blocked $type";
595 0           return ();
596             }
597              
598 0     0     my $reader = try { $self->reader($type) };
  0            
599 0 0         if($@)
600 0           { trace "cannot auto-convert 'any': ".$@->wasFatal->message;
601 0           return ($key => $nodes);
602             }
603 0           trace "auto-convert known type for 'any': $type";
604              
605 0 0         my @nodes = ref $nodes eq 'ARRAY' ? @$nodes : $nodes;
606 0           my @convert = map $reader->($_), @nodes;
607 0 0         ($key => (@convert==1 ? $convert[0] : \@convert) );
608             }
609              
610             sub _convertAnySloppy(@)
611 0     0     { my ($self, $type, $nodes, $path, $read) = @_;
612              
613 0           my $key = $read->keyRewrite($type);
614 0     0     my $reader = try { $self->reader($type) };
  0            
615 0 0         if($@)
616             { # unknown type or untyped...
617 0           my @convert = map XMLin($_), @$nodes;
618 0 0         return ($key => @convert==1 ? $convert[0] : \@convert);
619             }
620             else
621 0           { trace "auto-convert known 'any' $type";
622 0 0         my @nodes = ref $nodes eq 'ARRAY' ? @$nodes : $nodes;
623 0           my @convert = map $reader->($_), @nodes;
624              
625 0 0         ($key => @convert==1 ? $convert[0] : \@convert);
626             }
627             }
628              
629             1;