|
|
|
|
|
*/ |
|
/* |
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
* contributor license agreements. See the NOTICE file distributed with |
|
* this work for additional information regarding copyright ownership. |
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
* (the "License"); you may not use this file except in compliance with |
|
* the License. You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
package com.sun.org.apache.xerces.internal.impl.xs; |
|
|
|
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; |
|
import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; |
|
import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo; |
|
import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext; |
|
import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; |
|
import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder; |
|
import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator; |
|
import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator; |
|
import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; |
|
import com.sun.org.apache.xerces.internal.util.SymbolHash; |
|
import com.sun.org.apache.xerces.internal.xs.XSConstants; |
|
import com.sun.org.apache.xerces.internal.xs.XSObjectList; |
|
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; |
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.Comparator; |
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class XSConstraints { |
|
|
|
// IHR: Visited on 2006-11-17 |
|
// Added a boolean return value to particleValidRestriction (it was a void function) |
|
// to help the checkRecurseLax to know when expansion has happened and no order is required |
|
// (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com) |
|
|
|
static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1; |
|
static final XSSimpleType STRING_TYPE = |
|
(XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING); |
|
|
|
private static XSParticleDecl fEmptyParticle = null; |
|
public static XSParticleDecl getEmptySequence() { |
|
if (fEmptyParticle == null) { |
|
XSModelGroupImpl group = new XSModelGroupImpl(); |
|
group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; |
|
group.fParticleCount = 0; |
|
group.fParticles = null; |
|
group.fAnnotations = XSObjectListImpl.EMPTY_LIST; |
|
XSParticleDecl particle = new XSParticleDecl(); |
|
particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; |
|
particle.fValue = group; |
|
particle.fAnnotations = XSObjectListImpl.EMPTY_LIST; |
|
fEmptyParticle = particle; |
|
} |
|
return fEmptyParticle; |
|
} |
|
|
|
private static final Comparator<XSParticleDecl> ELEMENT_PARTICLE_COMPARATOR = |
|
new Comparator<XSParticleDecl>() { |
|
|
|
public int compare(XSParticleDecl o1, XSParticleDecl o2) { |
|
XSParticleDecl pDecl1 = o1; |
|
XSParticleDecl pDecl2 = o2; |
|
XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue; |
|
XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue; |
|
|
|
String namespace1 = decl1.getNamespace(); |
|
String namespace2 = decl2.getNamespace(); |
|
String name1 = decl1.getName(); |
|
String name2 = decl2.getName(); |
|
|
|
boolean sameNamespace = (namespace1 == namespace2); |
|
int namespaceComparison = 0; |
|
|
|
if (!sameNamespace) { |
|
if (namespace1 != null) { |
|
if (namespace2 != null){ |
|
namespaceComparison = namespace1.compareTo(namespace2); |
|
} |
|
else { |
|
namespaceComparison = 1; |
|
} |
|
} |
|
else { |
|
namespaceComparison = -1; |
|
} |
|
} |
|
|
|
return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
*/ |
|
public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) { |
|
|
|
if (derived == SchemaGrammar.fAnyType) |
|
return derived == base; |
|
// if derived is anySimpleType, then it's valid only if the base |
|
|
|
if (derived == SchemaGrammar.fAnySimpleType) { |
|
return (base == SchemaGrammar.fAnyType || |
|
base == SchemaGrammar.fAnySimpleType); |
|
} |
|
|
|
|
|
if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { |
|
|
|
if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { |
|
// if base is anyType, change base to anySimpleType, |
|
|
|
if (base == SchemaGrammar.fAnyType) |
|
base = SchemaGrammar.fAnySimpleType; |
|
else |
|
return false; |
|
} |
|
return checkSimpleDerivation((XSSimpleType)derived, |
|
(XSSimpleType)base, block); |
|
} |
|
else { |
|
return checkComplexDerivation((XSComplexTypeDecl)derived, base, block); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) { |
|
// if derived is anySimpleType, then it's valid only if the base |
|
|
|
if (derived == SchemaGrammar.fAnySimpleType) { |
|
return (base == SchemaGrammar.fAnyType || |
|
base == SchemaGrammar.fAnySimpleType); |
|
} |
|
|
|
|
|
if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { |
|
// if base is anyType, change base to anySimpleType, |
|
|
|
if (base == SchemaGrammar.fAnyType) |
|
base = SchemaGrammar.fAnySimpleType; |
|
else |
|
return false; |
|
} |
|
return checkSimpleDerivation(derived, (XSSimpleType)base, block); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { |
|
|
|
if (derived == SchemaGrammar.fAnyType) |
|
return derived == base; |
|
return checkComplexDerivation(derived, base, block); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) { |
|
|
|
if (derived == base) |
|
return true; |
|
|
|
// 2 All of the following must be true: |
|
|
|
if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 || |
|
(derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) { |
|
return false; |
|
} |
|
|
|
// 2.2 One of the following must be true: |
|
|
|
XSSimpleType directBase = (XSSimpleType)derived.getBaseType(); |
|
if (directBase == base) |
|
return true; |
|
|
|
|
|
if (directBase != SchemaGrammar.fAnySimpleType && |
|
checkSimpleDerivation(directBase, base, block)) { |
|
return true; |
|
} |
|
|
|
|
|
if ((derived.getVariety() == XSSimpleType.VARIETY_LIST || |
|
derived.getVariety() == XSSimpleType.VARIETY_UNION) && |
|
base == SchemaGrammar.fAnySimpleType) { |
|
return true; |
|
} |
|
|
|
|
|
if (base.getVariety() == XSSimpleType.VARIETY_UNION) { |
|
XSObjectList subUnionMemberDV = base.getMemberTypes(); |
|
int subUnionSize = subUnionMemberDV.getLength(); |
|
for (int i=0; i<subUnionSize; i++) { |
|
base = (XSSimpleType)subUnionMemberDV.item(i); |
|
if (checkSimpleDerivation(derived, base, block)) |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean checkComplexDerivation(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { |
|
|
|
if (derived == base) |
|
return true; |
|
|
|
|
|
if ((derived.fDerivedBy & block) != 0) |
|
return false; |
|
|
|
|
|
XSTypeDefinition directBase = derived.fBaseType; |
|
|
|
if (directBase == base) |
|
return true; |
|
|
|
// 2.3 All of the following must be true: |
|
|
|
if (directBase == SchemaGrammar.fAnyType || |
|
directBase == SchemaGrammar.fAnySimpleType) { |
|
return false; |
|
} |
|
|
|
// 2.3.2 The appropriate case among the following must be true: |
|
|
|
if (directBase.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) |
|
return checkComplexDerivation((XSComplexTypeDecl)directBase, base, block); |
|
|
|
|
|
if (directBase.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { |
|
|
|
if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { |
|
// if base is anyType, change base to anySimpleType, |
|
|
|
if (base == SchemaGrammar.fAnyType) |
|
base = SchemaGrammar.fAnySimpleType; |
|
else |
|
return false; |
|
} |
|
return checkSimpleDerivation((XSSimpleType)directBase, |
|
(XSSimpleType)base, block); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static Object ElementDefaultValidImmediate(XSTypeDefinition type, String value, ValidationContext context, ValidatedInfo vinfo) { |
|
|
|
XSSimpleType dv = null; |
|
|
|
// e-props-correct |
|
// For a string to be a valid default with respect to a type definition the appropriate case among the following must be true: |
|
|
|
if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { |
|
dv = (XSSimpleType)type; |
|
} |
|
|
|
|
|
else { |
|
|
|
XSComplexTypeDecl ctype = (XSComplexTypeDecl)type; |
|
// 2.2 The appropriate case among the following must be true: |
|
|
|
if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { |
|
dv = ctype.fXSSimpleType; |
|
} |
|
|
|
else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { |
|
if (!((XSParticleDecl)ctype.getParticle()).emptiable()) |
|
return null; |
|
} |
|
else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
Object actualValue = null; |
|
if (dv == null) { |
|
// complex type with mixed. to make sure that we store correct |
|
// information in vinfo and return the correct value, we use |
|
|
|
dv = STRING_TYPE; |
|
} |
|
try { |
|
|
|
actualValue = dv.validate(value, context, vinfo); |
|
|
|
if (vinfo != null) |
|
actualValue = dv.validate(vinfo.stringValue(), context, vinfo); |
|
} catch (InvalidDatatypeValueException ide) { |
|
return null; |
|
} |
|
|
|
return actualValue; |
|
} |
|
|
|
static void reportSchemaError(XMLErrorReporter errorReporter, |
|
SimpleLocator loc, |
|
String key, Object[] args) { |
|
if (loc != null) { |
|
errorReporter.reportError(loc, XSMessageFormatter.SCHEMA_DOMAIN, |
|
key, args, XMLErrorReporter.SEVERITY_ERROR); |
|
} |
|
else { |
|
errorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, |
|
key, args, XMLErrorReporter.SEVERITY_ERROR); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void fullSchemaChecking(XSGrammarBucket grammarBucket, |
|
SubstitutionGroupHandler SGHandler, |
|
CMBuilder cmBuilder, |
|
XMLErrorReporter errorReporter) { |
|
// get all grammars, and put all substitution group information |
|
|
|
SchemaGrammar[] grammars = grammarBucket.getGrammars(); |
|
for (int i = grammars.length-1; i >= 0; i--) { |
|
SGHandler.addSubstitutionGroup(grammars[i].getSubstitutionGroups()); |
|
} |
|
|
|
XSParticleDecl fakeDerived = new XSParticleDecl(); |
|
XSParticleDecl fakeBase = new XSParticleDecl(); |
|
fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP; |
|
fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP; |
|
// before worrying about complexTypes, let's get |
|
|
|
for (int g = grammars.length-1; g >= 0; g--) { |
|
XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls(); |
|
SimpleLocator [] rgLocators = grammars[g].getRGLocators(); |
|
for(int i=0; i<redefinedGroups.length; ) { |
|
XSGroupDecl derivedGrp = redefinedGroups[i++]; |
|
XSModelGroupImpl derivedMG = derivedGrp.fModelGroup; |
|
XSGroupDecl baseGrp = redefinedGroups[i++]; |
|
XSModelGroupImpl baseMG = baseGrp.fModelGroup; |
|
fakeDerived.fValue = derivedMG; |
|
fakeBase.fValue = baseMG; |
|
if(baseMG == null) { |
|
if(derivedMG != null) { |
|
reportSchemaError(errorReporter, rgLocators[i/2-1], |
|
"src-redefine.6.2.2", |
|
new Object[]{derivedGrp.fName, "rcase-Recurse.2"}); |
|
} |
|
} else if (derivedMG == null) { |
|
if (!fakeBase.emptiable()) { |
|
reportSchemaError(errorReporter, rgLocators[i/2-1], |
|
"src-redefine.6.2.2", |
|
new Object[]{derivedGrp.fName, "rcase-Recurse.2"}); |
|
} |
|
} else { |
|
try { |
|
particleValidRestriction(fakeDerived, SGHandler, fakeBase, SGHandler); |
|
} catch (XMLSchemaException e) { |
|
String key = e.getKey(); |
|
reportSchemaError(errorReporter, rgLocators[i/2-1], |
|
key, |
|
e.getArgs()); |
|
reportSchemaError(errorReporter, rgLocators[i/2-1], |
|
"src-redefine.6.2.2", |
|
new Object[]{derivedGrp.fName, key}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// for each complex type, check the 3 constraints. |
|
|
|
XSComplexTypeDecl[] types; |
|
SimpleLocator [] ctLocators; |
|
// to hold the errors |
|
// REVISIT: do we want to report all errors? or just one? |
|
//XMLSchemaError1D errors = new XMLSchemaError1D(); |
|
// whether need to check this type again; |
|
|
|
boolean further, fullChecked; |
|
|
|
int keepType; |
|
// i: grammar; j: type; k: error |
|
|
|
SymbolHash elemTable = new SymbolHash(); |
|
for (int i = grammars.length-1, j; i >= 0; i--) { |
|
|
|
keepType = 0; |
|
fullChecked = grammars[i].fFullChecked; |
|
types = grammars[i].getUncheckedComplexTypeDecls(); |
|
ctLocators = grammars[i].getUncheckedCTLocators(); |
|
|
|
for (j = 0; j < types.length; j++) { |
|
// if we've already full-checked this grammar, then |
|
|
|
if (!fullChecked) { |
|
|
|
if (types[j].fParticle!=null) { |
|
elemTable.clear(); |
|
try { |
|
checkElementDeclsConsistent(types[j], types[j].fParticle, |
|
elemTable, SGHandler); |
|
} |
|
catch (XMLSchemaException e) { |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
e.getKey(), |
|
e.getArgs()); |
|
} |
|
} |
|
} |
|
|
|
// 2. Particle Derivation |
|
|
|
if (types[j].fBaseType != null && |
|
types[j].fBaseType != SchemaGrammar.fAnyType && |
|
types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION && |
|
(types[j].fBaseType instanceof XSComplexTypeDecl)) { |
|
|
|
XSParticleDecl derivedParticle=types[j].fParticle; |
|
XSParticleDecl baseParticle= |
|
((XSComplexTypeDecl)(types[j].fBaseType)).fParticle; |
|
if (derivedParticle==null) { |
|
if (baseParticle!=null && !baseParticle.emptiable()) { |
|
reportSchemaError(errorReporter,ctLocators[j], |
|
"derivation-ok-restriction.5.3.2", |
|
new Object[]{types[j].fName, types[j].fBaseType.getName()}); |
|
} |
|
} |
|
else if (baseParticle!=null) { |
|
try { |
|
particleValidRestriction(types[j].fParticle, |
|
SGHandler, |
|
((XSComplexTypeDecl)(types[j].fBaseType)).fParticle, |
|
SGHandler); |
|
} catch (XMLSchemaException e) { |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
e.getKey(), |
|
e.getArgs()); |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
"derivation-ok-restriction.5.4.2", |
|
new Object[]{types[j].fName}); |
|
} |
|
} |
|
else { |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
"derivation-ok-restriction.5.4.2", |
|
new Object[]{types[j].fName}); |
|
} |
|
} |
|
// 3. UPA |
|
|
|
XSCMValidator cm = types[j].getContentModel(cmBuilder, true); |
|
further = false; |
|
if (cm != null) { |
|
try { |
|
further = cm.checkUniqueParticleAttribution(SGHandler); |
|
} catch (XMLSchemaException e) { |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
e.getKey(), |
|
e.getArgs()); |
|
} |
|
} |
|
// now report all errors |
|
// REVISIT: do we want to report all errors? or just one? |
|
/*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) { |
|
reportSchemaError(errorReporter, ctLocators[j], |
|
errors.getErrorCode(k), |
|
errors.getArgs(k)); |
|
}*/ |
|
|
|
// if we are doing all checkings, and this one needs further |
|
|
|
if (!fullChecked && further) |
|
types[keepType++] = types[j]; |
|
|
|
// clear errors for the next type. |
|
// REVISIT: do we want to report all errors? or just one? |
|
//errors.clear(); |
|
} |
|
// we've done with the types in this grammar. if we are checking |
|
// all constraints, need to trim type array to a proper size: |
|
// only contain those need further checking. |
|
|
|
if (!fullChecked) { |
|
grammars[i].setUncheckedTypeNum(keepType); |
|
grammars[i].fFullChecked = true; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
Check that a given particle is a valid restriction of a base particle. |
|
*/ |
|
|
|
public static void checkElementDeclsConsistent(XSComplexTypeDecl type, |
|
XSParticleDecl particle, |
|
SymbolHash elemDeclHash, |
|
SubstitutionGroupHandler sgHandler) |
|
throws XMLSchemaException { |
|
|
|
// check for elements in the tree with the same name and namespace |
|
|
|
int pType = particle.fType; |
|
|
|
if (pType == XSParticleDecl.PARTICLE_WILDCARD) |
|
return; |
|
|
|
if (pType == XSParticleDecl.PARTICLE_ELEMENT) { |
|
XSElementDecl elem = (XSElementDecl)(particle.fValue); |
|
findElemInTable(type, elem, elemDeclHash); |
|
|
|
if (elem.fScope == XSConstants.SCOPE_GLOBAL) { |
|
|
|
XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem); |
|
for (int i = 0; i < subGroup.length; i++) { |
|
findElemInTable(type, subGroup[i], elemDeclHash); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; |
|
for (int i = 0; i < group.fParticleCount; i++) |
|
checkElementDeclsConsistent(type, group.fParticles[i], elemDeclHash, sgHandler); |
|
} |
|
|
|
public static void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem, |
|
SymbolHash elemDeclHash) |
|
throws XMLSchemaException { |
|
|
|
|
|
String name = elem.fName + "," + elem.fTargetNamespace; |
|
|
|
XSElementDecl existingElem = null; |
|
if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) { |
|
|
|
elemDeclHash.put(name, elem); |
|
} |
|
else { |
|
|
|
if (elem == existingElem) |
|
return; |
|
|
|
if (elem.fType != existingElem.fType) { |
|
|
|
throw new XMLSchemaException("cos-element-consistent", |
|
new Object[] {type.fName, elem.fName}); |
|
|
|
} |
|
} |
|
} |
|
|
|
// Check that a given particle is a valid restriction of a base particle. |
|
// |
|
// IHR: 2006/11/17 |
|
// Returns a boolean indicating if there has been expansion of substitution group |
|
// in the bParticle. |
|
// With this information the checkRecurseLax function knows when is |
|
|
|
private static boolean particleValidRestriction(XSParticleDecl dParticle, |
|
SubstitutionGroupHandler dSGHandler, |
|
XSParticleDecl bParticle, |
|
SubstitutionGroupHandler bSGHandler) |
|
throws XMLSchemaException { |
|
return particleValidRestriction(dParticle, dSGHandler, bParticle, bSGHandler, true); |
|
} |
|
|
|
private static boolean particleValidRestriction(XSParticleDecl dParticle, |
|
SubstitutionGroupHandler dSGHandler, |
|
XSParticleDecl bParticle, |
|
SubstitutionGroupHandler bSGHandler, |
|
boolean checkWCOccurrence) |
|
throws XMLSchemaException { |
|
|
|
List<XSParticleDecl> dChildren = null; |
|
List<XSParticleDecl> bChildren = null; |
|
int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN; |
|
int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN; |
|
|
|
|
|
boolean bExpansionHappened = false; |
|
|
|
// Check for empty particles. If either base or derived particle is empty, |
|
|
|
if (dParticle.isEmpty() && !bParticle.emptiable()) { |
|
throw new XMLSchemaException("cos-particle-restrict.a", null); |
|
} |
|
else if (!dParticle.isEmpty() && bParticle.isEmpty()) { |
|
throw new XMLSchemaException("cos-particle-restrict.b", null); |
|
} |
|
|
|
// |
|
// Do setup prior to invoking the Particle (Restriction) cases. |
|
// This involves: |
|
// - removing pointless occurrences for groups, and retrieving a vector of |
|
// non-pointless children |
|
// - turning top-level elements with substitution groups into CHOICE groups. |
|
// |
|
|
|
short dType = dParticle.fType; |
|
// |
|
// Handle pointless groups for the derived particle |
|
|
|
if (dType == XSParticleDecl.PARTICLE_MODELGROUP) { |
|
dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; |
|
|
|
// Find a group, starting with this particle, with more than 1 child. There |
|
// may be none, and the particle of interest trivially becomes an element or |
|
|
|
XSParticleDecl dtmp = getNonUnaryGroup(dParticle); |
|
if (dtmp != dParticle) { |
|
|
|
dParticle = dtmp; |
|
dType = dParticle.fType; |
|
if (dType == XSParticleDecl.PARTICLE_MODELGROUP) |
|
dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; |
|
} |
|
|
|
// Fill in a vector with the children of the particle, removing any |
|
|
|
dChildren = removePointlessChildren(dParticle); |
|
} |
|
|
|
int dMinOccurs = dParticle.fMinOccurs; |
|
int dMaxOccurs = dParticle.fMaxOccurs; |
|
|
|
// |
|
// For elements which are the heads of substitution groups, treat as CHOICE |
|
|
|
if (dSGHandler != null && dType == XSParticleDecl.PARTICLE_ELEMENT) { |
|
XSElementDecl dElement = (XSElementDecl)dParticle.fValue; |
|
|
|
if (dElement.fScope == XSConstants.SCOPE_GLOBAL) { |
|
// Check for subsitution groups. Treat any element that has a |
|
// subsitution group as a choice. Fill in the children vector with the |
|
|
|
XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement); |
|
if (subGroup.length >0 ) { |
|
// Now, set the type to be CHOICE. The "group" will have the same |
|
|
|
dType = XSModelGroupImpl.MODELGROUP_CHOICE; |
|
dMinEffectiveTotalRange = dMinOccurs; |
|
dMaxEffectiveTotalRange = dMaxOccurs; |
|
|
|
|
|
dChildren = new ArrayList<>(subGroup.length+1); |
|
for (int i = 0; i < subGroup.length; i++) { |
|
addElementToParticleVector(dChildren, subGroup[i]); |
|
} |
|
addElementToParticleVector(dChildren, dElement); |
|
Collections.sort(dChildren, ELEMENT_PARTICLE_COMPARATOR); |
|
|
|
// Set the handler to null, to indicate that we've finished handling |
|
|
|
dSGHandler = null; |
|
} |
|
} |
|
} |
|
|
|
short bType = bParticle.fType; |
|
// |
|
// Handle pointless groups for the base particle |
|
|
|
if (bType == XSParticleDecl.PARTICLE_MODELGROUP) { |
|
bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; |
|
|
|
// Find a group, starting with this particle, with more than 1 child. There |
|
// may be none, and the particle of interest trivially becomes an element or |
|
|
|
XSParticleDecl btmp = getNonUnaryGroup(bParticle); |
|
if (btmp != bParticle) { |
|
|
|
bParticle = btmp; |
|
bType = bParticle.fType; |
|
if (bType == XSParticleDecl.PARTICLE_MODELGROUP) |
|
bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; |
|
} |
|
|
|
// Fill in a vector with the children of the particle, removing any |
|
|
|
bChildren = removePointlessChildren(bParticle); |
|
} |
|
|
|
int bMinOccurs = bParticle.fMinOccurs; |
|
int bMaxOccurs = bParticle.fMaxOccurs; |
|
|
|
if (bSGHandler != null && bType == XSParticleDecl.PARTICLE_ELEMENT) { |
|
XSElementDecl bElement = (XSElementDecl)bParticle.fValue; |
|
|
|
if (bElement.fScope == XSConstants.SCOPE_GLOBAL) { |
|
// Check for subsitution groups. Treat any element that has a |
|
// subsitution group as a choice. Fill in the children vector with the |
|
|
|
XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement); |
|
if (bsubGroup.length >0 ) { |
|
|
|
bType = XSModelGroupImpl.MODELGROUP_CHOICE; |
|
|
|
bChildren = new ArrayList<>(bsubGroup.length+1); |
|
for (int i = 0; i < bsubGroup.length; i++) { |
|
addElementToParticleVector(bChildren, bsubGroup[i]); |
|
} |
|
addElementToParticleVector(bChildren, bElement); |
|
Collections.sort(bChildren, ELEMENT_PARTICLE_COMPARATOR); |
|
// Set the handler to null, to indicate that we've finished handling |
|
|
|
bSGHandler = null; |
|
|
|
|
|
bExpansionHappened = true; |
|
} |
|
} |
|
} |
|
|
|
// |
|
// O.K. - Figure out which particle derivation rule applies and call it |
|
|
|
switch (dType) { |
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
switch (bType) { |
|
|
|
|
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, |
|
(XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs); |
|
return bExpansionHappened; |
|
} |
|
|
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, |
|
(XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs, |
|
checkWCOccurrence); |
|
return bExpansionHappened; |
|
} |
|
|
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
{ |
|
// Treat the element as if it were in a group of the same type |
|
|
|
dChildren = new ArrayList<>(); |
|
dChildren.add(dParticle); |
|
|
|
checkRecurseLax(dChildren, 1, 1, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
{ |
|
// Treat the element as if it were in a group of the same type |
|
|
|
dChildren = new ArrayList<>(); |
|
dChildren.add(dParticle); |
|
|
|
checkRecurse(dChildren, 1, 1, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
default: |
|
{ |
|
throw new XMLSchemaException("Internal-Error", |
|
new Object[]{"in particleValidRestriction"}); |
|
} |
|
} |
|
} |
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
switch (bType) { |
|
|
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
checkNSSubset((XSWildcardDecl)dParticle.fValue, dMinOccurs, dMaxOccurs, |
|
(XSWildcardDecl)bParticle.fValue, bMinOccurs, bMaxOccurs); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
throw new XMLSchemaException("cos-particle-restrict.2", |
|
new Object[]{"any:choice,sequence,all,elt"}); |
|
} |
|
|
|
default: |
|
{ |
|
throw new XMLSchemaException("Internal-Error", |
|
new Object[]{"in particleValidRestriction"}); |
|
} |
|
} |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
{ |
|
switch (bType) { |
|
|
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); |
|
if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); |
|
|
|
checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, |
|
dMaxEffectiveTotalRange, |
|
dSGHandler, |
|
bParticle,bMinOccurs,bMaxOccurs, |
|
checkWCOccurrence); |
|
|
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
{ |
|
checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
throw new XMLSchemaException("cos-particle-restrict.2", |
|
new Object[]{"all:choice,sequence,elt"}); |
|
} |
|
|
|
default: |
|
{ |
|
throw new XMLSchemaException("Internal-Error", |
|
new Object[]{"in particleValidRestriction"}); |
|
} |
|
} |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
{ |
|
switch (bType) { |
|
|
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); |
|
if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); |
|
|
|
checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, |
|
dMaxEffectiveTotalRange, |
|
dSGHandler, |
|
bParticle,bMinOccurs,bMaxOccurs, |
|
checkWCOccurrence); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
{ |
|
checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
throw new XMLSchemaException("cos-particle-restrict.2", |
|
new Object[]{"choice:all,sequence,elt"}); |
|
} |
|
|
|
default: |
|
{ |
|
throw new XMLSchemaException("Internal-Error", |
|
new Object[]{"in particleValidRestriction"}); |
|
} |
|
} |
|
} |
|
|
|
|
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
{ |
|
switch (bType) { |
|
|
|
|
|
case XSParticleDecl.PARTICLE_WILDCARD: |
|
{ |
|
if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); |
|
if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) |
|
dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); |
|
|
|
checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, |
|
dMaxEffectiveTotalRange, |
|
dSGHandler, |
|
bParticle,bMinOccurs,bMaxOccurs, |
|
checkWCOccurrence); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_ALL: |
|
{ |
|
checkRecurseUnordered(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_SEQUENCE: |
|
{ |
|
checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSModelGroupImpl.MODELGROUP_CHOICE: |
|
{ |
|
int min1 = dMinOccurs * dChildren.size(); |
|
int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED)? |
|
dMaxOccurs : dMaxOccurs * dChildren.size(); |
|
checkMapAndSum(dChildren, min1, max1, dSGHandler, |
|
bChildren, bMinOccurs, bMaxOccurs, bSGHandler); |
|
return bExpansionHappened; |
|
} |
|
|
|
case XSParticleDecl.PARTICLE_ELEMENT: |
|
{ |
|
throw new XMLSchemaException("cos-particle-restrict.2", |
|
new Object[]{"seq:elt"}); |
|
} |
|
|
|
default: |
|
{ |
|
throw new XMLSchemaException("Internal-Error", |
|
new Object[]{"in particleValidRestriction"}); |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
return bExpansionHappened; |
|
} |
|
|
|
private static void addElementToParticleVector (List<XSParticleDecl> v, XSElementDecl d) { |
|
|
|
XSParticleDecl p = new XSParticleDecl(); |
|
p.fValue = d; |
|
p.fType = XSParticleDecl.PARTICLE_ELEMENT; |
|
v.add(p); |
|
|
|
} |
|
|
|
private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) { |
|
|
|
if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || |
|
p.fType == XSParticleDecl.PARTICLE_WILDCARD) |
|
return p; |
|
|
|
if (p.fMinOccurs==1 && p.fMaxOccurs==1 && |
|
p.fValue!=null && ((XSModelGroupImpl)p.fValue).fParticleCount == 1) |
|
return getNonUnaryGroup(((XSModelGroupImpl)p.fValue).fParticles[0]); |
|
else |
|
return p; |
|
} |
|
|
|
private static List<XSParticleDecl> removePointlessChildren(XSParticleDecl p) { |
|
|
|
if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || |
|
p.fType == XSParticleDecl.PARTICLE_WILDCARD) |
|
return null; |
|
|
|
List<XSParticleDecl> children = new ArrayList<>(); |
|
|
|
XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; |
|
for (int i = 0; i < group.fParticleCount; i++) |
|
gatherChildren(group.fCompositor, group.fParticles[i], children); |
|
|
|
return children; |
|
} |
|
|
|
|
|
private static void gatherChildren(int parentType, XSParticleDecl p, List<XSParticleDecl> children) { |
|
|
|
int min = p.fMinOccurs; |
|
int max = p.fMaxOccurs; |
|
int type = p.fType; |
|
if (type == XSParticleDecl.PARTICLE_MODELGROUP) |
|
type = ((XSModelGroupImpl)p.fValue).fCompositor; |
|
|
|
if (type == XSParticleDecl.PARTICLE_ELEMENT || |
|
type== XSParticleDecl.PARTICLE_WILDCARD) { |
|
children.add(p); |
|
return; |
|
} |
|
|
|
if (! (min==1 && max==1)) { |
|
children.add(p); |
|
} |
|
else if (parentType == type) { |
|
XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; |
|
for (int i = 0; i < group.fParticleCount; i++) |
|
gatherChildren(type, group.fParticles[i], children); |
|
} |
|
else if (!p.isEmpty()) { |
|
children.add(p); |
|
} |
|
|
|
} |
|
|
|
private static void checkNameAndTypeOK(XSElementDecl dElement, int dMin, int dMax, |
|
XSElementDecl bElement, int bMin, int bMax) |
|
throws XMLSchemaException { |
|
|
|
|
|
// |
|
// Check that the names are the same |
|
|
|
if (dElement.fName != bElement.fName || |
|
dElement.fTargetNamespace != bElement.fTargetNamespace) { |
|
throw new XMLSchemaException( |
|
"rcase-NameAndTypeOK.1",new Object[]{dElement.fName, |
|
dElement.fTargetNamespace, bElement.fName, bElement.fTargetNamespace}); |
|
} |
|
|
|
// |
|
// Check nillable |
|
|
|
if (!bElement.getNillable() && dElement.getNillable()) { |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.2", |
|
new Object[]{dElement.fName}); |
|
} |
|
|
|
// |
|
// Check occurrence range |
|
|
|
if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) { |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.3", |
|
new Object[]{ |
|
dElement.fName, |
|
Integer.toString(dMin), |
|
dMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(dMax), |
|
Integer.toString(bMin), |
|
bMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(bMax)}); |
|
} |
|
|
|
// |
|
// Check for consistent fixed values |
|
|
|
if (bElement.getConstraintType() == XSConstants.VC_FIXED) { |
|
|
|
if (dElement.getConstraintType() != XSConstants.VC_FIXED) { |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.4.a", |
|
new Object[]{dElement.fName, bElement.fDefault.stringValue()}); |
|
} |
|
|
|
|
|
boolean isSimple = false; |
|
if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE || |
|
((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { |
|
isSimple = true; |
|
} |
|
|
|
|
|
if (!isSimple && !bElement.fDefault.normalizedValue.equals(dElement.fDefault.normalizedValue) || |
|
isSimple && !bElement.fDefault.actualValue.equals(dElement.fDefault.actualValue)) { |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.4.b", |
|
new Object[]{dElement.fName, |
|
dElement.fDefault.stringValue(), |
|
bElement.fDefault.stringValue()}); |
|
} |
|
} |
|
|
|
// |
|
// Check identity constraints |
|
|
|
checkIDConstraintRestriction(dElement, bElement); |
|
|
|
// |
|
// Check for disallowed substitutions |
|
|
|
int blockSet1 = dElement.fBlock; |
|
int blockSet2 = bElement.fBlock; |
|
if (((blockSet1 & blockSet2)!=blockSet2) || |
|
(blockSet1==XSConstants.DERIVATION_NONE && blockSet2!=XSConstants.DERIVATION_NONE)) |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.6", |
|
new Object[]{dElement.fName}); |
|
|
|
|
|
// |
|
// Check that the derived element's type is derived from the base's. |
|
|
|
if (!checkTypeDerivationOk(dElement.fType, bElement.fType, |
|
(short)(XSConstants.DERIVATION_EXTENSION|XSConstants.DERIVATION_LIST|XSConstants.DERIVATION_UNION))) { |
|
throw new XMLSchemaException("rcase-NameAndTypeOK.7", |
|
new Object[]{dElement.fName, dElement.fType.getName(), bElement.fType.getName()}); |
|
} |
|
|
|
} |
|
|
|
|
|
private static void checkIDConstraintRestriction(XSElementDecl derivedElemDecl, |
|
XSElementDecl baseElemDecl) |
|
throws XMLSchemaException { |
|
// TODO |
|
} // checkIDConstraintRestriction |
|
|
|
|
|
private static boolean checkOccurrenceRange(int min1, int max1, int min2, int max2) { |
|
|
|
if ((min1 >= min2) && |
|
((max2==SchemaSymbols.OCCURRENCE_UNBOUNDED) || |
|
(max1!=SchemaSymbols.OCCURRENCE_UNBOUNDED && max1<=max2))) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
private static void checkNSCompat(XSElementDecl elem, int min1, int max1, |
|
XSWildcardDecl wildcard, int min2, int max2, |
|
boolean checkWCOccurrence) |
|
throws XMLSchemaException { |
|
|
|
|
|
if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-NSCompat.2", |
|
new Object[]{ |
|
elem.fName, |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
|
|
if (!wildcard.allowNamespace(elem.fTargetNamespace)) { |
|
throw new XMLSchemaException("rcase-NSCompat.1", |
|
new Object[]{elem.fName,elem.fTargetNamespace}); |
|
} |
|
|
|
} |
|
|
|
private static void checkNSSubset(XSWildcardDecl dWildcard, int min1, int max1, |
|
XSWildcardDecl bWildcard, int min2, int max2) |
|
throws XMLSchemaException { |
|
|
|
|
|
if (!checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-NSSubset.2", new Object[]{ |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
|
|
if (!dWildcard.isSubsetOf(bWildcard)) { |
|
throw new XMLSchemaException("rcase-NSSubset.1", null); |
|
} |
|
|
|
if (dWildcard.weakerProcessContents(bWildcard)) { |
|
throw new XMLSchemaException("rcase-NSSubset.3", |
|
new Object[]{dWildcard.getProcessContentsAsString(), |
|
bWildcard.getProcessContentsAsString()}); |
|
} |
|
|
|
} |
|
|
|
|
|
private static void checkNSRecurseCheckCardinality(List<XSParticleDecl> children, int min1, int max1, |
|
SubstitutionGroupHandler dSGHandler, |
|
XSParticleDecl wildcard, int min2, int max2, |
|
boolean checkWCOccurrence) |
|
throws XMLSchemaException { |
|
|
|
|
|
|
|
if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.2", new Object[]{ |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
|
|
int count = children.size(); |
|
try { |
|
for (int i = 0; i < count; i++) { |
|
XSParticleDecl particle1 = children.get(i); |
|
particleValidRestriction(particle1, dSGHandler, wildcard, null, false); |
|
|
|
} |
|
} |
|
// REVISIT: should we really just ignore original cause of this error? |
|
|
|
catch (XMLSchemaException e) { |
|
throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null); |
|
} |
|
|
|
} |
|
|
|
private static void checkRecurse(List<XSParticleDecl> dChildren, int min1, int max1, |
|
SubstitutionGroupHandler dSGHandler, |
|
List<XSParticleDecl> bChildren, int min2, int max2, |
|
SubstitutionGroupHandler bSGHandler) |
|
throws XMLSchemaException { |
|
|
|
|
|
if (!checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-Recurse.1", new Object[]{ |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
int count1= dChildren.size(); |
|
int count2= bChildren.size(); |
|
|
|
int current = 0; |
|
label: for (int i = 0; i<count1; i++) { |
|
|
|
XSParticleDecl particle1 = dChildren.get(i); |
|
for (int j = current; j<count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
current +=1; |
|
try { |
|
particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); |
|
continue label; |
|
} |
|
catch (XMLSchemaException e) { |
|
if (!particle2.emptiable()) |
|
throw new XMLSchemaException("rcase-Recurse.2", null); |
|
} |
|
} |
|
throw new XMLSchemaException("rcase-Recurse.2", null); |
|
} |
|
|
|
|
|
for (int j=current; j < count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
if (!particle2.emptiable()) { |
|
throw new XMLSchemaException("rcase-Recurse.2", null); |
|
} |
|
} |
|
|
|
} |
|
|
|
private static void checkRecurseUnordered(List<XSParticleDecl> dChildren, int min1, int max1, |
|
SubstitutionGroupHandler dSGHandler, |
|
List<XSParticleDecl> bChildren, int min2, int max2, |
|
SubstitutionGroupHandler bSGHandler) |
|
throws XMLSchemaException { |
|
|
|
|
|
|
|
if (!checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-RecurseUnordered.1", new Object[]{ |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
int count1= dChildren.size(); |
|
int count2 = bChildren.size(); |
|
|
|
boolean foundIt[] = new boolean[count2]; |
|
|
|
label: for (int i = 0; i<count1; i++) { |
|
XSParticleDecl particle1 = dChildren.get(i); |
|
|
|
for (int j = 0; j<count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
try { |
|
particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); |
|
if (foundIt[j]) |
|
throw new XMLSchemaException("rcase-RecurseUnordered.2", null); |
|
else |
|
foundIt[j]=true; |
|
|
|
continue label; |
|
} |
|
catch (XMLSchemaException e) { |
|
} |
|
} |
|
|
|
throw new XMLSchemaException("rcase-RecurseUnordered.2", null); |
|
} |
|
|
|
|
|
for (int j=0; j < count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
if (!foundIt[j] && !particle2.emptiable()) { |
|
throw new XMLSchemaException("rcase-RecurseUnordered.2", null); |
|
} |
|
} |
|
|
|
} |
|
|
|
private static void checkRecurseLax(List<XSParticleDecl> dChildren, int min1, int max1, |
|
SubstitutionGroupHandler dSGHandler, |
|
List<XSParticleDecl> bChildren, int min2, int max2, |
|
SubstitutionGroupHandler bSGHandler) |
|
throws XMLSchemaException { |
|
|
|
|
|
if (!checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-RecurseLax.1", new Object[]{ |
|
Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
int count1= dChildren.size(); |
|
int count2 = bChildren.size(); |
|
|
|
int current = 0; |
|
label: for (int i = 0; i<count1; i++) { |
|
|
|
XSParticleDecl particle1 = dChildren.get(i); |
|
for (int j = current; j<count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
current +=1; |
|
try { |
|
// IHR: go back one element on b list because the next element may match |
|
|
|
if (particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler)) |
|
current--; |
|
continue label; |
|
} |
|
catch (XMLSchemaException e) { |
|
} |
|
} |
|
|
|
throw new XMLSchemaException("rcase-RecurseLax.2", null); |
|
|
|
} |
|
|
|
} |
|
|
|
private static void checkMapAndSum(List<XSParticleDecl> dChildren, int min1, int max1, |
|
SubstitutionGroupHandler dSGHandler, |
|
List<XSParticleDecl> bChildren, int min2, int max2, |
|
SubstitutionGroupHandler bSGHandler) |
|
throws XMLSchemaException { |
|
|
|
// See if the sequence group is a valid restriction of the choice |
|
|
|
// Here is an example of a valid restriction: |
|
// <choice minOccurs="2"> |
|
// <a/> |
|
// <b/> |
|
// <c/> |
|
// </choice> |
|
// |
|
// <sequence> |
|
// <b/> |
|
// <a/> |
|
// </sequence> |
|
|
|
|
|
if (!checkOccurrenceRange(min1,max1,min2,max2)) { |
|
throw new XMLSchemaException("rcase-MapAndSum.2", |
|
new Object[]{Integer.toString(min1), |
|
max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), |
|
Integer.toString(min2), |
|
max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); |
|
} |
|
|
|
int count1 = dChildren.size(); |
|
int count2 = bChildren.size(); |
|
|
|
label: for (int i = 0; i<count1; i++) { |
|
|
|
XSParticleDecl particle1 = dChildren.get(i); |
|
for (int j = 0; j<count2; j++) { |
|
XSParticleDecl particle2 = bChildren.get(j); |
|
try { |
|
particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); |
|
continue label; |
|
} |
|
catch (XMLSchemaException e) { |
|
} |
|
} |
|
|
|
throw new XMLSchemaException("rcase-MapAndSum.1", null); |
|
} |
|
} |
|
|
|
public static boolean overlapUPA(XSElementDecl element1, |
|
XSElementDecl element2, |
|
SubstitutionGroupHandler sgHandler) { |
|
|
|
if (element1.fName == element2.fName && |
|
element1.fTargetNamespace == element2.fTargetNamespace) { |
|
return true; |
|
} |
|
|
|
// or if there is an element decl in element1's substitution group, |
|
|
|
XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element1); |
|
for (int i = subGroup.length-1; i >= 0; i--) { |
|
if (subGroup[i].fName == element2.fName && |
|
subGroup[i].fTargetNamespace == element2.fTargetNamespace) { |
|
return true; |
|
} |
|
} |
|
|
|
// or if there is an element decl in element2's substitution group, |
|
|
|
subGroup = sgHandler.getSubstitutionGroup(element2); |
|
for (int i = subGroup.length-1; i >= 0; i--) { |
|
if (subGroup[i].fName == element1.fName && |
|
subGroup[i].fTargetNamespace == element1.fTargetNamespace) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
// to check whether an element overlaps with a wildcard, |
|
|
|
public static boolean overlapUPA(XSElementDecl element, |
|
XSWildcardDecl wildcard, |
|
SubstitutionGroupHandler sgHandler) { |
|
|
|
if (wildcard.allowNamespace(element.fTargetNamespace)) |
|
return true; |
|
|
|
|
|
XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element); |
|
for (int i = subGroup.length-1; i >= 0; i--) { |
|
if (wildcard.allowNamespace(subGroup[i].fTargetNamespace)) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public static boolean overlapUPA(XSWildcardDecl wildcard1, |
|
XSWildcardDecl wildcard2) { |
|
|
|
XSWildcardDecl intersect = wildcard1.performIntersectionWith(wildcard2, wildcard1.fProcessContents); |
|
if (intersect == null || |
|
intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST || |
|
intersect.fNamespaceList.length != 0) { |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
public static boolean overlapUPA(Object decl1, Object decl2, |
|
SubstitutionGroupHandler sgHandler) { |
|
if (decl1 instanceof XSElementDecl) { |
|
if (decl2 instanceof XSElementDecl) { |
|
return overlapUPA((XSElementDecl)decl1, |
|
(XSElementDecl)decl2, |
|
sgHandler); |
|
} |
|
else { |
|
return overlapUPA((XSElementDecl)decl1, |
|
(XSWildcardDecl)decl2, |
|
sgHandler); |
|
} |
|
} |
|
else { |
|
if (decl2 instanceof XSElementDecl) { |
|
return overlapUPA((XSElementDecl)decl2, |
|
(XSWildcardDecl)decl1, |
|
sgHandler); |
|
} |
|
else { |
|
return overlapUPA((XSWildcardDecl)decl1, |
|
(XSWildcardDecl)decl2); |
|
} |
|
} |
|
} |
|
|
|
} // class XSContraints |