author | joehw |
Mon, 13 Oct 2014 14:09:03 -0700 | |
changeset 27111 | 7a491d709b83 |
parent 25868 | 686eef1e7a79 |
child 33349 | 975138b77cff |
permissions | -rw-r--r-- |
12005 | 1 |
/* |
2 |
* reserved comment block |
|
3 |
* DO NOT REMOVE OR ALTER! |
|
4 |
*/ |
|
5 |
/* |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
6 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
7 |
* contributor license agreements. See the NOTICE file distributed with |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
8 |
* this work for additional information regarding copyright ownership. |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
9 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
10 |
* (the "License"); you may not use this file except in compliance with |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
11 |
* the License. You may obtain a copy of the License at |
12005 | 12 |
* |
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
14 |
* |
|
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
||
22 |
package com.sun.org.apache.xerces.internal.impl.xs; |
|
23 |
||
24 |
import com.sun.org.apache.xerces.internal.xs.XSConstants; |
|
25 |
import com.sun.org.apache.xerces.internal.xs.XSObjectList; |
|
26 |
import com.sun.org.apache.xerces.internal.xs.XSSimpleTypeDefinition; |
|
27 |
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; |
|
28 |
import com.sun.org.apache.xerces.internal.xni.QName; |
|
29 |
import java.util.Hashtable; |
|
30 |
import java.util.Vector; |
|
31 |
||
32 |
/** |
|
33 |
* To store and validate information about substitutionGroup |
|
34 |
* |
|
35 |
* @xerces.internal |
|
36 |
* |
|
37 |
* @author Sandy Gao, IBM |
|
38 |
* |
|
39 |
*/ |
|
40 |
public class SubstitutionGroupHandler { |
|
41 |
||
42 |
private static final XSElementDecl[] EMPTY_GROUP = new XSElementDecl[0]; |
|
43 |
||
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
44 |
// global element declaration resolver |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
45 |
private final XSElementDeclHelper fXSElementDeclHelper; |
12005 | 46 |
|
47 |
/** |
|
48 |
* Default constructor |
|
49 |
*/ |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
50 |
public SubstitutionGroupHandler(XSElementDeclHelper elementDeclHelper) { |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
51 |
fXSElementDeclHelper = elementDeclHelper; |
12005 | 52 |
} |
53 |
||
54 |
// 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3 |
|
55 |
// check whether one element decl matches an element with the given qname |
|
56 |
public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) { |
|
57 |
if (element.localpart == exemplar.fName && |
|
58 |
element.uri == exemplar.fTargetNamespace) { |
|
59 |
return exemplar; |
|
60 |
} |
|
61 |
||
62 |
// if the exemplar is not a global element decl, then it's not possible |
|
63 |
// to be substituted by another element. |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
64 |
if (exemplar.fScope != XSConstants.SCOPE_GLOBAL) { |
12005 | 65 |
return null; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
66 |
} |
12005 | 67 |
|
68 |
// if the decl blocks substitution, return false |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
69 |
if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) { |
12005 | 70 |
return null; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
71 |
} |
12005 | 72 |
|
73 |
// get the decl for the element |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
74 |
XSElementDecl eDecl = fXSElementDeclHelper.getGlobalElementDecl(element); |
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
75 |
if (eDecl == null) { |
12005 | 76 |
return null; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
77 |
} |
12005 | 78 |
|
79 |
// and check by using substitutionGroup information |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
80 |
if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock)) { |
12005 | 81 |
return eDecl; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
82 |
} |
12005 | 83 |
|
84 |
return null; |
|
85 |
} |
|
86 |
||
87 |
// 3.3.6 Substitution Group OK (Transitive) |
|
88 |
// check whether element can substitute exemplar |
|
89 |
protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) { |
|
90 |
// For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true: |
|
91 |
// 1. D and C are the same element declaration. |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
92 |
if (element == exemplar) { |
12005 | 93 |
return true; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
94 |
} |
12005 | 95 |
|
96 |
// 2 All of the following must be true: |
|
97 |
// 2.1 The blocking constraint does not contain substitution. |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
98 |
if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0) { |
12005 | 99 |
return false; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
100 |
} |
12005 | 101 |
|
102 |
// 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . . |
|
103 |
XSElementDecl subGroup = element.fSubGroup; |
|
104 |
while (subGroup != null && subGroup != exemplar) { |
|
105 |
subGroup = subGroup.fSubGroup; |
|
106 |
} |
|
107 |
||
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
108 |
if (subGroup == null) { |
12005 | 109 |
return false; |
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
110 |
} |
12005 | 111 |
|
112 |
// 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}. |
|
113 |
// prepare the combination of {derivation method} and |
|
114 |
// {disallowed substitution} |
|
115 |
return typeDerivationOK(element.fType, exemplar.fType, blockingConstraint); |
|
116 |
} |
|
27111
7a491d709b83
8036951: Xerces Update: XMLSchemaValidator.java and XMLSchemaLoader.java
joehw
parents:
25868
diff
changeset
|
117 |
|
12005 | 118 |
private boolean typeDerivationOK(XSTypeDefinition derived, XSTypeDefinition base, short blockingConstraint) { |
119 |
||
120 |
short devMethod = 0, blockConstraint = blockingConstraint; |
|
121 |
||
122 |
// "derived" should be derived from "base" |
|
123 |
// add derivation methods of derived types to devMethod; |
|
124 |
// add block of base types to blockConstraint. |
|
125 |
XSTypeDefinition type = derived; |
|
126 |
while (type != base && type != SchemaGrammar.fAnyType) { |
|
127 |
if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { |
|
128 |
devMethod |= ((XSComplexTypeDecl)type).fDerivedBy; |
|
129 |
} |
|
130 |
else { |
|
131 |
devMethod |= XSConstants.DERIVATION_RESTRICTION; |
|
132 |
} |
|
133 |
type = type.getBaseType(); |
|
134 |
// type == null means the current type is anySimpleType, |
|
135 |
// whose base type should be anyType |
|
136 |
if (type == null) { |
|
137 |
type = SchemaGrammar.fAnyType; |
|
138 |
} |
|
139 |
if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { |
|
140 |
blockConstraint |= ((XSComplexTypeDecl)type).fBlock; |
|
141 |
} |
|
142 |
} |
|
143 |
if (type != base) { |
|
144 |
// If the base is a union, check if "derived" is allowed through any of the member types. |
|
145 |
if (base.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { |
|
146 |
XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) base; |
|
147 |
if (st.getVariety() == XSSimpleTypeDefinition.VARIETY_UNION) { |
|
148 |
XSObjectList memberTypes = st.getMemberTypes(); |
|
149 |
final int length = memberTypes.getLength(); |
|
150 |
for (int i = 0; i < length; ++i) { |
|
151 |
if (typeDerivationOK(derived, (XSTypeDefinition) memberTypes.item(i), blockingConstraint)) { |
|
152 |
return true; |
|
153 |
} |
|
154 |
} |
|
155 |
} |
|
156 |
} |
|
157 |
return false; |
|
158 |
} |
|
159 |
if ((devMethod & blockConstraint) != 0) { |
|
160 |
return false; |
|
161 |
} |
|
162 |
return true; |
|
163 |
} |
|
164 |
||
165 |
// check whether element is in exemplar's substitution group |
|
166 |
public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) { |
|
167 |
// [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows: |
|
168 |
// Define PSG, the potential substitution group for HEAD, as follows: |
|
169 |
// 1 The element declaration itself is in PSG; |
|
170 |
// 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself. |
|
171 |
// HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true: |
|
172 |
// 1 Its {abstract} is false. |
|
173 |
// 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6). |
|
174 |
return substitutionGroupOK(element, exemplar, exemplar.fBlock); |
|
175 |
} |
|
176 |
||
177 |
// to store substitution group information |
|
178 |
// the key to the hashtable is an element decl, and the value is |
|
179 |
// - a Vector, which contains all elements that has this element as their |
|
180 |
// substitution group affilication |
|
181 |
// - an array of OneSubGroup, which contains its substitution group before block. |
|
182 |
Hashtable fSubGroupsB = new Hashtable(); |
|
183 |
private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0]; |
|
184 |
// The real substitution groups (after "block") |
|
185 |
Hashtable fSubGroups = new Hashtable(); |
|
186 |
||
187 |
/** |
|
188 |
* clear the internal registry of substitutionGroup information |
|
189 |
*/ |
|
190 |
public void reset() { |
|
191 |
fSubGroupsB.clear(); |
|
192 |
fSubGroups.clear(); |
|
193 |
} |
|
194 |
||
195 |
/** |
|
196 |
* add a list of substitution group information. |
|
197 |
*/ |
|
198 |
public void addSubstitutionGroup(XSElementDecl[] elements) { |
|
199 |
XSElementDecl subHead, element; |
|
200 |
Vector subGroup; |
|
201 |
// for all elements with substitution group affiliation |
|
202 |
for (int i = elements.length-1; i >= 0; i--) { |
|
203 |
element = elements[i]; |
|
204 |
subHead = element.fSubGroup; |
|
205 |
// check whether this an entry for this element |
|
206 |
subGroup = (Vector)fSubGroupsB.get(subHead); |
|
207 |
if (subGroup == null) { |
|
208 |
// if not, create a new one |
|
209 |
subGroup = new Vector(); |
|
210 |
fSubGroupsB.put(subHead, subGroup); |
|
211 |
} |
|
212 |
// add to the vactor |
|
213 |
subGroup.addElement(element); |
|
214 |
} |
|
215 |
} |
|
216 |
||
217 |
/** |
|
218 |
* get all elements that can substitute the given element, |
|
219 |
* according to the spec, we shouldn't consider the {block} constraints. |
|
220 |
* |
|
221 |
* from the spec, substitution group of a given element decl also contains |
|
222 |
* the element itself. but the array returned from this method doesn't |
|
223 |
* containt this element. |
|
224 |
*/ |
|
225 |
public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) { |
|
226 |
// If we already have sub group for this element, just return it. |
|
227 |
Object subGroup = fSubGroups.get(element); |
|
228 |
if (subGroup != null) |
|
229 |
return (XSElementDecl[])subGroup; |
|
230 |
||
231 |
if ((element.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) { |
|
232 |
fSubGroups.put(element, EMPTY_GROUP); |
|
233 |
return EMPTY_GROUP; |
|
234 |
} |
|
235 |
||
236 |
// Otherwise, get all potential sub group elements |
|
237 |
// (without considering "block" on this element |
|
238 |
OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup()); |
|
239 |
int len = groupB.length, rlen = 0; |
|
240 |
XSElementDecl[] ret = new XSElementDecl[len]; |
|
241 |
// For each of such elements, check whether the derivation methods |
|
242 |
// overlap with "block". If not, add it to the sub group |
|
243 |
for (int i = 0 ; i < len; i++) { |
|
244 |
if ((element.fBlock & groupB[i].dMethod) == 0) |
|
245 |
ret[rlen++] = groupB[i].sub; |
|
246 |
} |
|
247 |
// Resize the array if necessary |
|
248 |
if (rlen < len) { |
|
249 |
XSElementDecl[] ret1 = new XSElementDecl[rlen]; |
|
250 |
System.arraycopy(ret, 0, ret1, 0, rlen); |
|
251 |
ret = ret1; |
|
252 |
} |
|
253 |
// Store the subgroup |
|
254 |
fSubGroups.put(element, ret); |
|
255 |
||
256 |
return ret; |
|
257 |
} |
|
258 |
||
259 |
// Get potential sub group element (without considering "block") |
|
260 |
private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) { |
|
261 |
Object subGroup = fSubGroupsB.get(element); |
|
262 |
||
263 |
// substitution group for this one is empty |
|
264 |
if (subGroup == null) { |
|
265 |
fSubGroupsB.put(element, EMPTY_VECTOR); |
|
266 |
return EMPTY_VECTOR; |
|
267 |
} |
|
268 |
||
269 |
// we've already calculated the element, just return. |
|
270 |
if (subGroup instanceof OneSubGroup[]) |
|
271 |
return (OneSubGroup[])subGroup; |
|
272 |
||
273 |
// we only have the *direct* substitutions |
|
274 |
Vector group = (Vector)subGroup, newGroup = new Vector(); |
|
275 |
OneSubGroup[] group1; |
|
276 |
// then for each of the direct substitutions, get its substitution |
|
277 |
// group, and combine the groups together. |
|
278 |
short dMethod, bMethod, dSubMethod, bSubMethod; |
|
279 |
for (int i = group.size()-1, j; i >= 0; i--) { |
|
280 |
// Check whether this element is blocked. If so, ignore it. |
|
281 |
XSElementDecl sub = (XSElementDecl)group.elementAt(i); |
|
282 |
if (!getDBMethods(sub.fType, element.fType, methods)) |
|
283 |
continue; |
|
284 |
// Remember derivation methods and blocks from the types |
|
285 |
dMethod = methods.dMethod; |
|
286 |
bMethod = methods.bMethod; |
|
287 |
// Add this one to potential group |
|
288 |
newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod)); |
|
289 |
// Get potential group for this element |
|
290 |
group1 = getSubGroupB(sub, methods); |
|
291 |
for (j = group1.length-1; j >= 0; j--) { |
|
292 |
// For each of them, check whether it's blocked (by type) |
|
293 |
dSubMethod = (short)(dMethod | group1[j].dMethod); |
|
294 |
bSubMethod = (short)(bMethod | group1[j].bMethod); |
|
295 |
// Ignore it if it's blocked |
|
296 |
if ((dSubMethod & bSubMethod) != 0) |
|
297 |
continue; |
|
298 |
newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod)); |
|
299 |
} |
|
300 |
} |
|
301 |
// Convert to an array |
|
302 |
OneSubGroup[] ret = new OneSubGroup[newGroup.size()]; |
|
303 |
for (int i = newGroup.size()-1; i >= 0; i--) { |
|
304 |
ret[i] = (OneSubGroup)newGroup.elementAt(i); |
|
305 |
} |
|
306 |
// Store the potential sub group |
|
307 |
fSubGroupsB.put(element, ret); |
|
308 |
||
309 |
return ret; |
|
310 |
} |
|
311 |
||
312 |
private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb, |
|
313 |
OneSubGroup methods) { |
|
314 |
short dMethod = 0, bMethod = 0; |
|
315 |
while (typed != typeb && typed != SchemaGrammar.fAnyType) { |
|
316 |
if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) |
|
317 |
dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy; |
|
318 |
else |
|
319 |
dMethod |= XSConstants.DERIVATION_RESTRICTION; |
|
320 |
typed = typed.getBaseType(); |
|
321 |
// type == null means the current type is anySimpleType, |
|
322 |
// whose base type should be anyType |
|
323 |
if (typed == null) |
|
324 |
typed = SchemaGrammar.fAnyType; |
|
325 |
if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) |
|
326 |
bMethod |= ((XSComplexTypeDecl)typed).fBlock; |
|
327 |
} |
|
328 |
// No derivation relation, or blocked, return false |
|
329 |
if (typed != typeb || (dMethod & bMethod) != 0) |
|
330 |
return false; |
|
331 |
||
332 |
// Remember the derivation methods and blocks, return true. |
|
333 |
methods.dMethod = dMethod; |
|
334 |
methods.bMethod = bMethod; |
|
335 |
return true; |
|
336 |
} |
|
337 |
||
338 |
// Record the information about how one element substitute another one |
|
339 |
private static final class OneSubGroup { |
|
340 |
OneSubGroup() {} |
|
341 |
OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) { |
|
342 |
this.sub = sub; |
|
343 |
this.dMethod = dMethod; |
|
344 |
this.bMethod = bMethod; |
|
345 |
} |
|
346 |
// The element that substitutes another one |
|
347 |
XSElementDecl sub; |
|
348 |
// The combination of all derivation methods from sub's type to |
|
349 |
// the head's type |
|
350 |
short dMethod; |
|
351 |
// The combination of {block} of the types in the derivation chain |
|
352 |
// excluding sub's type |
|
353 |
short bMethod; |
|
354 |
} |
|
355 |
} // class SubstitutionGroupHandler |