File Coverage

lib/XML/Compile/Translate.pm
Criterion Covered Total %
statement 672 718 93.5
branch 373 528 70.6
condition 133 192 69.2
subroutine 62 66 93.9
pod 3 46 6.5
total 1243 1550 80.1


line stmt bran cond sub pod time code
1             # Copyrights 2006-2019 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             # This code is part of distribution XML-Compile. Meta-POD processed with
6             # OODoc into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package XML::Compile::Translate;
10 50     50   346 use vars '$VERSION';
  50         99  
  50         2604  
11             $VERSION = '1.62';
12              
13              
14 50     50   276 use warnings;
  50         86  
  50         1181  
15 50     50   243 use strict;
  50         88  
  50         1045  
16 50     50   233 no warnings 'recursion'; # trees can be quite deep
  50         83  
  50         2188  
17              
18             # Errors are either in _class 'usage': called with request
19             # or 'schema': syntax error in schema
20              
21 50     50   260 use Log::Report 'xml-compile', syntax => 'SHORT';
  50         97  
  50         304  
22 50     50   13604 use List::Util qw/first max/;
  50         110  
  50         3550  
23              
24 50     50   343 use XML::Compile::Schema::Specs;
  50         85  
  50         1381  
25 50     50   19680 use XML::Compile::Schema::BuiltInFacets;
  50         124  
  50         3061  
26 50     50   358 use XML::Compile::Schema::BuiltInTypes qw/%builtin_types/;
  50         2231  
  50         4856  
27 50         2645 use XML::Compile::Util qw/pack_type unpack_type type_of_node SCHEMA2001
28 50     50   407 unpack_id/;
  50         85  
