org.apache.xerces.impl.xs.XSConstraints Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xerces2-xsd11 Show documentation
Show all versions of xerces2-xsd11 Show documentation
A processor for parsing, validating, serializing and manipulating XML, written in Java
The newest version!
/*
* 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 org.apache.xerces.impl.xs;
import java.util.ArrayList;
import java.util.Stack;
import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.ValidationContext;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.xs.models.CMBuilder;
import org.apache.xerces.impl.xs.models.XSCMValidator;
import org.apache.xerces.impl.xs.util.SimpleLocator;
import org.apache.xerces.impl.xs.util.XSObjectListImpl;
import org.apache.xerces.util.SymbolHash;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSTypeDefinition;
/**
* Constraints shared by traversers and validator
*
* @xerces.internal
*
* @author Sandy Gao, IBM
*
* @version $Id$
*/
public abstract 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
// ([email protected]) ([email protected])
static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1;
// TODO: using 1.0 xs:string
static final XSSimpleType STRING_TYPE = (XSSimpleType)SchemaGrammar.getS4SGrammar(Constants.SCHEMA_VERSION_1_0).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;
}
static final XSConstraints XS_1_0_CONSTRAINTS = new XS10Constraints(Constants.SCHEMA_VERSION_1_0);
static final XSConstraints XS_1_0_CONSTRAINTS_EXTENDED = new XS10Constraints(Constants.SCHEMA_VERSION_1_0_EXTENDED);
static final XSConstraints XS_1_1_CONSTRAINTS = new XS11Constraints();
private final XSComplexTypeDecl fAnyType;
protected final short fSchemaVersion;
protected XSConstraints(XSComplexTypeDecl anyType, short schemaVersion) {
fAnyType = anyType;
fSchemaVersion = schemaVersion;
}
final public short getSchemaVersion() {
return fSchemaVersion;
}
public boolean isTypeTablesEquivalent(XSElementDecl elementDecl1, XSElementDecl elementDecl2) {
return true;
}
/**
* check whether derived is valid derived from base, given a subset
* of {restriction, extension}.B
*/
public boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) {
// if derived is anyType, then it's valid only if base is anyType too
if (derived == fAnyType)
return derived == base;
// if derived is anySimpleType, then it's valid only if the base
// is ur-type
if (derived == SchemaGrammar.fAnySimpleType) {
return (base == fAnyType ||
base == SchemaGrammar.fAnySimpleType);
}
// if derived is simple type
if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
// if base is complex type
if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
// if base is anyType, change base to anySimpleType,
// otherwise, not valid
if (base == fAnyType)
base = SchemaGrammar.fAnySimpleType;
else
return false;
}
return checkSimpleDerivation((XSSimpleType)derived,
(XSSimpleType)base, block);
}
else {
return checkComplexDerivation((XSComplexTypeDecl)derived, base, block);
}
}
/**
* check whether simple type derived is valid derived from base,
* given a subset of {restriction, extension}.
*/
public boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) {
// if derived is anySimpleType, then it's valid only if the base
// is ur-type
if (derived == SchemaGrammar.fAnySimpleType) {
return (base == fAnyType ||
base == SchemaGrammar.fAnySimpleType);
}
// if base is complex type
if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
// if base is anyType, change base to anySimpleType,
// otherwise, not valid
if (base == fAnyType)
base = SchemaGrammar.fAnySimpleType;
else
return false;
}
return checkSimpleDerivation((XSSimpleType)derived,
(XSSimpleType)base, block);
}
/**
* check whether complex type derived is valid derived from base,
* given a subset of {restriction, extension}.
*/
public boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) {
// if derived is anyType, then it's valid only if base is anyType too
if (derived == fAnyType)
return derived == base;
return checkComplexDerivation((XSComplexTypeDecl)derived, base, block);
}
/**
* Note: this will be a private method, and it assumes that derived is not
* anySimpleType, and base is not anyType. Another method will be
* introduced for public use, which will call this method.
*/
private boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) {
// 1 They are the same type definition.
if (derived == base)
return true;
// 2 All of the following must be true:
// 2.1 restriction is not in the subset, or in the {final} of its own {base type definition};
if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 ||
(derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) {
return false;
}
// 2.2 One of the following must be true:
// 2.2.1 D's base type definition is B.
XSSimpleType directBase = (XSSimpleType)derived.getBaseType();
if (directBase == base)
return true;
// 2.2.2 D's base type definition is not the simple ur-type definition and is validly derived from B given the subset, as defined by this constraint.
if (directBase != SchemaGrammar.fAnySimpleType &&
checkSimpleDerivation(directBase, base, block)) {
return true;
}
// 2.2.3 D's {variety} is list or union and B is the simple ur-type definition.
if ((derived.getVariety() == XSSimpleType.VARIETY_LIST ||
derived.getVariety() == XSSimpleType.VARIETY_UNION) &&
base == SchemaGrammar.fAnySimpleType) {
return true;
}
// 2.2.4 B's {variety} is union and D is validly derived from a type definition in B's {member type definitions} given the subset, as defined by this constraint.
if (base.getVariety() == XSSimpleType.VARIETY_UNION) {
if (checkEmptyFacets(base)) {
XSObjectList subUnionMemberDV = base.getMemberTypes();
int subUnionSize = subUnionMemberDV.getLength();
for (int i=0; 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
// groups redefined by restriction out of the way.
for (int g = grammars.length-1; g >= 0; g--) {
XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls();
SimpleLocator [] rgLocators = grammars[g].getRGLocators();
for(int i=0; i= 0; i--) {
// get whether to skip EDC, and types need to be checked
keepType = 0;
fullChecked = grammars[i].fFullChecked;
types = grammars[i].getUncheckedComplexTypeDecls();
ctLocators = grammars[i].getUncheckedCTLocators();
// for each type
for (j = 0; j < types.length; j++) {
// if we've already full-checked this grammar, then
// skip the EDC constraint
if (!fullChecked) {
// 1. Element Decl Consistent
if (types[j].fParticle!=null) {
elemTable.clear();
try {
checkElementDeclsConsistent(types[j], types[j].fParticle,
elemTable, SGHandler, grammarBucket,
wcList, stack);
}
catch (XMLSchemaException e) {
reportSchemaError(errorReporter, ctLocators[j],
e.getKey(),
e.getArgs());
}
}
}
// 2. Particle Derivation
if (types[j].fBaseType != null &&
types[j].fBaseType != fAnyType &&
types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION &&
(types[j].fBaseType instanceof XSComplexTypeDecl)) {
XSParticleDecl derivedParticle=types[j].fParticle;
XSComplexTypeDecl bType = (XSComplexTypeDecl)(types[j].fBaseType);
XSParticleDecl baseParticle= bType.fParticle;
// When there is open content, particle is never null.
// Open contents are handled in typeSubsumption().
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) {
typeSubsumption(types[j], bType, grammarBucket,
SGHandler, cmBuilder, errorReporter, ctLocators[j]);
}
else {
reportSchemaError(errorReporter, ctLocators[j],
"derivation-ok-restriction.5.4.2",
new Object[]{types[j].fName});
}
}
// 3. UPA
// get the content model and check UPA
XSCMValidator cm = types[j].getContentModel(cmBuilder, true);
further = false;
if (cm != null) {
try {
further = cm.checkUniqueParticleAttribution(SGHandler, this);
} 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
// checking, store it in the type array.
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.
// and mark this grammar that it only needs UPA checking.
if (!fullChecked) {
grammars[i].setUncheckedTypeNum(keepType);
grammars[i].fFullChecked = true;
}
}
}
/*
* Check that a given particle is a valid restriction of a base particle.
* NOTE: deprecated
*/
public 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) {
// Check for subsitution groups.
XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem, fSchemaVersion);
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);
}
protected void checkElementDeclsConsistent(XSComplexTypeDecl type,
XSParticleDecl particle,
SymbolHash elemDeclHash,
SubstitutionGroupHandler sgHandler,
XSGrammarBucket grammarBucket,
ArrayList wcList,
Stack stack) throws XMLSchemaException {
// check for elements in the tree with the same name and namespace
if (stack.size() > 0) {
stack.clear();
}
for (;;) {
final int pType = particle.fType;
if (pType == XSParticleDecl.PARTICLE_WILDCARD) {
// no op
}
else if (pType == XSParticleDecl.PARTICLE_ELEMENT) {
XSElementDecl elem = (XSElementDecl)(particle.fValue);
findElemInTable(type, elem, elemDeclHash);
if (elem.fScope == XSConstants.SCOPE_GLOBAL) {
// Check for subsitution groups.
XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem, fSchemaVersion);
for (int i = 0; i < subGroup.length; i++) {
findElemInTable(type, subGroup[i], elemDeclHash);
}
}
}
else {
XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue;
for (int i = group.fParticleCount - 1; i >= 0 ; i--)
stack.push(group.fParticles[i]);
}
if (stack.isEmpty()) {
break;
}
particle = (XSParticleDecl) stack.pop();
}
}
public void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem,
SymbolHash elemDeclHash)
throws XMLSchemaException {
final XSElementDecl existingElem = findExistingElement(elem, elemDeclHash);
// First time or is same element
if (existingElem == null || existingElem == elem) {
return;
}
if (elem.fType != existingElem.fType) {
// Types are not the same
throw new XMLSchemaException("cos-element-consistent", new Object[] {type.fName, elem.fName});
}
}
protected XSElementDecl findExistingElement(XSElementDecl elem, SymbolHash elemDeclHash) {
// How can we avoid this concat? LM.
String name = elem.fName + "," + elem.fTargetNamespace;
XSElementDecl existingElem = (XSElementDecl)(elemDeclHash.get(name));
if (existingElem == null) {
// just add it in
elemDeclHash.put(name, elem);
}
return existingElem;
}
// to check whether two element overlap, as defined in constraint UPA
protected boolean overlapUPA(XSElementDecl element1,
XSElementDecl element2,
SubstitutionGroupHandler sgHandler) {
// if the two element have the same name and namespace,
if (element1.fName == element2.fName &&
element1.fTargetNamespace == element2.fTargetNamespace) {
return true;
}
// or if there is an element decl in element1's substitution group,
// who has the same name/namespace with element2
XSElementDecl[] subGroup1 = sgHandler.getSubstitutionGroup(element1, fSchemaVersion);
for (int i = subGroup1.length-1; i >= 0; i--) {
if (subGroup1[i].fName == element2.fName &&
subGroup1[i].fTargetNamespace == element2.fTargetNamespace) {
return true;
}
}
// or if there is an element decl in element2's substitution group,
// who has the same name/namespace with element1
XSElementDecl[] subGroup2 = sgHandler.getSubstitutionGroup(element2, fSchemaVersion);
for (int i = subGroup2.length-1; i >= 0; i--) {
if (subGroup2[i].fName == element1.fName &&
subGroup2[i].fTargetNamespace == element1.fTargetNamespace) {
return true;
}
}
// or if the 2 substitution groups overlap.
for (int i = subGroup1.length-1; i >= 0; i--) {
for (int j = subGroup2.length-1; j >= 0; j--) {
if (subGroup1[i].fName == subGroup2[j].fName &&
subGroup1[i].fTargetNamespace == subGroup2[j].fTargetNamespace) {
return true;
}
}
}
return false;
}
public boolean overlapUPA(XSWildcardDecl wildcard1,
XSWildcardDecl wildcard2) {
// if the intersection of the two wildcards is not any and
// and the {namespaces} of such intersection is not the empty set
XSWildcardDecl intersect = performIntersectionWith(wildcard1, wildcard2, wildcard1.fProcessContents);
if (intersect == null ||
intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST ||
intersect.fNamespaceList.length != 0) {
return true;
}
return false;
}
// call one of the above methods according to the type of decls
public 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);
}
}
}
/**
* Wildcard constraints - helper methods
*/
boolean areSame(XSWildcardDecl wildcard, XSWildcardDecl otherWildcard) {
if (wildcard.fType == otherWildcard.fType) {
// ##any, true
if (wildcard.fType == XSWildcardDecl.NSCONSTRAINT_ANY) {
return true;
}
// ##other, only check the negated value
// * when we support not(list), we need to check in the same way
// as for NSCONSTRAINT_LIST.
// not(list) is supported - no need for that check
if (wildcard.fType == XSWildcardDecl.NSCONSTRAINT_NOT) {
return wildcard.fNamespaceList[0] == otherWildcard.fNamespaceList[0];
}
// ## list, must have the same length,
// and each item in one list must appear in the other one
// (we are assuming that there are no duplicate items in a list)
if (wildcard.fNamespaceList.length == otherWildcard.fNamespaceList.length) {
for (int i=0; i