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