File Coverage

lib/XML/Compile/Translate.pm
Criterion Covered Total %
statement 668 717 93.1
branch 378 532 71.0
condition 132 190 69.4
subroutine 60 65 92.3
pod 3 46 6.5
total 1241 1550 80.0


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;{
10             our $VERSION = '1.64';
11             }
12              
13              
14 50     50   345 use warnings;
  50         101  
  50         3991  
15 50     50   281 use strict;
  50         104  
  50         1433  
16 50     50   215 no warnings 'recursion'; # trees can be quite deep
  50         94  
  50         2917  
17              
18             # Errors are either in _class 'usage': called with request
19             # or 'schema': syntax error in schema
20              
21 50     50   323 use Log::Report 'xml-compile', syntax => 'SHORT';
  50         122  
  50         491  
22 50     50   16058 use List::Util qw/first max/;
  50         99  
  50         4274  
23              
24 50     50   371 use XML::Compile::Schema::Specs;
  50         129  
  50         1548  
25 50     50   28149 use XML::Compile::Schema::BuiltInFacets;
  50         166  
  50         4437  
26 50     50   392 use XML::Compile::Schema::BuiltInTypes qw/%builtin_types/;
  50         102  
  50         6117  
27 50         3185 use XML::Compile::Util qw/pack_type unpack_type type_of_node SCHEMA2001
28 50     50   402 unpack_id/;
  50         90  
29 50     50   28535 use XML::Compile::Iterator ();
  50         138  
  50         701229  
