| 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; |