29 50     50   20302 use XML::Compile::Iterator ();
  50         122  
  50         513945  
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 771     771 1 1578 { my ($baseclass, $trans) = (shift, shift);
51 771 50       2061 my $class = $translators{$trans}
52             or error __x"translator back-end {name} not defined", name => $trans;
53              
54 771         42284 eval "require $class";
55 771 50       9851 fault $@ if $@;
56              
57 771         4347 (bless {}, $class)->init( {@_} );
58             }
59              
60             sub init($)
61 771     771 0 1692 { my ($self, $args) = @_;
62 771 50       2761 $self->{nss} = $args->{nss} or panic "no namespace tables";
63 771   50     3061 $self->{prefixes} = $args->{prefixes} || {};
64 771         2328 $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 771     771 1 5556 { my ($self, $item, %args) = @_;
84 771         7168 @$self{keys %args} = values %args; # dirty. Always all the same fields
85              
86 771   66     3130 my $path = $self->prefixed($item, 1) || $item;
87 771 50       1768 ref $item
88             and panic "expecting an item as point to start at $path";
89              
90 771   100     1969 my $hooks = $self->{hooks} ||= [];
91 771   100     1633 my $typemap = $self->{typemap} ||= {};
92 771         2659 $self->typemapToHooks($hooks, $typemap);
93              
94             $self->{blocked_nss}
95 771         2386 = $self->decodeBlocked(delete $self->{block_namespace});
96              
97 771         2238 my $nsp = $self->namespaces;
98 771         1592 foreach my $t (keys %$typemap)
99 9 50 33     35 { $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 771 50       1405 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 771         1554 delete $self->{_created};
111 771         2358 my $produce = $self->topLevel($path, $item, 1);
112 769         7027 delete $self->{_created};
113              
114             my $in = $self->{include_namespaces}
115 769 100       8998 or return $produce;
116              
117 121         460 $self->makeWrapperNs($path, $produce, $self->{prefixes}, $in);
118             }
119              
120             sub assertType($$$$)
121 2134     2134 0 4395 { my ($self, $where, $field, $type, $value) = @_;
122 2134         4475 my $checker = $builtin_types{$type}{check};
123 2134 50       3772 unless(defined $checker)
124 0         0 { mistake "useless assert for type $type";
125 0         0 return;
126             }
127              
128 2134 50       5157 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 132 { my ($self, $in, $add) = @_;
138              
139 54 50       138 if(my $a = $add->{attrs})
140             { # new attrs overrule old definitions (restrictions)
141 54         104 my (@attrs, %code);
142 54 100       99 my @all = (@{$in->{attrs} || []}, @{$add->{attrs} || []});
  54 50       198  
  54         233  
143 54         153 while(@all)
144 80         167 { my ($type, $code) = (shift @all, shift @all);
145 80 50       183 if($code{$type})
146 0         0 { $attrs[$code{$type}] = $code;
147             }
148             else
149 80         157 { push @attrs, $type => $code;
150 80         1955 $code{$type} = $#attrs;
151             }
152             }
153 54         175 $in->{attrs} = \@attrs;
154             }
155              
156             # doing this correctly is too complex for now
157 54 50       179 unshift @{$in->{attrs_any}}, @{$add->{attrs_any}} if $add->{attrs_any};
  54         132  
  54         89  
158 54         101 $in;
159             }
160              
161 2452 50   2452 0 36108 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 2055     2055 0 3263 { my ($self, $def) = @_;
167 2055 50       3472 $def or return {};
168              
169 2055         3071 my $tns = $def->{ns};
170              
171             # top elements are to be qualified unless there is no targetNamespace
172 2055 100       6349 my %context = (tns => $tns, qual_top => ($tns ? 1 : 0));
173              
174 2055         3749 my $el_qual = $def->{efd} eq 'qualified';
175 2055 100       3971 if(exists $self->{elements_qualified})
176 1817   50     3634 { my $qual = $self->{elements_qualified} || 0;
177 1817 50       3078 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 1817 100       3934 { $el_qual = $qual eq 'ALL' ? 1 : $qual eq 'NONE' ? 0 : $qual;
    100          
183             }
184 1817 100       3696 $context{qual_top} = 0 if $qual eq 'NONE';
185             }
186 2055         3135 $context{qual_elem} = $el_qual;
187              
188 2055         3076 my $at_qual = $def->{afd} eq 'qualified';
189 2055 100       3624 if(exists $self->{attributes_qualified})
190 22   50     29 { my $qual = $self->{attributes_qualified} || 0;
191 22 50       34 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       38 { $at_qual = $qual eq 'ALL' ? 1 : $qual eq 'NONE' ? 0 : $qual;
    50          
196             }
197             }
198 2055         3116 $context{qual_attr} = $at_qual;
199              
200 2055         5232 \%context;
201             }
202              
203 4959     4959 0 13936 sub namespaces() { $_[0]->{nss} }
204              
205             sub topLevel($$;$)
206 771     771 0 1844 { 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 771         4046 );
214              
215 771 100       1674 if($internal)
216             { my $builtin = $self->makeBuiltin($fullname, undef
217 2         7 , $fullname, $internal, $self->{check_values});
218             my $builder = $self->actsAs('WRITER')
219 1     1   4 ? sub { $_[0]->createTextNode($builtin->(@_)) }
220 2 100       8 : $builtin;
221 2         6 return $self->makeElementWrapper($path, $builder);
222             }
223              
224 769         1572 my $nss = $self->namespaces;
225 769 0 66     2166 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 769         1366 my $node = $top->{node};
234 769         3681 my $schemans = $node->namespaceURI;
235             my $tree = XML::Compile::Iterator->new($node, $path, sub
236 8973     8973   10011 { my $n = shift;
237 8973 100 66     69301 $n->isa('XML::LibXML::Element')
238             && $n->namespaceURI eq $schemans
239             && $n->localName !~ $ignore_elements
240 769         5759 });
241              
242 769         1536 delete $self->{_nest}; # reset recursion administration
243              
244 769         2156 local $self->{_context} = $self->nsContext($top);
245 769         2960 my $name = $node->localName;
246 769         1241 my $data;
247 769 100       1669 if($name eq 'element')
    50          
248 761         2227 { my ($label, $make) = $self->element($tree, $is_root);
249 759 50       11561 $data = $self->makeElementWrapper($path, $make) if $make;
250             }
251             elsif($name eq 'attribute')
252 8         25 { my $make = $self->attribute($tree);
253 8 50       125 $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 767         5006 $data;
262             }
263              
264             sub typeByName($$$)
265 1969     1969 0 3738 { my ($self, $where, $tree, $typename) = @_;
266              
267 1969         4149 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 1969         7702 );
278              
279 1969 100       4034 if($def)
280             { # Is built-in
281 1589         5245 my $st = $self->makeBuiltin($where, $node, $typename, $def, $self->{check_values});
282              
283 1589         7980 return +{ st => $st, is_list => $def->{is_list} };
284             }
285              
286             #
287             # not a schema standard type
288             #
289 380 50 66     961 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 380         943 local $self->{_context} = $self->nsContext($top);
295 380         1234 my $typeimpl = $tree->descend($top->{node});
296              
297 380         739 my $typedef = $top->{type};
298 380 50       1721 $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 649 { my ($self, $tree, $in_list) = @_;
306              
307 372 50       884 $tree->nrChildren==1
308             or error __x"simpleType must have exactly one child at {where}"
309             , where => $tree->path, _class => 'schema';
310              
311 372         1389 my $child = $tree->firstChild;
312 372         1133 my $name = $child->localName;
313 372         764 my $nest = $tree->descend($child);
314              
315             # Full content:
316             # annotation?
317             # , (restriction | list | union)
318              
319 372 50       1546 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         812 delete @$type{'attrs','attrs_any'}; # spec says ignore attrs
327 372         1509 $type;
328             }
329              
330             sub simpleList($)
331 56     56 0 98 { my ($self, $tree) = @_;
332              
333             # attributes: id, itemType = QName
334             # content: annotation?, simpleType?
335              
336 56         139 my $per_item;
337 56         105 my $node = $tree->node;
338 56         105 my $where = $tree->path . '#list';
339              
340 56 100       140 if(my $type = $node->getAttribute('itemType'))
341 40 50       447 { $tree->nrChildren==0
342             or error __x"list with both itemType and content at {where}"
343             , where => $where, _class => 'schema';
344              
345 40         91 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       172 { $tree->nrChildren==1
351             or error __x"list expects one simpleType child at {where}"
352             , where => $where, _class => 'schema';
353              
354 16 50       44 $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         40 $per_item = $self->simpleType($tree->descend, 1);
359             }
360              
361             my $st = $per_item->{st}
362 56 50       388 or panic "list did not produce a simple type at $where";
363              
364 56         367 $per_item->{st} = $self->makeList($where, $st);
365 56         108 $per_item->{is_list} = 1;
366 56         102 $per_item;
367             }
368              
369             sub simpleUnion($)
370 37     37 0 59 { my ($self, $tree) = @_;
371              
372             # attributes: id, memberTypes = List of QName
373             # content: annotation?, simpleType*
374              
375 37         136 my $node = $tree->node;
376 37         66 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         75 local $self->{check_values} = 1;
384              
385 37         49 my @types;
386 37 100       80 if(my $members = $node->getAttribute('memberTypes'))
387 27         334 { foreach my $union (split " ", $members)
388 43         93 { my $typename = $self->rel2abs($where, $node, $union);
389 43   33     107 my $type = $self->blocked($where, simpleType => $typename)
390             || $self->typeByName($where, $tree, $typename);
391             my $st = $type->{st}
392 43 50       322 or error __x"union only of simpleTypes, but {type} is complex at {where}"
393             , type => $typename, where => $where, _class => 'schema';
394              
395 43         113 push @types, $st;
396             }
397             }
398              
399 37         175 foreach my $child ($tree->childs)
400 39         286 { my $name = $child->localName;
401 39 50       87 $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         98 my $ctype = $self->simpleType($tree->descend($child), 0);
406 39         490 push @types, $ctype->{st};
407             }
408              
409 37         380 my $do = $self->makeUnion($where, @types);
410 37         142 { st => $do, is_union => 1 };
411             }
412              
413             sub simpleRestriction($$)
414 279     279 0 502 { my ($self, $tree, $in_list) = @_;
415              
416             # attributes: id, base = QName
417             # content: annotation?, simpleType?, facet*
418              
419 279         735 my $node = $tree->node;
420 279         496 my $where = $tree->path . '#sres';
421              
422 279         444 my ($base, $typename);
423 279 50       649 if(my $basename = $node->getAttribute('base'))
424 279         3123 { $typename = $self->rel2abs($where, $node, $basename);
425 279   66     781 $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       1319 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     1258 , $in_list || $base->{is_list}, $typename);
454              
455 279 50       978 $tree->currentChild
456             and error __x"elements left at tail at {where}"
457             , where => $tree->path, _class => 'schema';
458              
459 279         1039 +{ 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 585 { my ($self, $tree, $st, $is_list, $type) = @_;
472 287         420 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         633 my $where = $tree->path . '#facet';
481 287         503 my (%facets, $is_qname);
482 287         592 for(my $child = $tree->currentChild; $child; $child = $tree->nextChild)
483 280         1811 { my $facet = $child->localName;
484 280 100       1453 last if $facet =~ $attribute_defs;
485              
486 272         666 my $value = $child->getAttribute('value');
487 272 50       2786 defined $value
488             or error __x"no value for facet `{facet}' at {where}"
489             , facet => $facet, where => $where, _class => 'schema';
490              
491 272 100       848 if($facet eq 'enumeration')
    100          
    50          
492 88 100       287 { $is_qname = $nss->doesExtend($type, $qname_type)
493             unless defined $is_qname;
494              
495 88 100       167 if($is_qname)
496             { # rewrite prefixed values into "{ns}local"
497 10 50       43 my ($prefix, $local)
498             = $value =~ m/\:/ ? split(/\:/, $value, 2) : ('', $value);
499 10         35 my $ns = $child->lookupNamespaceURI($prefix);
500 10         22 $value = pack_type $ns, $local;
501 10         22 $self->_registerNSprefix($prefix, $ns, 1);
502             }
503              
504 88         109 push @{$facets{enumeration}}, $value;
  88         348  
505             }
506 30         40 elsif($facet eq 'pattern') { push @{$facets{pattern}}, $value }
  30         121  
507 154         605 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     1368 if $self->{ignore_facets} || !keys %facets;
516              
517 210         760 my %facets_info = %facets;
518              
519             #
520             # new facets overrule all of the base-class
521             #
522              
523 210 100 100     583 if(defined $facets{totalDigits} && defined $facets{fractionDigits})
524 3         7 { my $td = delete $facets{totalDigits};
525 3         5 my $fd = delete $facets{fractionDigits};
526 3         9 $facets{_totalFracDigits} = [$td, $fd];
527             }
528              
529 210         302 my (@early, @late);
530 210 100       622 my $action = $self->actsAs('WRITER') ? 'WRITER' : 'READER';
531 210         533 foreach my $facet (keys %facets)
532             { my $h = builtin_facet($where, $self, $facet
533 243 100       793 , $facets{$facet}, $is_list, $type, $nss, $action) or next;
534              
535 241 100       622 if($facets_early{$facet})
536 34         77 { push @early, $h }
537 207         480 else { push @late, $h }
538             }
539              
540             $is_list
541 210 100       931 ? $self->makeFacetsList($where, $st, \%facets_info, \@early, \@late)
542             : $self->makeFacets($where, $st, \%facets_info, \@early, \@late);
543             }
544              
545             sub element($;$)
546 1880     1880 0 3376 { 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 1880         3816 my $node = $tree->node;
556 1880         6677 my $parent = $node->parentNode;
557 1880   100     4032 my $is_global= $parent
558             && $parent->isa('XML::LibXML::Element')
559             && $parent->localname eq 'schema';
560              
561 1880         20671 my $where = $tree->path;
562              
563 1880 50       4279 my $name = $node->getAttribute('name')
564             or error __x"element has no name nor ref at {where}"
565             , where => $where, _class => 'schema';
566 1880         21610 $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 1880         3609 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 1880         2384 my $abstract = 0;
577 1880         2506 my ($qual, $ns, $fullname);
578              
579 1880 100       3123 if($is_global)
580 860   66     1851 { $ns = $node->getAttribute('targetNamespace')
581             || $parent->getAttribute('targetNamespace');
582 860         16977 $fullname= pack_type $ns, $name;
583 860         2164 my $def = $self->namespaces->find(element => $fullname);
584 860         2061 $context = $self->nsContext($def);
585 860         1463 $qual = $context->{qual_top};
586              
587             # abstract elements are not to be used in messages.
588 860 50       2131 $abstract = $self->{abstract_types} eq 'ACCEPT' ? 0 : $def->{abstract};
589             }
590             else
591 1020         2064 { $qual = $context->{qual_elem};
592 1020   66     2259 $ns = $node->getAttribute('targetNamespace') || $context->{tns};
593 1020         12044 $fullname = pack_type $ns, $name;
594             }
595              
596 1880 100       4567 if(my $form = $node->getAttribute('form'))
597 8 50       80 { $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 1880 100       19277 local $self->{_context} = $context if $is_global;
605 1880 100       3352 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 1880         2288 my @sgs;
612 1880 100       4234 @sgs = $self->namespaces->findSgMembers($node->localName, $fullname)
613             unless $is_root;
614              
615             # Handle re-usable fragments, fight against combinatorial explosions
616              
617 1880         5036 my $nodeid = $node->unique_key; #$node->nodePath.'#'.$fullname;
618 1880 100       4806 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       30 $already = $self->substitutionGroup($tree, $fullname, $nodetype
622             , $already, \@sgs) if @sgs;
623 14         62 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 1866 100       3863 if(exists $self->{_nest}{$nodeid})
632 12         22 { my $outer = \$self->{_nest}{$nodeid};
633 12     13   53 my $nested = sub { $$outer->(@_) };
  13         48  
634              
635             # The code must be blessed in the right class, to be compiled
636             # correctly inside its parent.
637 12 50       26 bless $nested, 'BLOCK' if @sgs;
638              
639 12         68 return ($nodetype, $nested);
640             }
641 1854         4068 $self->{_nest}{$nodeid} = undef;
642              
643             # Construct XML tag to use
644              
645 1854 100       3299 my $trans = $qual ? 'makeTagQualified' : 'makeTagUnqualified';
646 1854         6149 my $tag = $self->$trans($where, $node, $name, $ns);
647              
648             # Construct type processor
649              
650 1854         2694 my ($comptype, $comps);
651 1854         5192 my $nr_childs = $tree->nrChildren;
652 1854 100       3870 if(my $isa = $node->getAttribute('type'))
    100          
    50          
653             { # explicitly names type
654 1347 50       13369 $nr_childs==0
655             or error __x"no childs expected with attribute `type' at {where}"
656             , where => $where, _class => 'schema';
657              
658 1347         3367 $comptype = $self->rel2abs($where, $node, $isa);
659 1347   66     3950 $comps = $self->blocked($where, anyType => $comptype)
660             || $self->typeByName($where, $tree, $comptype);
661             }
662             elsif($nr_childs==0)
663             { # default type for substGroups is type of base-class
664 17         167 my $base_node = $node;
665 17         38 local $self->{_context};
666 17         41 while(my $subst = $base_node->getAttribute('substitutionGroup'))
667 5         55 { my $subst_elem = $self->rel2abs($where, $base_node, $subst);
668 5         14 my $base_elem = $self->namespaces->find(element => $subst_elem);
669 5         14 $self->{_context} = $self->nsContext($base_elem);
670 5         19 $base_node = $base_elem->{node};
671 5 50       18 my $isa = $base_node->getAttribute('type')
672             or next;
673              
674 5         62 $comptype = $self->rel2abs($where, $base_node, $isa);
675 5   33     15 $comps = $self->blocked($where, complexType => $comptype)
676             || $self->typeByName($where, $tree, $comptype);
677 5         11 last;
678             }
679 17 100       146 unless($comptype)
680             { # no type found, so anyType
681 12         46 $comptype = $self->anyType($node);
682 12         42 $comps = $self->typeByName($where, $tree, $comptype);
683             }
684             }
685             elsif($nr_childs!=1)
686 0         0 { error __x"expected is only one child node at {where}"
687             , where => $where, _class => 'schema';
688             }
689             else # nameless types
690 490         6081 { my $child = $tree->firstChild;
691 490         1490 my $local = $child->localname;
692 490         1323 my $nest = $tree->descend($child);
693              
694 490 50       2491 ($comps, $comptype)
    100          
695             = $local eq 'simpleType'
696             ? ($self->simpleType($nest, 0), 'unnamed simple')
697             : $local eq 'complexType'
698             ? ($self->complexType($nest), 'unnamed complex')
699             : error __x"illegal element child `{name}' at {where}"
700             , name => $local, where => $where, _class => 'schema';
701             }
702              
703             my ($st, $elems, $attrs, $attrs_any)
704 1852         18168 = @$comps{ qw/st elems attrs attrs_any/ };
705 1852   100     11200 $_ ||= [] for $elems, $attrs, $attrs_any;
706              
707             # Construct basic element handler
708              
709 1852         2986 my $is_simple = defined $st;
710 1852   100     4740 my $nillable = $self->isTrue($node->getAttribute('nillable') || 'false');
711              
712             my $elem_handler
713 1852 100 66     8087 = $comps->{mixed} ? 'makeMixedElement'
    100          
    100          
714             : ! $is_simple ? 'makeComplexElement' # other complexType
715             : (@$attrs || @$attrs_any) ? 'makeTaggedElement' # complex/simpleContent
716             : 'makeSimpleElement';
717              
718 1852   66     7795 my $r = $self->$elem_handler
719             ( $where, $tag, ($st||$elems), $attrs, $attrs_any, $comptype, $nillable);
720              
721             # Add defaults and stuff
722 1852         7111 my $default = $node->getAttributeNode('default');
723 1852         4290 my $fixed = $node->getAttributeNode('fixed');
724              
725 1852 50 66     4336 $default && $fixed
726             and error __x"element can not have default and fixed at {where}"
727             , where => $tree->path, _class => 'schema';
728              
729 1852 100       4016 my $value
    100          
730             = $default ? $default->textContent
731             : $fixed ? $fixed->textContent
732             : undef;
733              
734 1852 100       4677 my $generate
    100          
    100          
735             = $abstract ? 'makeElementAbstract'
736             : $default ? 'makeElementDefault'
737             : $fixed ? 'makeElementFixed'
738             : 'makeElement';
739              
740 1852         5372 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 1852 50 33     4866 if $self->{permit_href} && $self->actsAs('READER');
745              
746             # Implement hooks
747 1852         4307 my ($before, $replace, $after)
748             = $self->findHooks($where, $comptype, $node);
749              
750 1852 100 100     8458 $do = $self->makeHook($where,$do,$tag,$before,$replace,$after,$comptype)
      100        
751             if $before || $replace || $after;
752              
753             $do = $self->xsiType($tree, $node, $name, $comptype, $do)
754 1852 100 66     6139 if $comptype && $self->{xsi_type}{$comptype};
755              
756             $do = $self->addTypeAttribute($comptype, $do)
757 1852 100 100     3878 if $self->{xsi_type_everywhere} && $comptype !~ /^unnamed /;
758              
759 1852         3542 $self->{_created}{$nodeid} = $do;
760              
761 1852 100       3516 $do = $self->substitutionGroup($tree, $fullname, $nodetype, $do, \@sgs)
762             if @sgs;
763              
764             # handle recursion
765             # this must look very silly to you... however, this is resolving
766             # recursive schemas: this way nested use of the same element
767             # definition will catch the code reference of the outer definition.
768 1852         2950 $self->{_nest}{$nodeid} = $do;
769 1852         3217 delete $self->{_nest}{$nodeid}; # clean the outer definition
770              
771 1852         12799 ($nodetype, $do);
772             }
773              
774             sub particle($)
775 1692     1692 0 2980 { my ($self, $tree) = @_;
776              
777 1692         3141 my $node = $tree->node;
778 1692         5774 my $local = $node->localName;
779 1692         3184 my $where = $tree->path;
780              
781 1692         3683 my $min = $node->getAttribute('minOccurs');
782 1692         16980 my $max = $node->getAttribute('maxOccurs');
783              
784 1692 100       13704 unless(defined $min)
785 1430 100 100     3490 { $min = ($self->actsAs('WRITER') || $self->{default_values} ne 'EXTEND')
786             && ($node->getAttribute('default') || $node->getAttribute('fixed'))
787             ? 0 : 1;
788             }
789              
790             $min = 0 if $self->{interpret_nillable_as_optional}
791 1692 100 100     14533 && $self->isTrue($node->getAttribute('nillable') || 'false');
      100        
792              
793             # default attribute in writer means optional, but we want to see
794             # them in the reader, to see the value.
795            
796 1692 100       3330 defined $max or $max = 1;
797             $max = 'unbounded'
798 1692 100 100     6036 if $max ne 'unbounded' && $max > 1 && !$self->{check_occurs};
      100        
799              
800             $min = 0
801 1692 100 100     3448 if $max eq 'unbounded' && !$self->{check_occurs};
802              
803 1692 100       2883 return $self->anyElement($tree, $min, $max)
804             if $local eq 'any';
805              
806 1682 50       9217 my ($label, $process)
    100          
    100          
807             = $local eq 'element' ? $self->particleElement($tree)
808             : $local eq 'group' ? $self->particleGroup($tree)
809             : $local =~ $particle_blocks ? $self->particleBlock($tree)
810             : error __x"unknown particle type '{name}' at {where}"
811             , name => $local, where => $tree->path, _class => 'schema';
812              
813 1682 100       20648 defined $label
814             or return ();
815              
816 1670 100       4012 if(ref $process eq 'BLOCK')
817 611         1302 { my $key = $self->keyRewrite($label);
818 611         1693 my $multi = $self->blockLabel($local, $key);
819 611         1950 return $self->makeBlockHandler($where, $label, $min, $max
820             , $process, $local, $multi);
821             }
822              
823             # only elements left
824 1059         1268 my $required;
825 1059         2527 my $key = $self->keyRewrite($label);
826 1059 100       3577 $required = $self->makeRequired($where, $key, $process) if $min!=0;
827              
828 1059 100       2410 ($self->actsAs('READER') ? $label : $key) =>
829             $self->makeElementHandler($where, $key, $min,$max, $required, $process);
830             }
831              
832             sub particleElement($)
833 1088     1088 0 1891 { my ($self, $tree) = @_;
834              
835 1088         2025 my $node = $tree->node;
836 1088 100       2392 if(my $ref = $node->getAttribute('ref'))
837 75         751 { my $where = $tree->path . "/$ref";
838 75         318 my $refname = $self->rel2abs($tree, $node, $ref);
839 75 100       251 return () if $self->blocked($where, ref => $refname);
840              
841 63 50       151 my $def = $self->namespaces->find(element => $refname)
842             or error __x"cannot find ref element '{name}' at {where}"
843             , name => $refname, where => $where, _class => 'schema';
844              
845             return $self->element($tree->descend($def->{node}
846 63         227 , $self->prefixed($refname, 1)));
847             }
848              
849 1013         9089 my $name = $node->getAttribute('name');
850 1013         8732 $self->element($tree->descend($node, $name));
851             }
852              
853             # blockLabel KIND, LABEL
854             # Particle blocks, like `sequence' and `choice', which have a maxOccurs
855             # (maximum occurrence) which is 2 of more, are represented by an ARRAY
856             # of HASHs. The label with such a block is derived from its first element.
857             # This function determines how.
858             # seq_address sequence get seq_ prepended
859             # cho_gender choices get cho_ before them
860             # all_money an all block can also be repreated in spec >1.1
861             # gr_people group refers to a block of above type, but
862             # that type is not reflected in the name
863              
864             my %block_abbrev = qw/sequence seq_ choice cho_ all all_ group gr_/;
865             sub blockLabel($$)
866 611     611 0 1222 { my ($self, $kind, $label) = @_;
867 611 100       1276 return $label if $kind eq 'element';
868              
869 594         1549 $label =~ s/^(?:seq|cho|all|gr)_//;
870 594         3648 $block_abbrev{$kind} . (unpack_type $label)[1];
871             }
872              
873             sub particleGroup($)
874 16     16 0 32 { my ($self, $tree) = @_;
875              
876             # attributes: id, maxOccurs, minOccurs, name, ref
877             # content: annotation?, (all|choice|sequence)?
878             # apparently, a group can not refer to a group... well..
879              
880 16         37 my $node = $tree->node;
881 16         33 my $where = $tree->path . '#group';
882 16 50       40 my $ref = $node->getAttribute('ref')
883             or error __x"group without ref at {where}"
884             , where => $where, _class => 'schema';
885              
886 16         178 my $typename = $self->rel2abs($where, $node, $ref);
887 16 50       53 if(my $blocked = $self->blocked($where, ref => $typename))
888 0         0 { return ($typename, $blocked);
889             }
890              
891 16 50       39 my $dest = $self->namespaces->find(group => $typename)
892             or error __x"cannot find group `{name}' at {where}"
893             , name => $typename, where => $where, _class => 'schema';
894              
895 16         53 my $group = $tree->descend($dest->{node}, $self->prefixed($typename, 1));
896 16 50       42 return () if $group->nrChildren==0;
897              
898 16 50       41 $group->nrChildren==1
899             or error __x"only one particle block expected in group `{name}' at {where}"
900             , name => $typename, where => $where, _class => 'schema';
901              
902 16         38 my $local = $group->currentLocal;
903 16 50       82 $local =~ m/^(?:all|choice|sequence)$/
904             or error __x"illegal group member `{name}' at {where}"
905             , name => $local, where => $where, _class => 'schema';
906              
907 16         40 my ($blocklabel, $code) = $self->particleBlock($group->descend);
908 16         58 ($typename, $code);
909             }
910              
911             sub particleBlock($)
912 594     594 0 1265 { my ($self, $tree) = @_;
913              
914 594         1421 my $node = $tree->node;
915 594         2298 my @pairs = map $self->particle($tree->descend($_)), $tree->childs;
916 594 50       2126 @pairs or return ();
917              
918             # label is name of first component, only needed when maxOcc > 1
919 594         990 my $label = $pairs[0];
920 594         2254 my $blocktype = $node->localName;
921              
922 594         2067 my $call = 'make'.ucfirst $blocktype;
923 594         1637 ($label => $self->$call($tree->path, @pairs));
924             }
925              
926             sub xsiType($$$$$)
927 7     7 0 19 { my ($self, $tree, $node, $name, $type, $base) = @_;
928              
929 7         20 my %alt = ($type => $base);
930              
931 7         10 foreach my $alttype (@{$self->{xsi_type}{$type}})
  7         24  
932 11 100       27 { next if $alttype eq $type;
933              
934 7         30 my ($ns, $local) = unpack_type $alttype;
935 7         55 my $prefix = $node->lookupNamespacePrefix($ns);
936 7 50       24 defined $prefix
937             or $prefix = $self->_registerNSprefix(undef, $ns, 1);
938              
939 7 50       30 my $type = length $prefix ? "$prefix:$local" : $local;
940              
941             # do not accidentally use the default namespace, when there
942             # may also be namespace-less types used.
943 7         45 my $doc = $node->ownerDocument;
944 7         51 my $altnode = $doc->createElement('element');
945 7         28 $altnode->setNamespace(SCHEMA2001, 'temp1234', 1);
946 7         154 $altnode->setNamespace($ns, $prefix);
947 7         98 $altnode->setAttribute(name => $name);
948 7         86 $altnode->setAttribute(type => $type);
949              
950 7         65 delete $self->{_created}{$altnode->unique_key}; # clean nesting cache
951 7         22 (undef, $alt{$alttype}) = $self->element($tree->descend($altnode));
952             }
953 7         121 $self->makeXsiTypeSwitch($tree->path, $name, $type, \%alt);
954             }
955              
956             sub substitutionGroup($$$$$)
957 19     19 0 52 { my ($self, $tree, $fullname, $label, $base, $sgs) = @_;
958              
959 19 50       82 if(Log::Report->needs('TRACE')) # dump table of substgroup alternatives
960 0         0 { my $labelrw = $self->keyRewrite($label);
961 0         0 my @full = sort map $_->{full}, @$sgs;
962 0         0 my $longest = max map length, @full;
963 0         0 my @c = map sprintf("%-${longest}s %s",$_,$self->keyRewrite($_)), @full;
964 0         0 local $" = "\n ";
965 0         0 trace "substitutionGroup $fullname$\"BASE=$label ($labelrw)$\"@c";
966             }
967              
968 19         317 my @elems;
969 19 50       77 push @elems, $label => [$self->keyRewrite($label), $base] if $base;
970              
971 19         42 foreach my $subst (@$sgs)
972 36         111 { my ($l, $d) = $self->element($tree->descend($subst->{node}), 1);
973 36 50       535 push @elems, $l => [$self->keyRewrite($l), $d] if defined $d;
974             }
975              
976 19         62 $self->makeSubstgroup($tree->path.'#subst', $fullname, @elems);
977             }
978              
979             sub keyRewrite($;$)
980 2067     2067 0 3107 { my $self = shift;
981 2067 100       6285 my ($ns, $key) = @_==1 ? unpack_type($_[0]) : @_;
982 2067         3172 my $oldkey = $key;
983              
984 2067         2344 foreach my $r ( @{$self->{rewrite}} )
  2067         4357  
985 115 100       390 { if(ref $r eq 'HASH')
    100          
    50          
    100          
    50          
    0          
986 14         35 { my $full = pack_type $ns, $key;
987 14 100       40 $key = $r->{$full} if defined $r->{$full};
988 14 50       34 $key = $r->{$key} if defined $r->{$key};
989             }
990             elsif(ref $r eq 'CODE')
991 51         120 { $key = $r->($ns, $key);
992             }
993             elsif($r eq 'UNDERSCORES')
994 0         0 { $key =~ s/-/_/g;
995             }
996             elsif($r eq 'SIMPLIFIED')
997 21         65 { $key =~ s/-/_/g;
998 21         51 $key =~ s/\W//g;
999 21         57 $key = lc $key;
1000             }
1001             elsif($r eq 'PREFIXED')
1002 29         42 { my $p = $self->{prefixes};
1003 29 100       76 my $prefix = $p->{$ns} ? $p->{$ns}{prefix} : '';
1004 29 100       90 $key = $prefix . '_' . $key if $prefix ne '';
1005             }
1006             elsif($r =~ m/^PREFIXED\(\s*(.*?)\s*\)$/)
1007 0         0 { my @l = split /\s*\,\s*/, $1;
1008 0         0 my $p = $self->{prefixes};
1009 0 0       0 my $prefix = $p->{$ns} ? $p->{$ns}{prefix} : '';
1010 0 0       0 $key = $prefix . '_' . $key if grep {$prefix eq $_} @l;
  0         0  
1011             }
1012             else
1013 0         0 { error __x"key rewrite `{got}' not understood", got => $r;
1014             }
1015             }
1016              
1017 2067 100       4456 trace "rewrote type @_ to $key"
1018             if $key ne $oldkey;
1019              
1020 2067         5786 $key;
1021             }
1022              
1023             sub prefixed($;$)
1024 988     988 0 1942 { my ($self, $qname, $hide) = @_;
1025 988         2950 my ($ns, $local) = unpack_type $qname;
1026 988 50       2735 defined $ns or return $qname;
1027              
1028 988 100       4528 my $pn = $self->{prefixes}{$ns} or return;
1029 261 100       586 $pn->{used}++ unless $hide ;
1030 261 100       1276 length $pn->{prefix} ? "$pn->{prefix}:$local" : $local;
1031             }
1032              
1033             sub prefixForNamespace($)
1034 8     8 0 13 { my ($self, $ns) = @_;
1035 8 50       21 my $def = $self->{prefixes}{$ns} or return;
1036 8         38 $def->{prefix};
1037             }
1038              
1039             sub attribute($)
1040 259     259 0 410 { my ($self, $tree) = @_;
1041              
1042             # attributes: default, fixed, form, id, name, ref, type, use
1043             # content: annotation?, simpleType?
1044              
1045 259         516 my $node = $tree->node;
1046 259         830 my $parent = $node->parentNode;
1047 259   66     506 my $is_global= $parent && $parent->localname eq 'schema';
1048 259         2088 my $where = $tree->path;
1049              
1050 259         426 my $context = $self->{_context};
1051              
1052 259 100       562 if(my $refattr = $node->getAttribute('ref'))
1053             {
1054 5         45 my $refname = $self->rel2abs($tree, $node, $refattr);
1055 5 50       13 return () if $self->blocked($where, ref => $refname);
1056              
1057 5 50       10 my $def = $self->namespaces->find(attribute => $refname)
1058             or error __x"cannot find attribute {name} at {where}"
1059             , name => $refname, where => $where, _class => 'schema';
1060              
1061 5         9 local $self->{_context} = $def;
1062 5         12 return $self->attribute($tree->descend($def->{node}));
1063             }
1064              
1065             # Not a ref to attribute
1066 254 50       2681 my $name = $node->getAttribute('name')
1067             or error __x"attribute without name at {where}", where => $where;
1068 254         2396 $where .= '/@'.$name;
1069 254         686 $self->assertType($where, name => NCName => $name);
1070              
1071 254         476 my ($qual, $ns, $fullname);
1072 254 100       483 if($is_global)
1073 13   33     23 { $ns = $node->getAttribute('targetNamespace')
1074             || $parent->getAttribute('targetNamespace');
1075 13         218 $fullname= pack_type $ns, $name;
1076 13         28 my $def = $self->namespaces->find(attribute => $fullname);
1077 13         26 $context = $self->nsContext($def);
1078 13         21 $qual = $context->{qual_top};
1079             }
1080             else
1081 241         415 { $qual = $context->{qual_attr};
1082 241         332 $ns = $context->{tns};
1083 241         662 $fullname= pack_type $ns, $name;
1084             }
1085 254 100       557 local $self->{_context} = $context if $is_global;
1086              
1087 254 50       565 if(my $form = $node->getAttribute('form'))
1088 0 0       0 { $qual
    0          
1089             = $form eq 'qualified' ? 1
1090             : $form eq 'unqualified' ? 0
1091             : error __x"form must be (un)qualified, not `{form}' at {where}"
1092             , form => $form, where => $where, _class => 'schema';
1093             }
1094              
1095             # no default prefixes for attributes
1096 254 50 66     2442 error __x"attribute namespace {ns} cannot be the default namespace"
      66        
1097             , ns => $ns
1098             if $qual && $ns && $self->prefixForNamespace($ns) eq '';
1099            
1100 254         352 my ($type, $typeattr);
1101 254 100       550 if($tree->nrChildren==1)
1102 7 50       12 { $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         15 $type = $self->simpleType($tree->descend);
1108             }
1109             else
1110 247 50       506 { $name = $node->getAttribute('name')
1111             or error __x"attribute without name or ref at {where}"
1112             , where => $where, _class => 'schema';
1113              
1114 247         2321 $typeattr = $node->getAttribute('type');
1115             }
1116              
1117 254 100       2094 unless($type)
1118 247 100       743 { my $typename = defined $typeattr
1119             ? $self->rel2abs($where, $node, $typeattr)
1120             : $self->anyType($node);
1121              
1122 247   66     642 $type = $self->blocked($where, simpleType => $typename)
1123             || $self->typeByName($where, $tree, $typename);
1124             }
1125              
1126             my $st = $type->{st}
1127 254 50       793 or error __x"attribute not based in simple value type at {where}"
1128             , where => $where, _class => 'schema';
1129              
1130 254 100       488 my $trans = $qual ? 'makeTagQualified' : 'makeTagUnqualified';
1131 254 100       447 my $qns = $qual ? $context->{tns} : '';
1132 254         729 my $tag = $self->$trans($where, $node, $name, $qns);
1133              
1134 254   100     674 my $use = $node->getAttribute('use') || '';
1135 254 50       3492 $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 254         879 my $default = $node->getAttributeNode('default');
1140 254         578 my $fixed = $node->getAttributeNode('fixed');
1141              
1142 254 100       886 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 254 100       421 my $value = defined $default ? $default : $fixed;
1150 254         2201 my $label = $self->keyRewrite($qns, $name);
1151 254         855 my $do = $self->$generate($where, $qns, $tag, $label, $st, $value);
1152 254 50       3097 defined $do ? ($label => $do) : ();
1153             }
1154              
1155             sub attributeGroup($)
1156 6     6 0 9 { my ($self, $tree) = @_;
1157              
1158             # attributes: id, ref = QName
1159             # content: annotation?
1160              
1161 6         10 my $node = $tree->node;
1162 6         9 my $where = $tree->path;
1163 6 50       9 my $ref = $node->getAttribute('ref')
1164             or error __x"attributeGroup use without ref at {where}"
1165             , where => $tree->path, _class => 'schema';
1166              
1167 6         55 my $typename = $self->rel2abs($where, $node, $ref);
1168 6 50       11 return () if $self->blocked($where, ref => $typename);
1169              
1170 6 50       13 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         18 local $self->{tns} = $def->{ns};
1175 6         13 $self->attributeList($tree->descend($def->{node}));
1176             }
1177              
1178             # Don't known how to handle notQName
1179             sub anyAttribute($)
1180 10     10 0 19 { 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         36 my $node = $tree->node;
1191 10         19 my $where = $tree->path . '@any';
1192              
1193 10         21 my $handler = $self->{any_attribute};
1194 10   50     21 my $namespace = $node->getAttribute('namespace') || '##any';
1195 10         128 my $not_ns = $node->getAttribute('notNamespace');
1196 10   50     92 my $process = $node->getAttribute('processContents') || 'strict';
1197              
1198 10 50 33     118 warn "HELP: please explain me how to handle notQName"
1199             if $^W && $node->getAttribute('notQName');
1200              
1201 10         30 my ($yes, $no) = $self->translateNsLimits($namespace, $not_ns);
1202 10         65 my $do = $self->makeAnyAttribute($where, $handler, $yes, $no, $process);
1203 10 100       40 defined $do ? $do : ();
1204             }
1205              
1206             sub anyElement($$$)
1207 10     10 0 25 { 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         23 my $node = $tree->node;
1218 10         29 my $where = $tree->path . '#any';
1219 10         29 my $handler = $self->{any_element};
1220              
1221 10   50     27 my $namespace = $node->getAttribute('namespace') || '##any';
1222 10         106 my $not_ns = $node->getAttribute('notNamespace');
1223 10   50     100 my $process = $node->getAttribute('processContents') || 'strict';
1224              
1225 10 50 33     126 info "HELP: please explain me how to handle notQName"
1226             if $^W && $node->getAttribute('notQName');
1227              
1228 10         32 my ($yes, $no) = $self->translateNsLimits($namespace, $not_ns);
1229 10         42 (any => $self->makeAnyElement($where, $handler, $yes, $no
1230             , $process, $min, $max));
1231             }
1232              
1233             sub translateNsLimits($$)
1234 20     20 0 43 { 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       57 return (undef, []) if $include eq '##any';
1241              
1242 12         36 my $tns = $self->{_context}{tns};
1243 12 100       32 return (undef, [$tns]) if $include eq '##other';
1244              
1245 8         17 my @return;
1246 8         16 foreach my $list ($include, $exclude)
1247 16         20 { my @list;
1248 16 100 66     49 if(defined $list && length $list)
1249 8         27 { foreach my $uri (split " ", $list)
1250 8 0       36 { push @list
    50          
1251             , $uri eq '##targetNamespace' ? $tns
1252             : $uri eq '##local' ? ()
1253             : $uri;
1254             }
1255             }
1256 16 100       51 push @return, @list ? \@list : undef;
1257             }
1258              
1259 8         25 @return;
1260             }
1261              
1262             sub complexType($)
1263 592     592 0 1075 { 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 592         1269 my $node = $tree->node;
1278 592   100     1396 my $mixed = $self->isTrue($node->getAttribute('mixed') || 'false');
1279             undef $mixed
1280 592 100       1687 if $self->{mixed_elements} eq 'STRUCTURAL';
1281              
1282 592 100       1288 my $first = $tree->firstChild
1283             or return {elems => [], mixed => $mixed};
1284              
1285 568         4635 my $name = $first->localName;
1286 568 100 100     5868 return $self->complexBody($tree, $mixed)
1287             if $name =~ $particle_blocks || $name =~ $attribute_defs;
1288              
1289 56 50       176 $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       203 return $self->simpleContent($tree->descend($first))
1294             if $name eq 'simpleContent';
1295              
1296 34 100       148 return $self->complexContent($tree->descend($first), $mixed)
1297             if $name eq 'complexContent';
1298              
1299 1         4 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 544     544 0 1796 { my ($self, $tree, $mixed) = @_;
1305              
1306 544 50       1396 $tree->currentChild
1307             or return ();
1308              
1309             # partial
1310             # (group|all|choice|sequence)?
1311             # , ((attribute|attributeGroup)*
1312             # , anyAttribute?
1313              
1314 544         2681 my @elems;
1315 544 100       1479 if($tree->currentLocal =~ $particle_blocks)
1316 512         1506 { push @elems, $self->particle($tree->descend); # unless $mixed;
1317 512         2089 $tree->nextChild;
1318             }
1319              
1320 544         1787 my @attrs = $self->attributeList($tree);
1321              
1322 544 50       1105 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 544         3988 {elems => \@elems, mixed => $mixed, @attrs};
1328             }
1329              
1330             sub attributeList($)
1331 572     572 0 1027 { my ($self, $tree) = @_;
1332              
1333             # partial content
1334             # ((attribute|attributeGroup)*
1335             # , anyAttribute?
1336              
1337 572         1181 my $where = $tree->path;
1338              
1339 572         889 my (@attrs, @any);
1340 572         1166 for(my $attr = $tree->currentChild; defined $attr; $attr = $tree->nextChild)
1341 262         899 { my $name = $attr->localName;
1342 262 100       588 if($name eq 'attribute')
    100          
1343 246         618 { push @attrs, $self->attribute($tree->descend);
1344             }
1345             elsif($name eq 'attributeGroup')
1346 6         10 { my %group = $self->attributeGroup($tree->descend);
1347 6         15 push @attrs, @{$group{attrs}};
  6         133  
1348 6         7 push @any, @{$group{attrs_any}};
  6         15  
1349             }
1350 10         20 else { last }
1351             }
1352              
1353             # officially only one: don't believe that
1354 572         1416 while($tree->currentLocal eq 'anyAttribute')
1355 10         29 { push @any, $self->anyAttribute($tree->descend);
1356 10         43 $tree->nextChild;
1357             }
1358              
1359 572         2054 (attrs => \@attrs, attrs_any => \@any);
1360             }
1361              
1362             sub simpleContent($)
1363 22     22 0 55 { my ($self, $tree) = @_;
1364              
1365             # attributes: id
1366             # content: annotation?, (restriction | extension)
1367              
1368 22 50       45 $tree->nrChildren==1
1369             or error __x"need one simpleContent child at {where}"
1370             , where => $tree->path, _class => 'schema';
1371              
1372 22         207 my $name = $tree->currentLocal;
1373 22 100       73 return $self->simpleContentExtension($tree->descend)
1374             if $name eq 'extension';
1375              
1376 8 50       27 return $self->simpleContentRestriction($tree->descend)
1377             if $name eq 'restriction';
1378              
1379 0         0 error __x"simpleContent needs extension or restriction, not `{name}' at {where}"
1380             , name => $name, where => $tree->path, _class => 'schema';
1381             }
1382              
1383             sub simpleContentExtension($)
1384 14     14 0 27 { my ($self, $tree) = @_;
1385              
1386             # attributes: id, base = QName
1387             # content: annotation?
1388             # , (attribute | attributeGroup)*
1389             # , anyAttribute?
1390             # , (assert | report)*
1391              
1392 14         29 my $node = $tree->node;
1393 14         31 my $where = $tree->path . '#sext';
1394              
1395 14         36 my $base = $node->getAttribute('base');
1396 14 50       166 my $typename = defined $base ? $self->rel2abs($where, $node, $base)
1397             : $self->anyType($node);
1398              
1399 14   33     46 my $basetype = $self->blocked($where, simpleType => $typename)
1400             || $self->typeByName($where, $tree, $typename);
1401             defined $basetype->{st}
1402 14 50       162 or error __x"base of simpleContent not simple at {where}"
1403             , where => $where, _class => 'schema';
1404            
1405 14         43 $self->extendAttrs($basetype, {$self->attributeList($tree)});
1406              
1407 14 50       48 $tree->currentChild
1408             and error __x"elements left at tail at {where}"
1409             , where => $tree->path, _class => 'schema';
1410              
1411 14         60 $basetype;
1412             }
1413              
1414             sub simpleContentRestriction($$)
1415 8     8 0 14 { my ($self, $tree) = @_;
1416              
1417             # attributes id, base = QName
1418             # content: annotation?
1419             # , (simpleType?, facet*)?
1420             # , (attribute | attributeGroup)*, anyAttribute?
1421             # , (assert | report)*
1422              
1423 8         18 my $node = $tree->node;
1424 8         15 my $where = $tree->path . '#cres';
1425              
1426 8         12 my ($type, $typename);
1427 8   50     17 my $first = $tree->currentLocal || '';
1428 8 100       26 if($first eq 'simpleType')
    50          
1429 4         14 { $type = $self->simpleType($tree->descend);
1430 4         39 $tree->nextChild;
1431             }
1432             elsif(my $basename = $node->getAttribute('base'))
1433 4         49 { $typename = $self->rel2abs($where, $node, $basename);
1434 4   33     15 $type = $self->blocked($where, simpleType => $type)
1435             || $self->typeByName($where, $tree, $typename);
1436             }
1437             else
1438 0         0 { error __x"no base in complex-restriction, so simpleType required at {where}"
1439             , where => $where, _class => 'schema';
1440             }
1441              
1442             my $st = $type->{st}
1443 8 50       28 or error __x"not a simpleType in simpleContent/restriction at {where}"
1444             , where => $where, _class => 'schema';
1445              
1446 8         31 $type->{st} = $self->applySimpleFacets($tree, $st, 0, $typename);
1447              
1448 8         31 $self->extendAttrs($type, {$self->attributeList($tree)});
1449              
1450 8 50       28 $tree->currentChild
1451             and error __x"elements left at tail at {where}"
1452             , where => $where, _class => 'schema';
1453              
1454 8         39 $type;
1455             }
1456              
1457             sub complexContent($$)
1458 33     33 0 117 { my ($self, $tree, $mixed) = @_;
1459              
1460             # attributes: id, mixed = boolean
1461             # content: annotation?, (restriction | extension)
1462              
1463 33         284 my $node = $tree->node;
1464 33 50       98 if(my $m = $node->getAttribute('mixed'))
1465             { $mixed = $self->isTrue($m)
1466 0 0       0 if $self->{mixed_elements} ne 'STRUCTURAL';
1467             }
1468              
1469 33 50       394 $tree->nrChildren == 1
1470             or error __x"only one complexContent child expected at {where}"
1471             , where => $tree->path, _class => 'schema';
1472              
1473 33         104 my $name = $tree->currentLocal;
1474 33 100 100     154 error __x"complexContent needs extension or restriction, not `{name}' at {where}"
1475             , name => $name, where => $tree->path, _class => 'schema'
1476             if $name ne 'extension' && $name ne 'restriction';
1477              
1478 32         82 $tree = $tree->descend;
1479 32         95 $node = $tree->node;
1480 32   33     86 my $base = $node->getAttribute('base') || $self->anyType($node);
1481 32         350 my $type = {};
1482 32         77 my $where = $tree->path . '#cce';
1483              
1484 32 50       195 if($base !~ m/\banyType$/)
1485 32         101 { my $typename = $self->rel2abs($where, $node, $base);
1486 32 100       115 if($type = $self->blocked($where, complexType => $typename))
1487             { # blocked base type
1488             }
1489             else
1490 28 50       72 { my $typedef = $self->namespaces->find(complexType => $typename)
1491             or error __x"unknown base type '{type}' at {where}"
1492             , type => $typename, where => $tree->path, _class => 'schema';
1493              
1494 28         85 local $self->{_context} = $self->nsContext($typedef);
1495 28         99 $type = $self->complexType($tree->descend($typedef->{node}));
1496             }
1497             }
1498              
1499 32         110 my $own = $self->complexBody($tree, $mixed);
1500 32         176 $self->extendAttrs($type, $own);
1501              
1502 32 100       84 if($name eq 'extension')
1503 28 50       39 { push @{$type->{elems}}, @{$own->{elems} || []};
  28         1764  
  28         129  
1504             }
1505             else # restriction
1506 4         38 { $type->{elems} = $own->{elems};
1507             }
1508              
1509 32   33     177 $type->{mixed} ||= $own->{mixed};
1510 32         163 $type;
1511             }
1512              
1513             #
1514             # Helper routines
1515             #
1516              
1517             # print $self->rel2abs($path, $node, '{ns}type') -> '{ns}type'
1518             # print $self->rel2abs($path, $node, 'prefix:type') -> '{ns-of-prefix}type'
1519              
1520             sub rel2abs($$$)
1521 2115     2115 0 4359 { my ($self, $where, $node, $type) = @_;
1522 2115 50       7033 return $type if substr($type, 0, 1) eq '{';
1523              
1524 2115 100       8862 my ($prefix, $local) = $type =~ m/^(.+?)\:(.*)/ ? ($1, $2) : ('', $type);
1525 2115         9208 my $uri = $node->lookupNamespaceURI($prefix);
1526 2115 100       6676 $self->_registerNSprefix($prefix, $uri, 0) if $uri;
1527              
1528 2115 50 66     5737 error __x"No namespace for prefix `{prefix}' in `{type}' at {where}"
1529             , prefix => $prefix, type => $type, where => $where, _class => 'schema'
1530             if length $prefix && !defined $uri;
1531              
1532 2115         5284 pack_type $uri, $local;
1533             }
1534              
1535             sub _registerNSprefix($$$)
1536 2353     2353   4189 { my ($self, $prefix, $uri, $used) = @_;
1537 2353         3362 my $table = $self->{prefixes};
1538              
1539 2353 100       5743 if(my $u = $table->{$uri}) # namespace already has a prefix
1540 1212         1857 { $u->{used} += $used;
1541 1212         2550 return $u->{prefix};
1542             }
1543              
1544 1141         6327 my %prefs = map +($_->{prefix} => 1), values %$table;
1545 1141         1854 my $take;
1546 1141 100 66     4810 if(defined $prefix && !$prefs{$prefix}) { $take = $prefix }
  724 50       1146  
1547 0         0 elsif(!$prefs{''}) { $take = '' }
1548             else
1549             { # prefix already in use; create a new x\d+ prefix
1550 417         664 my $count = 0;
1551 417         1361 $count++ while exists $prefs{"x$count"};
1552 417         664 $take = 'x'.$count;
1553             }
1554 1141         8031 $table->{$uri} = {prefix => $take, uri => $uri, used => $used};
1555 1141         2560 $take;
1556             }
1557              
1558             sub anyType($)
1559 15     15 0 35 { my ($self, $node) = @_;
1560 15         92 pack_type $node->namespaceURI, 'anyType';
1561             }
1562              
1563             sub findHooks($$$)
1564 1852     1852 0 3421 { my ($self, $path, $type, $node) = @_;
1565             # where is before, replace, after
1566              
1567 1852         2300 my %hooks;
1568 1852         2253 foreach my $hook (@{$self->{hooks}})
  1852         4196  
1569 61         81 { my $match;
1570              
1571             $match++
1572             if !$hook->{path} && !$hook->{id}
1573 61 0 100     259 && !$hook->{type} && !$hook->{extends};
      66        
      33        
1574              
1575 61 100 66     189 if(!$match && $hook->{path})
1576 8         10 { my $p = $hook->{path};
1577             $match++
1578 8 50   8   70 if first {ref $_ eq 'Regexp' ? $path =~ $_ : $path eq $_}
1579 8 50       50 ref $p eq 'ARRAY' ? @$p : $p;
    100          
1580             }
1581              
1582 61   100     234 my $id = !$match && $hook->{id} && $node->getAttribute('id');
1583 61 100       354 if($id)
1584 15         21 { my $i = $hook->{id};
1585             $match++
1586 15 50   15   54 if first {ref $_ eq 'Regexp' ? $id =~ $_ : $id eq $_}
1587 15 50       77 ref $i eq 'ARRAY' ? @$i : $i;
    100          
1588             }
1589              
1590 61 100 66     316 if(!$match && defined $type && $hook->{type})
      100        
1591 36         49 { my $t = $hook->{type};
1592 36         82 my ($ns, $local) = unpack_type $type;
1593             $match++
1594 36 100   36   177 if first {ref $_ eq 'Regexp' ? $type =~ $_
    50          
1595             : substr($_,0,1) eq '{' ? $type eq $_
1596             : $local eq $_
1597 36 50       212 } ref $t eq 'ARRAY' ? @$t : $t;
    100          
1598             }
1599              
1600 61 50 66     381 if(!$match && defined $type && $hook->{extends})
      66        
1601 0 0       0 { $match++ if $self->{nss}->doesExtend($type, $hook->{extends});
1602             }
1603              
1604 61 100       143 $match or next;
1605              
1606 23         47 foreach my $where ( qw/before replace after/ )
1607 69 100       143 { my $w = $hook->{$where} or next;
1608 29 100       37 push @{$hooks{$where}}, ref $w eq 'ARRAY' ? @$w : $w;
  29         117  
1609             }
1610             }
1611              
1612 1852         5029 @hooks{ qw/before replace after/ };
1613             }
1614              
1615             # Namespace blocks, in most cases because the schema refers to an
1616             # older version of itself, which is deprecated.
1617             # performance is important, because it is called increadably often.
1618              
1619             sub decodeBlocked($)
1620 771     771 0 1433 { my ($self, $what) = @_;
1621 771 50       1608 defined $what or return;
1622 771         1028 my @blocked; # code-refs called with ($type, $ns, $local, $path)
1623 771 50       2730 foreach my $w (ref $what eq 'ARRAY' ? @$what : $what)
1624             { push @blocked,
1625 86 50   86   329 !ref $w ? sub { $_[0] eq $w || $_[1] eq $w }
1626             : ref $w eq 'HASH'
1627 0 0   0   0 ? sub { defined $w->{$_[0]} ? $w->{$_[0]} : $w->{$_[1]} }
1628 30 0       167 : ref $what eq 'CODE' ? $w
    0          
    50          
1629             : error __x"blocking rule with {what} not supported", what => $w;
1630             }
1631 771         1812 \@blocked;
1632             }
1633              
1634             sub blocked($$$)
1635 2113     2113 0 4062 { my ($self, $path, $class, $type) = @_;
1636             # $class = simpleType, complexType, or ref
1637 2113 100       2547 @{$self->{blocked_nss}} or return ();
  2113         9836  
1638              
1639 86         173 my ($ns, $local) = unpack_type $type;
1640 86         145 my $is_blocked;
1641 86         97 foreach my $blocked ( @{$self->{blocked_nss}} )
  86         195  
1642 86         170 { $is_blocked = $blocked->($type, $ns, $local, $path);
1643 86 50       258 last if defined $is_blocked;
1644             }
1645 86 100       286 $is_blocked or return;
1646              
1647 38         183 trace "$type of $class is blocked";
1648 38         1177 $self->makeBlocked($path, $class, $type);
1649             }
1650              
1651             sub addTypeAttribute($$)
1652 0     0 0   { my ($self, $type, $call) = @_;
1653 0           $call;
1654             }
1655              
1656             #------------
1657              
1658             1;