30              
31             my %translators =
32             ( READER => 'XML::Compile::Translate::Reader'
33             , WRITER => 'XML::Compile::Translate::Writer'
34             , TEMPLATE => 'XML::Compile::Translate::Template'
35             );
36              
37             # Elements from the schema to ignore: remember, we are collecting data
38             # from the schema, but only use selective items to produce processors.
39             # All the sub-elements of these will be ignored automatically
40             # Don't known whether we ever need the notation... maybe
41             my $assertions = qr/assert|report/;
42             my $id_constraints = qr/unique|key|keyref/;
43             my $ignore_elements = qr/^(?:notation|annotation|$id_constraints|$assertions)$/;
44              
45             my $particle_blocks = qr/^(?:sequence|choice|all|group)$/;
46             my $attribute_defs = qr/^(?:attribute|attributeGroup|anyAttribute)$/;
47              
48              
49             sub new($@)
50 779     779 1 2239 { my ($baseclass, $trans) = (shift, shift);
51 779 50       3325 my $class = $translators{$trans}
52             or error __x"translator back-end {name} not defined", name => $trans;
53              
54 779         67437 eval "require $class";
55 779 50       14423 fault $@ if $@;
56              
57 779         6328 (bless {}, $class)->init( {@_} );
58             }
59              
60             sub init($)
61 779     779 0 2037 { my ($self, $args) = @_;
62 779 50       6855 $self->{nss} = $args->{nss} or panic "no namespace tables";
63 779   50     4290 $self->{prefixes} = $args->{prefixes} || {};
64 779         3450 $self;
65             }
66              
67              
68             sub register($)
69 0     0 1 0 { my ($class, $name) = @_;
70 0 0       0 UNIVERSAL::isa($class, __PACKAGE__)
71             or error __x"back-end {class} does not extend {base}"
72             , class => $class, base => __PACKAGE__;
73 0         0 $translators{$name} = $class;
74             }
75              
76              
77             # may disappear, so not documented publicly (yet)
78 0     0 0 0 sub actsAs($) { panic "not implemented" }
79              
80             #--------
81              
82             sub compile($@)
83 779     779 1 8233 { my ($self, $item, %args) = @_;
84 779         9178 @$self{keys %args} = values %args; # dirty. Always all the same fields
85              
86 779   66     5171 my $path = $self->prefixed($item, 1) || $item;
87 779 50       2538 ref $item
88             and panic "expecting an item as point to start at $path";
89              
90 779   100     2821 my $hooks = $self->{hooks} ||= [];
91 779   100     2562 my $typemap = $self->{typemap} ||= {};
92 779         4195 $self->typemapToHooks($hooks, $typemap);
93              
94             $self->{blocked_nss}
95 779         3825 = $self->decodeBlocked(delete $self->{block_namespace});
96              
97 779         6940 my $nsp = $self->namespaces;
98 779         1926 foreach my $t (keys %$typemap)
99 9 50 33     34 { $nsp->find(complexType => $t) || $nsp->find(simpleType => $t)
100             or error __x"complex or simpleType {type} for typemap unknown"
101             , type => $t;
102             }
103              
104 779 50       1820 if(my $def = $self->namespaces->findID($item))
105 0         0 { my $node = $def->{node};
106 0         0 my $name = $node->localName;
107 0         0 $item = $def->{full};
108             }
109              
110 779         1679 delete $self->{_created};
111 779         2884 my $produce = $self->topLevel($path, $item, 1);
112 777         8736 delete $self->{_created};
113              
114             my $in = $self->{include_namespaces}
115 777 100       13884 or return $produce;
116              
117 121         500 $self->makeWrapperNs($path, $produce, $self->{prefixes}, $in);
118             }
119              
120             sub assertType($$$$)
121 2170     2170 0 5444 { my ($self, $where, $field, $type, $value) = @_;
122 2170         6488 my $checker = $builtin_types{$type}{check};
123 2170 50       5095 unless(defined $checker)
124 0         0 { mistake "useless assert for type $type";
125 0         0 return;
126             }
127              
128 2170 50       6832 return if $checker->($value);
129              
130 0         0 error __x"field {field} contains '{value}' which is not a valid {type} at {where}"
131             , field => $field, value => $value, type => $type, where => $where
132             , _class => 'usage';
133              
134             }
135              
136             sub extendAttrs($@)
137 54     54 0 165 { my ($self, $in, $add) = @_;
138              
139 54 50       202 if(my $a = $add->{attrs})
140             { # new attrs overrule old definitions (restrictions)
141 54         113 my (@attrs, %code);
142 54 100       84 my @all = (@{$in->{attrs} || []}, @{$add->{attrs} || []});
  54 50       275  
  54         264  
143 54         171 while(@all)
144 80         182 { my ($type, $code) = (shift @all, shift @all);
145 80 50       189 if($code{$type})
146 0         0 { $attrs[$code{$type}] = $code;
147             }
148             else
149 80         174 { push @attrs, $type => $code;
150 80         270 $code{$type} = $#attrs;
151             }
152             }
153 54         208 $in->{attrs} = \@attrs;
154             }
155              
156             # doing this correctly is too complex for now
157 54 50       175 unshift @{$in->{attrs_any}}, @{$add->{attrs_any}} if $add->{attrs_any};
  54         267  
  54         119  
158 54         114 $in;
159             }
160              
161 2500 50   2500 0 44000 sub isTrue($) { $_[1] eq '1' || $_[1] eq 'true' }
162              
163             # Find the namespace use details of a certain top-level element or
164             # attribute.
165             sub nsContext($)
166 2081     2081 0 3851 { my ($self, $def) = @_;
167 2081 50       4080 $def or return {};
168              
169 2081         4365 my $tns = $def->{ns};
170              
171             # top elements are to be qualified unless there is no targetNamespace
172 2081 100       9439 my %context = (tns => $tns, qual_top => ($tns ? 1 : 0));
173              
174 2081         4517 my $el_qual = $def->{efd} eq 'qualified';
175 2081 100       4711 if(exists $self->{elements_qualified})
176 1843   50     4143 { my $qual = $self->{elements_qualified} || 0;
177 1843 50       4643 if($qual eq 'TOP')
178             { $tns or error __x"application requires that element `{name}' has a targetNamespace"
179 0 0       0 , name => $def->{full};
180             }
181             else
182 1843 100       4716 { $el_qual = $qual eq 'ALL' ? 1 : $qual eq 'NONE' ? 0 : $qual;
    100          
183             }
184 1843 100       4594 $context{qual_top} = 0 if $qual eq 'NONE';
185             }
186 2081         3968 $context{qual_elem} = $el_qual;
187              
188 2081         4300 my $at_qual = $def->{afd} eq 'qualified';
189 2081 100       4471 if(exists $self->{attributes_qualified})
190 22   50     79 { my $qual = $self->{attributes_qualified} || 0;
191 22 50       58 if($qual eq 'TOP')
192 0 0       0 { $tns or error __x"application requires that attibute `{name}' has a targetNamespace", name => $def->{full};
193             }
194             else
195 22 50       97 { $at_qual = $qual eq 'ALL' ? 1 : $qual eq 'NONE' ? 0 : $qual;
    50          
196             }
197             }
198 2081         3667 $context{qual_attr} = $at_qual;
199              
200 2081         6206 \%context;
201             }
202              
203 5031     5031 0 19919 sub namespaces() { $_[0]->{nss} }
204              
205             sub topLevel($$;$)
206 779     779 0 2122 { my ($self, $path, $fullname, $is_root) = @_;
207              
208             # built-in types have to be handled differently.
209             my $internal = XML::Compile::Schema::Specs->builtInType(undef, $fullname
210             , sloppy_integers => $self->{sloppy_integers}
211             , sloppy_floats => $self->{sloppy_floats}
212             , json_friendly => $self->{json_friendly}
213 779         5974 );
214              
215 779 100       5828 if($internal)
216             { my $builtin = $self->makeBuiltin($fullname, undef
217 2         10 , $fullname, $internal, $self->{check_values});
218             my $builder = $self->actsAs('WRITER')
219 1     1   4 ? sub { $_[0]->createTextNode($builtin->(@_)) }
220 2 100       9 : $builtin;
221 2         7 return $self->makeElementWrapper($path, $builder);
222             }
223              
224 777         2055 my $nss = $self->namespaces;
225 777 0 66     2862 my $top = $nss->find(element => $fullname)
    50          
226             || $nss->find(attribute => $fullname)
227             or error __x(( $fullname eq $path
228             ? N__"cannot find element or attribute `{name}'"
229             : N__"cannot find element or attribute `{name}' at {where}"
230             ), name => $fullname, where => $path, _class => 'usage');
231              
232             # filter the nodes in the schema which are to be processed
233 777         1856 my $node = $top->{node};
234 777         4987 my $schemans = $node->namespaceURI;
235             my $tree = XML::Compile::Iterator->new($node, $path, sub
236 9135     9135   14481 { my $n = shift;
237 9135 100 66     90899 $n->isa('XML::LibXML::Element')
238             && $n->namespaceURI eq $schemans
239             && $n->localName !~ $ignore_elements
240 777         8266 });
241              
242 777         2256 delete $self->{_nest}; # reset recursion administration
243              
244 777         3777 local $self->{_context} = $self->nsContext($top);
245 777         3810 my $name = $node->localName;
246 777         1440 my $data;
247 777 100       2078 if($name eq 'element')
    50          
248 769         3177 { my ($label, $make) = $self->element($tree, $is_root);
249 767 50       15479 $data = $self->makeElementWrapper($path, $make) if $make;
250             }
251             elsif($name eq 'attribute')
252 8         30 { my $make = $self->attribute($tree);
253 8 50       159 $data = $self->makeAttributeWrapper($path, $make) if $make;
254             }
255             else
256 0         0 { error __x"top-level `{full}' is not an element or attribute but {name} at {where}"
257             , full => $fullname, name => $name, where => $tree->path
258             , _class => 'usage';
259             }
260              
261 775         8611 $data;
262             }
263              
264             sub typeByName($$$)
265 1993     1993 0 4006 { my ($self, $where, $tree, $typename) = @_;
266              
267 1993         4766 my $node = $tree->node;
268              
269             #
270             # Try to detect a built-in type
271             #
272              
273             my $def = XML::Compile::Schema::Specs->builtInType($node, $typename
274             , sloppy_integers => $self->{sloppy_integers}
275             , sloppy_floats => $self->{sloppy_floats}
276             , json_friendly => $self->{json_friendly}
277 1993         10830 );
278              
279 1993 100       4466 if($def)
280             { # Is built-in
281 1611         7318 my $st = $self->makeBuiltin($where, $node, $typename, $def, $self->{check_values});
282              
283 1611         11877 return +{ st => $st, is_list => $def->{is_list} };
284             }
285              
286             #
287             # not a schema standard type
288             #
289 382 50 66     1512 my $top = $self->namespaces->find(complexType => $typename)
290             || $self->namespaces->find(simpleType => $typename)
291             or error __x"cannot find type {type} at {where}"
292             , type => $typename, where => $where, _class => 'usage';
293              
294 382         1108 local $self->{_context} = $self->nsContext($top);
295 382         1563 my $typeimpl = $tree->descend($top->{node});
296              
297 382         962 my $typedef = $top->{type};
298 382 50       2065 $typedef eq 'simpleType' ? $self->simpleType($typeimpl)
    100          
299             : $typedef eq 'complexType' ? $self->complexType($typeimpl)
300             : error __x"expecting simple- or complexType, not '{type}' at {where}"
301             , type => $typedef, where => $tree->path, _class => 'schema';
302             }
303              
304             sub simpleType($;$)
305 372     372 0 866 { my ($self, $tree, $in_list) = @_;
306              
307 372 50       1072 $tree->nrChildren==1
308             or error __x"simpleType must have exactly one child at {where}"
309             , where => $tree->path, _class => 'schema';
310              
311 372         980 my $child = $tree->firstChild;
312 372         1558 my $name = $child->localName;
313 372         1034 my $nest = $tree->descend($child);
314              
315             # Full content:
316             # annotation?
317             # , (restriction | list | union)
318              
319 372 50       2167 my $type
    100          
    100          
320             = $name eq 'restriction' ? $self->simpleRestriction($nest, $in_list)
321             : $name eq 'list' ? $self->simpleList($nest)
322             : $name eq 'union' ? $self->simpleUnion($nest)
323             : error __x"simpleType contains '{local}', must be restriction, list, or union at {where}"
324             , local => $name, where => $tree->path, _class => 'schema';
325              
326 372         967 delete @$type{'attrs','attrs_any'}; # spec says ignore attrs
327 372         2180 $type;
328             }
329              
330             sub simpleList($)
331 56     56 0 94 { my ($self, $tree) = @_;
332              
333             # attributes: id, itemType = QName
334             # content: annotation?, simpleType?
335              
336 56         64 my $per_item;
337 56         98 my $node = $tree->node;
338 56         117 my $where = $tree->path . '#list';
339              
340 56 100       127 if(my $type = $node->getAttribute('itemType'))
341 40 50       428 { $tree->nrChildren==0
342             or error __x"list with both itemType and content at {where}"
343             , where => $where, _class => 'schema';
344              
345 40         111 my $typename = $self->rel2abs($where, $node, $type);
346 40   33     107 $per_item = $self->blocked($where, simpleType => $typename)
347             || $self->typeByName($where, $tree, $typename);
348             }
349             else
350 16 50       308 { $tree->nrChildren==1
351             or error __x"list expects one simpleType child at {where}"
352             , where => $where, _class => 'schema';
353              
354 16 50       34 $tree->currentLocal eq 'simpleType'
355             or error __x"list can only have a simpleType child at {where}"
356             , where => $where, _class => 'schema';
357              
358 16         38 $per_item = $self->simpleType($tree->descend, 1);
359             }
360              
361             my $st = $per_item->{st}
362 56 50       372 or panic "list did not produce a simple type at $where";
363              
364 56         348 $per_item->{st} = $self->makeList($where, $st);
365 56         98 $per_item->{is_list} = 1;
366 56         95 $per_item;
367             }
368              
369             sub simpleUnion($)
370 37     37 0 71 { my ($self, $tree) = @_;
371              
372             # attributes: id, memberTypes = List of QName
373             # content: annotation?, simpleType*
374              
375 37         81 my $node = $tree->node;
376 37         104 my $where = $tree->path . '#union';
377              
378             # Normal error handling switched off, and check_values must be on
379             # When check_values is off, we may decide later to treat that as
380             # string, which is faster but not 100% safe, where int 2 may be
381             # formatted as float 1.999
382              
383 37         82 local $self->{check_values} = 1;
384              
385 37         50 my @types;
386 37 100       99 if(my $members = $node->getAttribute('memberTypes'))
387 27         403 { foreach my $union (split " ", $members)
388 43         113 { my $typename = $self->rel2abs($where, $node, $union);
389 43   33     104 my $type = $self->blocked($where, simpleType => $typename)
390             || $self->typeByName($where, $tree, $typename);
391             my $st = $type->{st}
392 43 50       387 or error __x"union only of simpleTypes, but {type} is complex at {where}"
393             , type => $typename, where => $where, _class => 'schema';
394              
395 43         141 push @types, $st;
396             }
397             }
398              
399 37         236 foreach my $child ($tree->childs)
400 39         299 { my $name = $child->localName;
401 39 50       114 $name eq 'simpleType'
402             or error __x"only simpleType's within union, found {local} at {where}"
403             , local => $name, where => $where, _class => 'schema';
404              
405 39         129 my $ctype = $self->simpleType($tree->descend($child), 0);
406 39         604 push @types, $ctype->{st};
407             }
408              
409 37         415 my $do = $self->makeUnion($where, @types);
410 37         160 { st => $do, is_union => 1 };
411             }
412              
413             sub simpleRestriction($$)
414 279     279 0 760 { my ($self, $tree, $in_list) = @_;
415              
416             # attributes: id, base = QName
417             # content: annotation?, simpleType?, facet*
418              
419 279         748 my $node = $tree->node;
420 279         857 my $where = $tree->path . '#sres';
421              
422 279         528 my ($base, $typename);
423 279 50       828 if(my $basename = $node->getAttribute('base'))
424 279         4278 { $typename = $self->rel2abs($where, $node, $basename);
425 279   66     1031 $base = $self->blocked($where, simpleType => $typename)
426             || $self->typeByName($where, $tree, $typename);
427             }
428             else
429 0 0       0 { my $simple = $tree->firstChild
430             or error __x"no base in simple-restriction, so simpleType required at {where}"
431             , where => $where, _class => 'schema';
432              
433 0 0       0 $simple->localName eq 'simpleType'
434             or error __x"simpleType expected, because there is no base attribute at {where}"
435             , where => $where, _class => 'schema';
436              
437 0         0 $base = $self->simpleType($tree->descend($simple, 'st'));
438              
439 0 0       0 if((my $r) = $simple->getChildrenByLocalName('restriction')) {
440             # @facets
441 0         0 my $basename = $r->getAttribute('base');
442 0 0       0 $typename = $self->rel2abs($where, $r, $basename) if $r;
443             }
444              
445 0         0 $tree->nextChild;
446             }
447              
448             my $st = $base->{st}
449 279 50       1816 or error __x"simple-restriction is not a simpleType at {where}"
450             , where => $where, _class => 'schema';
451              
452             my $do = $self->applySimpleFacets($tree, $st
453 279   100     1721 , $in_list || $base->{is_list}, $typename);
454              
455 279 50       1386 $tree->currentChild
456             and error __x"elements left at tail at {where}"
457             , where => $tree->path, _class => 'schema';
458              
459 279         1507 +{ st => $do };
460             }
461              
462             # Early=lexical space, Late=value space
463             my %facets_early = map +($_ => 1), qw/whiteSpace pattern/;
464             #my %facets_late = map +($_ => 1), qw/totalDigits maxScale minScale enumeration
465             # maxInclusive maxExclusive minInclusive minExclusive fractionDigits
466             # length minLength maxLength/;
467              
468             my $qname_type = pack_type SCHEMA2001, 'QName';
469              
470             sub applySimpleFacets($$$$)
471 287     287 0 737 { my ($self, $tree, $st, $is_list, $type) = @_;
472 287         666 my $nss = $self->{nss};
473              
474             # partial
475             # content: facet*
476             # facet = minExclusive | minInclusive | maxExclusive | maxInclusive
477             # | totalDigits | fractionDigits | maxScale | minScale | length
478             # | minLength | maxLength | enumeration | whiteSpace | pattern
479              
480 287         801 my $where = $tree->path . '#facet';
481 287         531 my (%facets, $is_qname);
482 287         808 for(my $child = $tree->currentChild; $child; $child = $tree->nextChild)
483 280         2270 { my $facet = $child->localName;
484 280 100       2319 last if $facet =~ $attribute_defs;
485              
486 272         885 my $value = $child->getAttribute('value');
487 272 50       3507 defined $value
488             or error __x"no value for facet `{facet}' at {where}"
489             , facet => $facet, where => $where, _class => 'schema';
490              
491 272 100       1260 if($facet eq 'enumeration')
    100          
    50          
492 88 100       415 { $is_qname = $nss->doesExtend($type, $qname_type)
493             unless defined $is_qname;
494              
495 88 100       245 if($is_qname)
496             { # rewrite prefixed values into "{ns}local"
497 10 50       55 my ($prefix, $local)
498             = $value =~ m/\:/ ? split(/\:/, $value, 2) : ('', $value);
499 10         43 my $ns = $child->lookupNamespaceURI($prefix);
500 10         34 $value = pack_type $ns, $local;
501 10         28 $self->_registerNSprefix($prefix, $ns, 1);
502             }
503              
504 88         126 push @{$facets{enumeration}}, $value;
  88         558  
505             }
506 30         61 elsif($facet eq 'pattern') { push @{$facets{pattern}}, $value }
  30         173  
507 154         867 elsif(!exists $facets{$facet}) { $facets{$facet} = $value }
508             else
509 0         0 { error __x"facet `{facet}' defined twice at {where}"
510             , facet => $facet, where => $where, _class => 'schema';
511             }
512             }
513              
514             return $st
515 287 100 66     1654 if $self->{ignore_facets} || !keys %facets;
516              
517 210         999 my %facets_info = %facets;
518              
519             #
520             # new facets overrule all of the base-class
521             #
522              
523 210 100 100     860 if(defined $facets{totalDigits} && defined $facets{fractionDigits})
524 3         8 { my $td = delete $facets{totalDigits};
525 3         8 my $fd = delete $facets{fractionDigits};
526 3         14 $facets{_totalFracDigits} = [$td, $fd];
527             }
528              
529 210         384 my (@early, @late);
530 210 100       926 my $action = $self->actsAs('WRITER') ? 'WRITER' : 'READER';
531 210         819 foreach my $facet (keys %facets)
532             { my $h = builtin_facet($where, $self, $facet
533 243 100       1158 , $facets{$facet}, $is_list, $type, $nss, $action) or next;
534              
535 241 100       768 if($facets_early{$facet})
536 34         115 { push @early, $h }
537 207         657 else { push @late, $h }
538             }
539              
540             $is_list
541 210 100       1394 ? $self->makeFacetsList($where, $st, \%facets_info, \@early, \@late)
542             : $self->makeFacets($where, $st, \%facets_info, \@early, \@late);
543             }
544              
545             sub element($;$)
546 1914     1914 0 4104 { my ($self, $tree, $is_root) = @_;
547              
548             # attributes: abstract, default, fixed, form, id, maxOccurs, minOccurs
549             # , name, nillable, ref, substitutionGroup, targetNamespace, type
550             # ignored: block, final, targetNamespace additional restrictions
551             # content: annotation?
552             # , (simpleType | complexType)?
553             # , (unique | key | keyref)*
554              
555 1914         4984 my $node = $tree->node;
556 1914         11298 my $parent = $node->parentNode;
557 1914   100     4831 my $is_global= $parent
558             && $parent->isa('XML::LibXML::Element')
559             && $parent->localname eq 'schema';
560              
561 1914         24105 my $where = $tree->path;
562              
563 1914 50       4984 my $name = $node->getAttribute('name')
564             or error __x"element has no name nor ref at {where}"
565             , where => $where, _class => 'schema';
566 1914         27287 $self->assertType($where, name => NCName => $name);
567              
568             # Full name based on current context. This might be a global name
569             # or a local name.
570              
571 1914         4464 my $context = $self->{_context};
572              
573             # Determine the context of this element. When it is a global, we need
574             # to set-up a new context until end-of-function.
575              
576 1914         2812 my $abstract = 0;
577 1914         3089 my ($qual, $ns, $fullname);
578              
579 1914 100       3978 if($is_global)
580 876   66     3114 { $ns = $node->getAttribute('targetNamespace')
581             || $parent->getAttribute('targetNamespace');
582 876         21076 $fullname= pack_type $ns, $name;
583 876         2534 my $def = $self->namespaces->find(element => $fullname);
584 876         2611 $context = $self->nsContext($def);
585 876         1807 $qual = $context->{qual_top};
586              
587             # abstract elements are not to be used in messages.
588 876 50       3037 $abstract = $self->{abstract_types} eq 'ACCEPT' ? 0 : $def->{abstract};
589             }
590             else
591 1038         1977 { $qual = $context->{qual_elem};
592 1038   66     2479 $ns = $node->getAttribute('targetNamespace') || $context->{tns};
593 1038         14158 $fullname = pack_type $ns, $name;
594             }
595              
596 1914 100       5162 if(my $form = $node->getAttribute('form'))
597 8 50       99 { $qual
    100          
598             = $form eq 'qualified' ? 1
599             : $form eq 'unqualified' ? 0
600             : error __x"form must be (un)qualified, not `{form}' at {where}"
601             , form => $form, where => $where, _class => 'schema';
602             }
603              
604 1914 100       22463 local $self->{_context} = $context if $is_global;
605 1914 100       4339 my $nodetype = $qual ? $fullname : $name;
606              
607             # SubstitionGroups
608             # We know the type of the message root, so do not need to look for
609             # alternative sgs (and it wouldn't work anyway)
610              
611 1914         2742 my @sgs;
612 1914 100       5540 @sgs = $self->namespaces->findSgMembers($node->localName, $fullname)
613             unless $is_root;
614              
615             # Handle re-usable fragments, fight against combinatorial explosions
616              
617 1914         6088 my $nodeid = $node->unique_key; #$node->nodePath.'#'.$fullname;
618 1914 100       7259 if(my $already = $self->{_created}{$nodeid})
619             { # We cannot cache compile subst-group handlers, because sgs using
620             # elements which were already compiled into sgs does not work.
621 14 50       39 $already = $self->substitutionGroup($tree, $fullname, $nodetype
622             , $already, \@sgs) if @sgs;
623 14         75 return ($nodetype, $already);
624             }
625              
626             # Detect recursion
627             # Very complicated: recursively nested structures. It is less of a
628             # problem when you handle in run-time what you see... but we here
629             # have to be prepared for everything.
630              
631 1900 100       6042 if(exists $self->{_nest}{$nodeid})
632 12         59 { my $outer = \$self->{_nest}{$nodeid};
633 12     13   60 my $nested = sub { $$outer->(@_) };
  13         52  
634              
635             # The code must be blessed in the right class, to be compiled
636             # correctly inside its parent.
637 12 50       30 bless $nested, 'BLOCK' if @sgs;
638              
639 12         85 return ($nodetype, $nested);
640             }
641 1888         5320 $self->{_nest}{$nodeid} = undef;
642              
643             # Construct XML tag to use
644              
645 1888 100       4064 my $trans = $qual ? 'makeTagQualified' : 'makeTagUnqualified';
646 1888         7684 my $tag = $self->$trans($where, $node, $name, $ns);
647              
648             # Construct type processor
649              
650 1888         3203 my ($comptype, $comps);
651 1888         5948 my $nr_childs = $tree->nrChildren;
652 1888 100       4687 if(my $isa = $node->getAttribute('type'))
    100          
    50          
653             { # explicitly names type
654 1369 50       14966 $nr_childs==0
655             or error __x"no childs expected with attribute `type' at {where}", where => $where, _class => 'schema';
656              
657 1369         4721 $comptype = $self->rel2abs($where, $node, $isa);
658 1369   66     4538 $comps = $self->blocked($where, anyType => $comptype) || $self->typeByName($where, $tree, $comptype);
659             }
660             elsif($nr_childs==0)
661             { # default type for substGroups is type of base-class
662 17         162 my $base_node = $node;
663 17         40 local $self->{_context};
664 17         44 while(my $subst = $base_node->getAttribute('substitutionGroup'))
665 5         49 { my $subst_elem = $self->rel2abs($where, $base_node, $subst);
666 5         14 my $base_elem = $self->namespaces->find(element => $subst_elem);
667 5         10 $self->{_context} = $self->nsContext($base_elem);
668 5         6 $base_node = $base_elem->{node};
669 5 50       12 my $isa = $base_node->getAttribute('type')
670             or next;
671              
672 5         73 $comptype = $self->rel2abs($where, $base_node, $isa);
673 5   33     14 $comps = $self->blocked($where, complexType => $comptype) || $self->typeByName($where, $tree, $comptype);
674 5         178 last;
675             }
676 17 100       179 unless($comptype)
677             { # no type found, so anyType
678 12         88 $comptype = $self->anyType($node);
679 12         46 $comps = $self->typeByName($where, $tree, $comptype);
680             }
681             }
682             elsif($nr_childs!=1)
683 0         0 { error __x"expected is only one child node at {where}"
684             , where => $where, _class => 'schema';
685             }
686             else # nameless types
687 502         8938 { my $child = $tree->firstChild;
688 502         1879 my $local = $child->localname;
689 502         1729 my $nest = $tree->descend($child);
690              
691             # Sometimes extension or restriction with base attribute required for hooks
692 502         1385 my $ext = $nest->firstChild;
693 502 100       2094 my $base = $ext ? $ext->getAttribute('base') : undef;
694 502 100       8173 my $basex = $base ? $self->rel2abs($where, $ext, $base) : undef;
695              
696 502 50 100     3484 ($comps, $comptype)
    100 50        
697             = $local eq 'simpleType'
698             ? ($self->simpleType($nest, 0), $basex // 'unnamed simple')
699             : $local eq 'complexType'
700             ? ($self->complexType($nest), $basex // 'unnamed complex')
701             : error __x"illegal element child `{name}' at {where}", name => $local, where => $where, _class => 'schema';
702             }
703              
704             my ($st, $elems, $attrs, $attrs_any)
705 1886         23237 = @$comps{ qw/st elems attrs attrs_any/ };
706 1886   100     13579 $_ ||= [] for $elems, $attrs, $attrs_any;
707              
708             # Construct basic element handler
709              
710 1886         3388 my $is_simple = defined $st;
711 1886   100     5701 my $nillable = $self->isTrue($node->getAttribute('nillable') || 'false');
712              
713             my $elem_handler
714 1886 100 66     8980 = $comps->{mixed} ? 'makeMixedElement'
    100          
    100          
715             : ! $is_simple ? 'makeComplexElement' # other complexType
716             : (@$attrs || @$attrs_any) ? 'makeTaggedElement' # complex/simpleContent
717             : 'makeSimpleElement';
718              
719 1886   66     10194 my $r = $self->$elem_handler
720             ( $where, $tag, ($st||$elems), $attrs, $attrs_any, $comptype, $nillable);
721              
722             # Add defaults and stuff
723 1886         8944 my $default = $node->getAttributeNode('default');
724 1886         5678 my $fixed = $node->getAttributeNode('fixed');
725              
726 1886 50 66     4945 $default && $fixed
727             and error __x"element can not have default and fixed at {where}", where => $tree->path, _class => 'schema';
728              
729 1886 100       4657 my $value
    100          
730             = $default ? $default->textContent
731             : $fixed ? $fixed->textContent
732             : undef;
733              
734 1886 100       5664 my $generate
    100          
    100          
735             = $abstract ? 'makeElementAbstract'
736             : $default ? 'makeElementDefault'
737             : $fixed ? 'makeElementFixed'
738             : 'makeElement';
739              
740 1886         6870 my $do = $self->$generate($where, $ns, $nodetype, $r, $value, $tag);
741              
742             # hrefs are used by SOAP-RPC
743             $do = $self->makeElementHref($where, $ns, $nodetype, $do)
744 1886 50 33     6984 if $self->{permit_href} && $self->actsAs('READER');
745              
746             # Implement hooks
747 1886         5523 my ($before, $replace, $after) = $self->findHooks($where, $comptype, $node);
748              
749 1886 100 100     10738 $do = $self->makeHook($where, $do, $tag, $before, $replace, $after, $comptype)
      100        
750             if $before || $replace || $after;
751              
752             $do = $self->xsiType($tree, $node, $name, $comptype, $do)
753 1886 100 66     9061 if $comptype && $self->{xsi_type}{$comptype};
754              
755             $do = $self->addTypeAttribute($comptype, $do)
756 1886 100 100     4811 if $self->{xsi_type_everywhere} && $comptype !~ /^unnamed /;
757              
758 1886         5052 $self->{_created}{$nodeid} = $do;
759              
760 1886 100       3908 $do = $self->substitutionGroup($tree, $fullname, $nodetype, $do, \@sgs)
761             if @sgs;
762              
763             # handle recursion
764             # this must look very silly to you... however, this is resolving
765             # recursive schemas: this way nested use of the same element
766             # definition will catch the code reference of the outer definition.
767 1886         3467 $self->{_nest}{$nodeid} = $do;
768 1886         3710 delete $self->{_nest}{$nodeid}; # clean the outer definition
769              
770 1886         22809 ($nodetype, $do);
771             }
772              
773             sub particle($)
774 1732     1732 0 3172 { my ($self, $tree) = @_;
775              
776 1732         3570 my $node = $tree->node;
777 1732         7077 my $local = $node->localName;
778 1732         3520 my $where = $tree->path;
779              
780 1732         4348 my $min = $node->getAttribute('minOccurs');
781 1732         18955 my $max = $node->getAttribute('maxOccurs');
782              
783 1732 100       14145 unless(defined $min)
784 1470 100 100     6689 { $min = ($self->actsAs('WRITER') || $self->{default_values} ne 'EXTEND')
785             && ($node->getAttribute('default') || $node->getAttribute('fixed'))
786             ? 0 : 1;
787             }
788              
789             $min = 0 if $self->{interpret_nillable_as_optional}
790 1732 100 100     15417 && $self->isTrue($node->getAttribute('nillable') || 'false');
      100        
791              
792             # default attribute in writer means optional, but we want to see
793             # them in the reader, to see the value.
794            
795 1732 100       3808 defined $max or $max = 1;
796             $max = 'unbounded'
797 1732 100 100     7085 if $max ne 'unbounded' && $max > 1 && !$self->{check_occurs};
      100        
798              
799             $min = 0
800 1732 100 100     4154 if $max eq 'unbounded' && !$self->{check_occurs};
801              
802 1732 100       3539 return $self->anyElement($tree, $min, $max)
803             if $local eq 'any';
804              
805 1722 50       11644 my ($label, $process)
    100          
    100          
806             = $local eq 'element' ? $self->particleElement($tree)
807             : $local eq 'group' ? $self->particleGroup($tree)
808             : $local =~ $particle_blocks ? $self->particleBlock($tree)
809             : error __x"unknown particle type '{name}' at {where}"
810             , name => $local, where => $tree->path, _class => 'schema';
811              
812 1722 100       25533 defined $label
813             or return ();
814              
815 1706 100       4759 if(ref $process eq 'BLOCK')
816 627         1540 { my $key = $self->keyRewrite($label);
817 627         2013 my $multi = $self->blockLabel($local, $key);
818 627         2362 return $self->makeBlockHandler($where, $label, $min, $max
819             , $process, $local, $multi);
820             }
821              
822             # only elements left
823 1079         1556 my $required;
824 1079         7403 my $key = $self->keyRewrite($label);
825 1079 100       4331 $required = $self->makeRequired($where, $key, $process) if $min!=0;
826              
827 1079 100       2981 ($self->actsAs('READER') ? $label : $key) =>
828             $self->makeElementHandler($where, $key, $min,$max, $required, $process);
829             }
830              
831             sub particleElement($)
832 1110     1110 0 1984 { my ($self, $tree) = @_;
833              
834 1110         2530 my $node = $tree->node;
835 1110 100       2637 if(my $ref = $node->getAttribute('ref'))
836 79         803 { my $where = $tree->path . "/$ref";
837 79         290 my $refname = $self->rel2abs($tree, $node, $ref);
838 79 100       286 return () if $self->blocked($where, ref => $refname);
839              
840 67 50       226 my $def = $self->namespaces->find(element => $refname)
841             or error __x"cannot find ref element '{name}' at {where}"
842             , name => $refname, where => $where, _class => 'schema';
843              
844             return $self->element($tree->descend($def->{node}
845 67         300 , $self->prefixed($refname, 1)));
846             }
847              
848 1031         10153 my $name = $node->getAttribute('name');
849 1031         9465 $self->element($tree->descend($node, $name));
850             }
851              
852             # blockLabel KIND, LABEL
853             # Particle blocks, like `sequence' and `choice', which have a maxOccurs
854             # (maximum occurrence) which is 2 of more, are represented by an ARRAY
855             # of HASHs. The label with such a block is derived from its first element.
856             # This function determines how.
857             # seq_address sequence get seq_ prepended
858             # cho_gender choices get cho_ before them
859             # all_money an all block can also be repreated in spec >1.1
860             # gr_people group refers to a block of above type, but
861             # that type is not reflected in the name
862              
863             my %block_abbrev = qw/sequence seq_ choice cho_ all all_ group gr_/;
864             sub blockLabel($$)
865 627     627 0 1519 { my ($self, $kind, $label) = @_;
866 627 100       1580 return $label if $kind eq 'element';
867              
868 608         1947 $label =~ s/^(?:seq|cho|all|gr)_//;
869 608         2163 $block_abbrev{$kind} . (unpack_type $label)[1];
870             }
871              
872             sub particleGroup($)
873 20     20 0 58 { my ($self, $tree) = @_;
874              
875             # attributes: id, maxOccurs, minOccurs, name, ref
876             # content: annotation?, (all|choice|sequence)?
877             # apparently, a group can not refer to a group... well..
878              
879 20         58 my $node = $tree->node;
880 20 50       62 my $ref = $node->getAttribute('ref')
881             or error __x"group without ref at {where}"
882             , where => $tree->path, _class => 'schema';
883              
884 20         360 my $where = $tree->path . '#' . $ref;
885              
886 20         102 my $typename = $self->rel2abs($where, $node, $ref);
887 20 50       91 if(my $blocked = $self->blocked($where, ref => $typename))
888 0         0 { return ($typename, $blocked);
889             }
890              
891 20 50       66 my $dest = $self->namespaces->find(group => $typename)
892             or error __x"cannot find group `{name}' at {where}", name => $typename, where => $where, _class => 'schema';
893              
894 20         126 my $group = $tree->descend($dest->{node}, $self->prefixed($typename, 1));
895 20 50       73 return () if $group->nrChildren==0;
896              
897 20 50       62 $group->nrChildren==1
898             or error __x"only one particle block expected in group `{name}' at {where}", name => $typename, where => $where, _class => 'schema';
899              
900 20         70 my $local = $group->currentLocal;
901 20 50       144 $local =~ m/^(?:all|choice|sequence)$/
902             or error __x"illegal group member `{name}' at {where}", name => $local, where => $where, _class => 'schema';
903              
904 20         67 my ($blocklabel, $code) = $self->particleBlock($group->descend);
905 20 100       120 $code ? ($typename, $code) : ();
906             }
907              
908             sub particleBlock($)
909 612     612 0 1424 { my ($self, $tree) = @_;
910              
911 612         1500 my $node = $tree->node;
912 612         1626 my @pairs = map $self->particle($tree->descend($_)), $tree->childs;
913 612 100       2324 @pairs or return ();
914              
915             # label is name of first component, only needed when maxOcc > 1
916 608         1125 my $label = $pairs[0];
917 608         3131 my $blocktype = $node->localName;
918              
919 608         2140 my $call = 'make'.ucfirst $blocktype;
920 608         2054 ($label => $self->$call($tree->path, @pairs));
921             }
922              
923             sub xsiType($$$$$)
924 7     7 0 27 { my ($self, $tree, $node, $name, $type, $base) = @_;
925              
926 7         28 my %alt = ($type => $base);
927              
928 7         13 foreach my $alttype (@{$self->{xsi_type}{$type}})
  7         29  
929 11 100       32 { next if $alttype eq $type;
930              
931 7         35 my ($ns, $local) = unpack_type $alttype;
932 7         143 my $prefix = $node->lookupNamespacePrefix($ns);
933 7 50       28 defined $prefix
934             or $prefix = $self->_registerNSprefix(undef, $ns, 1);
935              
936 7 50       29 my $type = length $prefix ? "$prefix:$local" : $local;
937              
938             # do not accidentally use the default namespace, when there
939             # may also be namespace-less types used.
940 7         61 my $doc = $node->ownerDocument;
941 7         73 my $altnode = $doc->createElement('element');
942 7         40 $altnode->setNamespace(SCHEMA2001, 'temp1234', 1);
943 7         227 $altnode->setNamespace($ns, $prefix);
944 7         127 $altnode->setAttribute(name => $name);
945 7         138 $altnode->setAttribute(type => $type);
946              
947 7         89 delete $self->{_created}{$altnode->unique_key}; # clean nesting cache
948 7         51 (undef, $alt{$alttype}) = $self->element($tree->descend($altnode));
949             }
950 7         180 $self->makeXsiTypeSwitch($tree->path, $name, $type, \%alt);
951             }
952              
953             sub substitutionGroup($$$$$)
954 21     21 0 72 { my ($self, $tree, $fullname, $label, $base, $sgs) = @_;
955              
956 21 50       136 if(Log::Report->needs('TRACE')) # dump table of substgroup alternatives
957 0         0 { my $labelrw = $self->keyRewrite($label);
958 0         0 my @full = sort map $_->{full}, @$sgs;
959 0         0 my $longest = max map length, @full;
960 0         0 my @c = map sprintf("%-${longest}s %s",$_,$self->keyRewrite($_)), @full;
961 0         0 local $" = "\n ";
962 0         0 trace "substitutionGroup $fullname$\"BASE=$label ($labelrw)$\"@c";
963             }
964              
965 21         434 my @elems;
966 21 50       113 push @elems, $label => [$self->keyRewrite($label), $base] if $base;
967              
968 21         48 foreach my $subst (@$sgs)
969 40         237 { my ($l, $d) = $self->element($tree->descend($subst->{node}), 1);
970 40 50       759 push @elems, $l => [$self->keyRewrite($l), $d] if defined $d;
971             }
972              
973 21         102 $self->makeSubstgroup($tree->path.'#subst', $fullname, @elems);
974             }
975              
976             sub keyRewrite($;$)
977 2111     2111 0 3591 { my $self = shift;
978 2111 100       8208 my ($ns, $key) = @_==1 ? unpack_type($_[0]) : @_;
979 2111         3713 my $oldkey = $key;
980              
981 2111         2618 foreach my $r ( @{$self->{rewrite}} )
  2111         5232  
982 115 100       456 { if(ref $r eq 'HASH')
    100          
    50          
    100          
    50          
    0          
983 14         55 { my $full = pack_type $ns, $key;
984 14 100       51 $key = $r->{$full} if defined $r->{$full};
985 14 50       37 $key = $r->{$key} if defined $r->{$key};
986             }
987             elsif(ref $r eq 'CODE')
988 51         126 { $key = $r->($ns, $key);
989             }
990             elsif($r eq 'UNDERSCORES')
991 0         0 { $key =~ s/-/_/g;
992             }
993             elsif($r eq 'SIMPLIFIED')
994 21         80 { $key =~ s/-/_/g;
995 21         80 $key =~ s/\W//g;
996 21         58 $key = lc $key;
997             }
998             elsif($r eq 'PREFIXED')
999 29         57 { my $p = $self->{prefixes};
1000 29 100       109 my $prefix = $p->{$ns} ? $p->{$ns}{prefix} : '';
1001 29 100       108 $key = $prefix . '_' . $key if $prefix ne '';
1002             }
1003             elsif($r =~ m/^PREFIXED\(\s*(.*?)\s*\)$/)
1004 0         0 { my @l = split /\s*\,\s*/, $1;
1005 0         0 my $p = $self->{prefixes};
1006 0 0       0 my $prefix = $p->{$ns} ? $p->{$ns}{prefix} : '';
1007 0 0       0 $key = $prefix . '_' . $key if grep {$prefix eq $_} @l;
  0         0  
1008             }
1009             else
1010 0         0 { error __x"key rewrite `{got}' not understood", got => $r;
1011             }
1012             }
1013              
1014 2111 100       5221 trace "rewrote type @_ to $key"
1015             if $key ne $oldkey;
1016              
1017 2111         6751 $key;
1018             }
1019              
1020             sub prefixed($;$)
1021 1004     1004 0 2587 { my ($self, $qname, $hide_use) = @_;
1022             # hide_use = do not cause inclusion in output prefix table
1023              
1024 1004         4675 my ($ns, $local) = unpack_type $qname;
1025 1004 50       3328 defined $ns or return $qname;
1026              
1027 1004 100       6727 my $pn = $self->{prefixes}{$ns} or return;
1028 269 100       1406 $pn->{used}++ unless $hide_use;
1029 269 100       1531 length $pn->{prefix} ? "$pn->{prefix}:$local" : $local;
1030             }
1031              
1032             sub prefixForNamespace($)
1033 0     0 0 0 { my ($self, $ns) = @_;
1034 0 0       0 my $def = $self->{prefixes}{$ns} or return;
1035 0         0 $def->{prefix};
1036             }
1037              
1038             sub attribute($)
1039 261     261 0 541 { my ($self, $tree) = @_;
1040              
1041             # attributes: default, fixed, form, id, name, ref, type, use
1042             # content: annotation?, simpleType?
1043              
1044 261         660 my $node = $tree->node;
1045 261         2052 my $parent = $node->parentNode;
1046 261   66     604 my $is_global= $parent && $parent->localname eq 'schema';
1047 261         2561 my $where = $tree->path;
1048              
1049 261         523 my $context = $self->{_context};
1050              
1051 261 100       770 if(my $refattr = $node->getAttribute('ref'))
1052             {
1053 5         100 my $refname = $self->rel2abs($tree, $node, $refattr);
1054 5 50       27 return () if $self->blocked($where, ref => $refname);
1055              
1056 5 50       20 my $def = $self->namespaces->find(attribute => $refname)
1057             or error __x"cannot find attribute {name} at {where}"
1058             , name => $refname, where => $where, _class => 'schema';
1059              
1060 5         19 local $self->{_context} = $def;
1061 5         23 return $self->attribute($tree->descend($def->{node}));
1062             }
1063              
1064             # Not a ref to attribute
1065 256 50       3338 my $name = $node->getAttribute('name')
1066             or error __x"attribute without name at {where}", where => $where;
1067 256         2879 $where .= '/@'.$name;
1068 256         832 $self->assertType($where, name => NCName => $name);
1069              
1070 256         511 my ($qual, $ns, $fullname);
1071 256 100       618 if($is_global)
1072 13   33     29 { $ns = $node->getAttribute('targetNamespace')
1073             || $parent->getAttribute('targetNamespace');
1074 13         227 $fullname= pack_type $ns, $name;
1075 13         34 my $def = $self->namespaces->find(attribute => $fullname);
1076 13         37 $context = $self->nsContext($def);
1077 13         31 $qual = $context->{qual_top};
1078             }
1079             else
1080 243         446 { $qual = $context->{qual_attr};
1081 243         448 $ns = $context->{tns};
1082 243         841 $fullname= pack_type $ns, $name;
1083             }
1084 256 100       677 local $self->{_context} = $context if $is_global;
1085              
1086 256 50       662 if(my $form = $node->getAttribute('form'))
1087 0 0       0 { $qual
    0          
1088             = $form eq 'qualified' ? 1
1089             : $form eq 'unqualified' ? 0
1090             : error __x"form must be (un)qualified, not `{form}' at {where}"
1091             , form => $form, where => $where, _class => 'schema';
1092             }
1093              
1094             # no default prefixes for attributes
1095             #warn "#", $self->prefixForNamespace($ns), "#";
1096             # error __x"attribute namespace {ns} cannot be the default namespace"
1097             # , ns => $ns
1098             # if $qual && $ns && $self->prefixForNamespace($ns) eq '';
1099              
1100 256         2713 my ($type, $typeattr);
1101 256 100       751 if($tree->nrChildren==1)
1102 7 50       20 { $tree->currentLocal eq 'simpleType'
1103             or error __x"attribute child can only be `simpleType', not `{found}' at {where}"
1104             , found => $tree->currentLocal, where => $where
1105             , _class => 'schema';
1106              
1107 7         25 $type = $self->simpleType($tree->descend);
1108             }
1109             else
1110 249 50       578 { $name = $node->getAttribute('name')
1111             or error __x"attribute without name or ref at {where}"
1112             , where => $where, _class => 'schema';
1113              
1114 249         2695 $typeattr = $node->getAttribute('type');
1115             }
1116              
1117 256 100       2221 unless($type)
1118 249 100       1088 { my $typename = defined $typeattr
1119             ? $self->rel2abs($where, $node, $typeattr)
1120             : $self->anyType($node);
1121              
1122 249   66     731 $type = $self->blocked($where, simpleType => $typename)
1123             || $self->typeByName($where, $tree, $typename);
1124             }
1125              
1126             my $st = $type->{st}
1127 256 50       937 or error __x"attribute not based in simple value type at {where}"
1128             , where => $where, _class => 'schema';
1129              
1130 256 100       593 my $trans = $qual ? 'makeTagQualified' : 'makeTagUnqualified';
1131 256 100       540 my $qns = $qual ? $context->{tns} : '';
1132 256         1045 my $tag = $self->$trans($where, $node, $name, $qns);
1133              
1134 256   100     839 my $use = $node->getAttribute('use') || '';
1135 256 50       4352 $use =~ m/^(?:optional|required|prohibited|)$/
1136             or error __x"attribute use is required, optional or prohibited (not '{use}') at {where}"
1137             , use => $use, where => $where, _class => 'schema';
1138              
1139 256         1089 my $default = $node->getAttributeNode('default');
1140 256         785 my $fixed = $node->getAttributeNode('fixed');
1141              
1142 256 100       1035 my $generate
    100          
    100          
    100          
1143             = defined $default ? 'makeAttributeDefault'
1144             : defined $fixed ? 'makeAttributeFixed'
1145             : $use eq 'required' ? 'makeAttributeRequired'
1146             : $use eq 'prohibited'? 'makeAttributeProhibited'
1147             : 'makeAttribute';
1148              
1149 256 100       537 my $value = defined $default ? $default : $fixed;
1150 256         2242 my $label = $self->keyRewrite($qns, $name);
1151 256         1195 my $do = $self->$generate($where, $qns, $tag, $label, $st, $value);
1152 256 50       2257 defined $do ? ($label => $do) : ();
1153             }
1154              
1155             sub attributeGroup($)
1156 6     6 0 15 { my ($self, $tree) = @_;
1157              
1158             # attributes: id, ref = QName
1159             # content: annotation?
1160              
1161 6         19 my $node = $tree->node;
1162 6         330 my $where = $tree->path;
1163 6 50       23 my $ref = $node->getAttribute('ref')
1164             or error __x"attributeGroup use without ref at {where}"
1165             , where => $tree->path, _class => 'schema';
1166              
1167 6         98 my $typename = $self->rel2abs($where, $node, $ref);
1168 6 50       23 return () if $self->blocked($where, ref => $typename);
1169              
1170 6 50       21 my $def = $self->namespaces->find(attributeGroup => $typename)
1171             or error __x"cannot find attributeGroup {name} at {where}"
1172             , name => $typename, where => $where, _class => 'schema';
1173              
1174 6         31 local $self->{tns} = $def->{ns};
1175 6         24 $self->attributeList($tree->descend($def->{node}));
1176             }
1177              
1178             # Don't known how to handle notQName
1179             sub anyAttribute($)
1180 10     10 0 18 { my ($self, $tree) = @_;
1181              
1182             # attributes: id
1183             # , namespace = ##any|##other| List of (anyURI|##targetNamespace|##local)
1184             # , notNamespace = List of (anyURI|##targetNamespace|##local)
1185             # ignored attributes
1186             # , notQName = List of QName
1187             # , processContents = lax|skip|strict
1188             # content: annotation?
1189              
1190 10         38 my $node = $tree->node;
1191 10         14 my $where = $tree->path . '@any';
1192              
1193 10         18 my $handler = $self->{any_attribute};
1194 10   50     17 my $namespace = $node->getAttribute('namespace') || '##any';
1195 10         101 my $not_ns = $node->getAttribute('notNamespace');
1196 10   50     61 my $process = $node->getAttribute('processContents') || 'strict';
1197              
1198 10 50 33     79 warn "HELP: please explain me how to handle notQName"
1199             if $^W && $node->getAttribute('notQName');
1200              
1201 10         20 my ($yes, $no) = $self->translateNsLimits($namespace, $not_ns);
1202 10         48 my $do = $self->makeAnyAttribute($where, $handler, $yes, $no, $process);
1203 10 100       41 defined $do ? $do : ();
1204             }
1205              
1206             sub anyElement($$$)
1207 10     10 0 23 { my ($self, $tree, $min, $max) = @_;
1208              
1209             # attributes: id, maxOccurs, minOccurs,
1210             # , namespace = ##any|##other| List of (anyURI|##targetNamespace|##local)
1211             # , notNamespace = List of (anyURI|##targetNamespace|##local)
1212             # ignored attributes
1213             # , notQName = List of QName
1214             # , processContents = lax|skip|strict
1215             # content: annotation?
1216              
1217 10         14 my $node = $tree->node;
1218 10         15 my $where = $tree->path . '#any';
1219 10         30 my $handler = $self->{any_element};
1220              
1221 10   50     14 my $namespace = $node->getAttribute('namespace') || '##any';
1222 10         82 my $not_ns = $node->getAttribute('notNamespace');
1223 10   50     58 my $process = $node->getAttribute('processContents') || 'strict';
1224              
1225 10 50 33     71 info "HELP: please explain me how to handle notQName"
1226             if $^W && $node->getAttribute('notQName');
1227              
1228 10         20 my ($yes, $no) = $self->translateNsLimits($namespace, $not_ns);
1229 10         34 (any => $self->makeAnyElement($where, $handler, $yes, $no
1230             , $process, $min, $max));
1231             }
1232              
1233             sub translateNsLimits($$)
1234 20     20 0 45 { my ($self, $include, $exclude) = @_;
1235              
1236             # namespace = ##any|##other| List of (anyURI|##targetNamespace|##local)
1237             # notNamespace = List of (anyURI |##targetNamespace|##local)
1238             # handling of ##local ignored: only full namespaces are supported for now
1239              
1240 20 100       33 return (undef, []) if $include eq '##any';
1241              
1242 12         16 my $tns = $self->{_context}{tns};
1243 12 100       49 return (undef, [$tns]) if $include eq '##other';
1244              
1245 8         7 my @return;
1246 8         19 foreach my $list ($include, $exclude)
1247 16         10 { my @list;
1248 16 100 66     37 if(defined $list && length $list)
1249 8         18 { foreach my $uri (split " ", $list)
1250 8 0       20 { push @list
    50          
1251             , $uri eq '##targetNamespace' ? $tns
1252             : $uri eq '##local' ? ()
1253             : $uri;
1254             }
1255             }
1256 16 100       36 push @return, @list ? \@list : undef;
1257             }
1258              
1259 8         14 @return;
1260             }
1261              
1262             sub complexType($)
1263 606     606 0 1395 { my ($self, $tree) = @_;
1264              
1265             # abstract, block, final, id, mixed, name, defaultAttributesApply
1266             # Full content:
1267             # annotation?
1268             # , ( simpleContent
1269             # | complexContent
1270             # | ( (group|all|choice|sequence)?
1271             # , (attribute|attributeGroup)*
1272             # , anyAttribute?
1273             # )
1274             # )
1275             # , (assert | report)*
1276              
1277 606         1520 my $node = $tree->node;
1278 606   100     1764 my $mixed = $self->isTrue($node->getAttribute('mixed') || 'false');
1279             undef $mixed
1280 606 100       2021 if $self->{mixed_elements} eq 'STRUCTURAL';
1281              
1282 606 100       1511 my $first = $tree->firstChild
1283             or return {elems => [], mixed => $mixed};
1284              
1285 582         4310 my $name = $first->localName;
1286 582 100 100     8229 return $self->complexBody($tree, $mixed)
1287             if $name =~ $particle_blocks || $name =~ $attribute_defs;
1288              
1289 56 50       183 $tree->nrChildren==1
1290             or error __x"expected is single simpleContent or complexContent at {where}"
1291             , where => $tree->path, _class => 'schema';
1292              
1293 56 100       206 return $self->simpleContent($tree->descend($first))
1294             if $name eq 'simpleContent';
1295              
1296 34 100       419 return $self->complexContent($tree->descend($first), $mixed)
1297             if $name eq 'complexContent';
1298              
1299 1         6 error __x"complexType contains particles, simpleContent or complexContent, not `{name}' at {where}"
1300             , name => $name, where => $tree->path, _class => 'schema';
1301             }
1302              
1303             sub complexBody($$)
1304 558     558 0 2234 { my ($self, $tree, $mixed) = @_;
1305              
1306 558 50       1668 $tree->currentChild
1307             or return ();
1308              
1309             # partial
1310             # (group|all|choice|sequence)?
1311             # , ((attribute|attributeGroup)*
1312             # , anyAttribute?
1313              
1314 558         2834 my @elems;
1315 558 100       1735 if($tree->currentLocal =~ $particle_blocks)
1316 526         1849 { push @elems, $self->particle($tree->descend); # unless $mixed;
1317 526         2743 $tree->nextChild;
1318             }
1319              
1320 558         2449 my @attrs = $self->attributeList($tree);
1321              
1322 558 50       1399 defined $tree->currentChild
1323             and error __x"trailing non-attribute `{name}' at {where}"
1324             , name => $tree->currentChild->localName, where => $tree->path
1325             , _class => 'schema';
1326              
1327 558         6876 {elems => \@elems, mixed => $mixed, @attrs};
1328             }
1329              
1330             sub attributeList($)
1331 586     586 0 1336 { my ($self, $tree) = @_;
1332              
1333             # partial content
1334             # ((attribute|attributeGroup)*
1335             # , anyAttribute?
1336              
1337 586         1429 my $where = $tree->path;
1338              
1339 586         1101 my (@attrs, @any);
1340 586         1506 for(my $attr = $tree->currentChild; defined $attr; $attr = $tree->nextChild)
1341 264         1229 { my $name = $attr->localName;
1342 264 100       719 if($name eq 'attribute')
    100          
1343 248         814 { push @attrs, $self->attribute($tree->descend);
1344             }
1345             elsif($name eq 'attributeGroup')
1346 6         22 { my %group = $self->attributeGroup($tree->descend);
1347 6         23 push @attrs, @{$group{attrs}};
  6         161  
1348 6         14 push @any, @{$group{attrs_any}};
  6         31  
1349             }
1350 10         18 else { last }
1351             }
1352              
1353             # officially only one: don't believe that
1354 586         1738 while($tree->currentLocal eq 'anyAttribute')
1355 10         34 { push @any, $self->anyAttribute($tree->descend);
1356 10         36 $tree->nextChild;
1357             }
1358              
1359 586         2661 (attrs => \@attrs, attrs_any => \@any);
1360             }
1361              
1362             sub simpleContent($)
1363 22     22 0 43 { my ($self, $tree) = @_;
1364              
1365             # attributes: id
1366             # content: annotation?, (restriction | extension)
1367              
1368 22 50       60 $tree->nrChildren==1
1369             or error __x"need one simpleContent child at {where}", where => $tree->path, _class => 'schema';
1370              
1371 22         112 my $name = $tree->currentLocal;
1372 22 100       85 return $self->simpleContentExtension($tree->descend)
1373             if $name eq 'extension';
1374              
1375 8 50       27 return $self->simpleContentRestriction($tree->descend)
1376             if $name eq 'restriction';
1377              
1378 0         0 error __x"simpleContent needs extension or restriction, not `{name}' at {where}"
1379             , name => $name, where => $tree->path, _class => 'schema';
1380             }
1381              
1382             sub simpleContentExtension($)
1383 14     14 0 30 { my ($self, $tree) = @_;
1384              
1385             # attributes: id, base = QName
1386             # content: annotation?
1387             # , (attribute | attributeGroup)*
1388             # , anyAttribute?
1389             # , (assert | report)*
1390              
1391 14         36 my $node = $tree->node;
1392 14         32 my $where = $tree->path . '#sext';
1393              
1394 14         73 my $base = $node->getAttribute('base');
1395 14 50       211 my $typename = defined $base ? $self->rel2abs($where, $node, $base) : $self->anyType($node);
1396              
1397 14   33     47 my $basetype = $self->blocked($where, simpleType => $typename)
1398             || $self->typeByName($where, $tree, $typename);
1399             defined $basetype->{st}
1400 14 50       250 or error __x"base of simpleContent not simple at {where}", where => $where, _class => 'schema';
1401            
1402 14         61 $self->extendAttrs($basetype, {$self->attributeList($tree)});
1403              
1404 14 50       62 $tree->currentChild
1405             and error __x"elements left at tail at {where}", where => $tree->path, _class => 'schema';
1406              
1407 14         91 $basetype;
1408             }
1409              
1410             sub simpleContentRestriction($$)
1411 8     8 0 16 { my ($self, $tree) = @_;
1412              
1413             # attributes id, base = QName
1414             # content: annotation?
1415             # , (simpleType?, facet*)?
1416             # , (attribute | attributeGroup)*, anyAttribute?
1417             # , (assert | report)*
1418              
1419 8         17 my $node = $tree->node;
1420 8         18 my $where = $tree->path . '#cres';
1421              
1422 8         13 my ($type, $typename);
1423 8   50     15 my $first = $tree->currentLocal || '';
1424 8 100       22 if($first eq 'simpleType')
    50          
1425 4         12 { $type = $self->simpleType($tree->descend);
1426 4         44 $tree->nextChild;
1427             }
1428             elsif(my $basename = $node->getAttribute('base'))
1429 4         40 { $typename = $self->rel2abs($where, $node, $basename);
1430 4   33     9 $type = $self->blocked($where, simpleType => $type)
1431             || $self->typeByName($where, $tree, $typename);
1432             }
1433             else
1434 0         0 { error __x"no base in complex-restriction, so simpleType required at {where}"
1435             , where => $where, _class => 'schema';
1436             }
1437              
1438             my $st = $type->{st}
1439 8 50       20 or error __x"not a simpleType in simpleContent/restriction at {where}"
1440             , where => $where, _class => 'schema';
1441              
1442 8         45 $type->{st} = $self->applySimpleFacets($tree, $st, 0, $typename);
1443              
1444 8         29 $self->extendAttrs($type, {$self->attributeList($tree)});
1445              
1446 8 50       29 $tree->currentChild
1447             and error __x"elements left at tail at {where}"
1448             , where => $where, _class => 'schema';
1449              
1450 8         43 $type;
1451             }
1452              
1453             sub complexContent($$)
1454 33     33 0 97 { my ($self, $tree, $mixed) = @_;
1455              
1456             # attributes: id, mixed = boolean
1457             # content: annotation?, (restriction | extension)
1458              
1459 33         159 my $node = $tree->node;
1460 33 50       98 if(my $m = $node->getAttribute('mixed'))
1461             { $mixed = $self->isTrue($m)
1462 0 0       0 if $self->{mixed_elements} ne 'STRUCTURAL';
1463             }
1464              
1465 33 50       515 $tree->nrChildren == 1
1466             or error __x"only one complexContent child expected at {where}"
1467             , where => $tree->path, _class => 'schema';
1468              
1469 33         153 my $name = $tree->currentLocal;
1470 33 100 100     157 error __x"complexContent needs extension or restriction, not `{name}' at {where}"
1471             , name => $name, where => $tree->path, _class => 'schema'
1472             if $name ne 'extension' && $name ne 'restriction';
1473              
1474 32         100 $tree = $tree->descend;
1475 32         99 $node = $tree->node;
1476 32   33     105 my $base = $node->getAttribute('base') || $self->anyType($node);
1477 32         416 my $type = {};
1478 32         91 my $where = $tree->path . '#cce';
1479              
1480 32 50       129 if($base !~ m/\banyType$/)
1481 32         113 { my $typename = $self->rel2abs($where, $node, $base);
1482 32 100       342 if($type = $self->blocked($where, complexType => $typename))
1483             { # blocked base type
1484             }
1485             else
1486 28 50       94 { my $typedef = $self->namespaces->find(complexType => $typename)
1487             or error __x"unknown base type '{type}' at {where}"
1488             , type => $typename, where => $tree->path, _class => 'schema';
1489              
1490 28         97 local $self->{_context} = $self->nsContext($typedef);
1491 28         126 $type = $self->complexType($tree->descend($typedef->{node}));
1492             }
1493             }
1494              
1495 32         134 my $own = $self->complexBody($tree, $mixed);
1496 32         216 $self->extendAttrs($type, $own);
1497              
1498 32 100       104 if($name eq 'extension')
1499 28 50       46 { push @{$type->{elems}}, @{$own->{elems} || []};
  28         69  
  28         197  
1500             }
1501             else # restriction
1502 4         58 { $type->{elems} = $own->{elems};
1503             }
1504              
1505 32   33     219 $type->{mixed} ||= $own->{mixed};
1506 32         248 $type;
1507             }
1508              
1509             #
1510             # Helper routines
1511             #
1512              
1513             # print $self->rel2abs($path, $node, '{ns}type') -> '{ns}type'
1514             # print $self->rel2abs($path, $node, 'prefix:type') -> '{ns-of-prefix}type'
1515              
1516             sub rel2abs($$$)
1517 2251     2251 0 5396 { my ($self, $where, $node, $type) = @_;
1518 2251 50       8741 return $type if substr($type, 0, 1) eq '{';
1519              
1520 2251 100       12281 my ($prefix, $local) = $type =~ m/^(.+?)\:(.*)/ ? ($1, $2) : ('', $type);
1521 2251         10996 my $uri = $node->lookupNamespaceURI($prefix);
1522 2251 100       9079 $self->_registerNSprefix($prefix, $uri, 0) if $uri;
1523              
1524 2251 50 66     6487 error __x"No namespace for prefix `{prefix}' in `{type}' at {where}"
1525             , prefix => $prefix, type => $type, where => $where, _class => 'schema'
1526             if length $prefix && !defined $uri;
1527              
1528 2251         6997 pack_type $uri, $local;
1529             }
1530              
1531             sub _registerNSprefix($$$)
1532 2489     2489   5221 { my ($self, $prefix, $uri, $used) = @_;
1533 2489         5164 my $table = $self->{prefixes};
1534              
1535 2489 100       7667 if(my $u = $table->{$uri}) # namespace already has a prefix
1536 1334         2670 { $u->{used} += $used;
1537 1334         7133 return $u->{prefix};
1538             }
1539              
1540 1155         12743 my %prefs = map +($_->{prefix} => 1), values %$table;
1541 1155         2107 my $take;
1542 1155 100 66     5770 if(defined $prefix && !$prefs{$prefix}) { $take = $prefix }
  735 50       1634  
1543 0         0 elsif(!$prefs{''}) { $take = '' }
1544             else
1545             { # prefix already in use; create a new x\d+ prefix
1546 420         769 my $count = 0;
1547 420         1997 $count++ while exists $prefs{"x$count"};
1548 420         818 $take = 'x'.$count;
1549             }
1550 1155         5627 $table->{$uri} = {prefix => $take, uri => $uri, used => $used};
1551 1155         3152 $take;
1552             }
1553              
1554             sub anyType($)
1555 15     15 0 33 { my ($self, $node) = @_;
1556 15         81 pack_type $node->namespaceURI, 'anyType';
1557             }
1558              
1559             sub findHooks($$$)
1560 1886     1886 0 4110 { my ($self, $path, $type, $node) = @_;
1561             # where is before, replace, after
1562              
1563 1886         2932 my %hooks;
1564 1886         2569 foreach my $hook (@{$self->{hooks}})
  1886         5290  
1565 61         66 { my $match;
1566              
1567             $match++
1568             if !$hook->{path} && !$hook->{id}
1569 61 0 100     264 && !$hook->{type} && !$hook->{extends};
      66        
      33        
1570              
1571 61 100 66     191 if(!$match && $hook->{path})
1572 8         13 { my $p = $hook->{path};
1573             $match++
1574 8 50   8   155 if first {ref $_ eq 'Regexp' ? $path =~ $_ : $path eq $_}
1575 8 50       60 ref $p eq 'ARRAY' ? @$p : $p;
    100          
1576             }
1577              
1578 61   100     307 my $id = !$match && $hook->{id} && $node->getAttribute('id');
1579 61 100       373 if($id)
1580 15         29 { my $i = $hook->{id};
1581             $match++
1582 15 50   15   64 if first {ref $_ eq 'Regexp' ? $id =~ $_ : $id eq $_}
1583 15 50       100 ref $i eq 'ARRAY' ? @$i : $i;
    100          
1584             }
1585              
1586 61 100 66     275 if(!$match && defined $type && $hook->{type})
      100        
1587 36         52 { my $t = $hook->{type};
1588 36         72 my ($ns, $local) = unpack_type $type;
1589             $match++
1590 36 100   36   191 if first {ref $_ eq 'Regexp' ? $type =~ $_
    50          
1591             : substr($_,0,1) eq '{' ? $type eq $_
1592             : $local eq $_
1593 36 50       163 } ref $t eq 'ARRAY' ? @$t : $t;
    100          
1594             }
1595              
1596 61 50 66     352 if(!$match && defined $type && $hook->{extends})
      66        
1597 0 0       0 { $match++ if $self->{nss}->doesExtend($type, $hook->{extends});
1598             }
1599              
1600 61 100       124 $match or next;
1601              
1602 23         44 foreach my $where ( qw/before replace after/ )
1603 69 100       149 { my $w = $hook->{$where} or next;
1604 29 100       35 push @{$hooks{$where}}, ref $w eq 'ARRAY' ? @$w : $w;
  29         122  
1605             }
1606             }
1607              
1608 1886         6576 @hooks{ qw/before replace after/ };
1609             }
1610              
1611             # Namespace blocks, in most cases because the schema refers to an
1612             # older version of itself, which is deprecated.
1613             # performance is important, because it is called increadably often.
1614              
1615             sub decodeBlocked($)
1616 779     779 0 1819 { my ($self, $what) = @_;
1617 779 50       2285 defined $what or return;
1618 779         1304 my @blocked; # code-refs called with ($type, $ns, $local, $path)
1619 779 50       3450 foreach my $w (ref $what eq 'ARRAY' ? @$what : $what)
1620             { push @blocked,
1621 86 50   86   317 !ref $w ? sub { $_[0] eq $w || $_[1] eq $w }
1622             : ref $w eq 'HASH'
1623 0 0   0   0 ? sub { defined $w->{$_[0]} ? $w->{$_[0]} : $w->{$_[1]} }
1624 30 0       192 : ref $what eq 'CODE' ? $w
    0          
    50          
1625             : error __x"blocking rule with {what} not supported", what => $w;
1626             }
1627 779         2411 \@blocked;
1628             }
1629              
1630             sub blocked($$$)
1631 2145     2145 0 4575 { my ($self, $path, $class, $type) = @_;
1632             # $class = simpleType, complexType, or ref
1633 2145 100       2699 @{$self->{blocked_nss}} or return ();
  2145         12733  
1634              
1635 86         268 my ($ns, $local) = unpack_type $type;
1636 86         122 my $is_blocked;
1637 86         96 foreach my $blocked ( @{$self->{blocked_nss}} )
  86         205  
1638 86         162 { $is_blocked = $blocked->($type, $ns, $local, $path);
1639 86 50       202 last if defined $is_blocked;
1640             }
1641 86 100       268 $is_blocked or return;
1642              
1643 38         159 trace "$type of $class is blocked";
1644 38         1095 $self->makeBlocked($path, $class, $type);
1645             }
1646              
1647             sub addTypeAttribute($$)
1648 0     0 0   { my ($self, $type, $call) = @_;
1649 0           $call;
1650             }
1651              
1652             #------------
1653              
1654             1;