/* * reserved comment block * DO NOT REMOVE OR ALTER! */ /* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed 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 java.util.Collections; import java.util.Comparator; import java.util.Vector; 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; /** * Constaints shared by traversers and validator * * @xerces.internal * * @author Sandy Gao, IBM * */ 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 ELEMENT_PARTICLE_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { XSParticleDecl pDecl1 = (XSParticleDecl) o1; XSParticleDecl pDecl2 = (XSParticleDecl) 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; } } //This assumes that the names are never null. return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2); } }; /** * check whether derived is valid derived from base, given a subset * of {restriction, extension}.B */ public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) { // if derived is anyType, then it's valid only if base is anyType too if (derived == SchemaGrammar.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 == SchemaGrammar.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 == SchemaGrammar.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 static 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 == SchemaGrammar.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 == SchemaGrammar.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 static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { // if derived is anyType, then it's valid only if base is anyType too if (derived == SchemaGrammar.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 static 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) { 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); } 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 // get the content model and check UPA XSCMValidator cm = types[j].getContentModel(cmBuilder); 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 // 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. */ 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) { // Check for subsitution groups. 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 { // How can we avoid this concat? LM. String name = elem.fName + "," + elem.fTargetNamespace; XSElementDecl existingElem = null; if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) { // just add it in elemDeclHash.put(name, elem); } else { // If this is the same check element, we're O.K. if (elem == existingElem) return; if (elem.fType != existingElem.fType) { // Types are not the same 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 // to keep the order and when to ignore it. 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 { Vector dChildren = null; Vector bChildren = null; int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN; int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN; // By default there has been no expansion boolean bExpansionHappened = false; // Check for empty particles. If either base or derived particle is empty, // (and the other isn't) it's an error. 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 // wildcard. XSParticleDecl dtmp = getNonUnaryGroup(dParticle); if (dtmp != dParticle) { // Particle has been replaced. Retrieve new type info. 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 // pointless model groups in the process. 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 // members of the substitution group XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement); if (subGroup.length >0 ) { // Now, set the type to be CHOICE. The "group" will have the same // occurrence information as the original particle. dType = XSModelGroupImpl.MODELGROUP_CHOICE; dMinEffectiveTotalRange = dMinOccurs; dMaxEffectiveTotalRange = dMaxOccurs; // Fill in the vector of children dChildren = new Vector(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 // substitution groups for this particle. 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 // wildcard. XSParticleDecl btmp = getNonUnaryGroup(bParticle); if (btmp != bParticle) { // Particle has been replaced. Retrieve new type info. 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 // pointless model groups in the process. 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 // members of the substitution group XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement); if (bsubGroup.length >0 ) { // Now, set the type to be CHOICE bType = XSModelGroupImpl.MODELGROUP_CHOICE; bChildren = new Vector(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 // substitution groups for this particle. bSGHandler = null; // if we are here expansion of bParticle happened bExpansionHappened = true; } } } // // O.K. - Figure out which particle derivation rule applies and call it // switch (dType) { case XSParticleDecl.PARTICLE_ELEMENT: { switch (bType) { // Elt:Elt NameAndTypeOK case XSParticleDecl.PARTICLE_ELEMENT: { checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, (XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs); return bExpansionHappened; } // Elt:Any NSCompat case XSParticleDecl.PARTICLE_WILDCARD: { checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, (XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs, checkWCOccurrence); return bExpansionHappened; } // Elt:All RecurseAsIfGroup case XSModelGroupImpl.MODELGROUP_CHOICE: { // Treat the element as if it were in a group of the same type // as the base Particle dChildren = new Vector(); dChildren.addElement(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 // as the base Particle dChildren = new Vector(); dChildren.addElement(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) { // Any:Any NSSubset 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) { // All:Any NSRecurseCheckCardinality 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) { // Choice:Any NSRecurseCheckCardinality 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) { // Choice:Any NSRecurseCheckCardinality 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 (Vector v, XSElementDecl d) { XSParticleDecl p = new XSParticleDecl(); p.fValue = d; p.fType = XSParticleDecl.PARTICLE_ELEMENT; v.addElement(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 Vector removePointlessChildren(XSParticleDecl p) { if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || p.fType == XSParticleDecl.PARTICLE_WILDCARD) return null; Vector children = new Vector(); 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, Vector 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.addElement(p); return; } if (! (min==1 && max==1)) { children.addElement(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.addElement(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) { // derived one has to have a fixed value if (dElement.getConstraintType() != XSConstants.VC_FIXED) { throw new XMLSchemaException("rcase-NameAndTypeOK.4.a", new Object[]{dElement.fName, bElement.fDefault.stringValue()}); } // get simple type boolean isSimple = false; if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE || ((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { isSimple = true; } // if there is no simple type, then compare based on string 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 { // check Occurrence ranges 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)}); } // check wildcard allows namespace of element 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 { // check Occurrence ranges 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)}); } // check wildcard subset 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(Vector children, int min1, int max1, SubstitutionGroupHandler dSGHandler, XSParticleDecl wildcard, int min2, int max2, boolean checkWCOccurrence) throws XMLSchemaException { // check Occurrence ranges 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)}); } // Check that each member of the group is a valid restriction of the wildcard int count = children.size(); try { for (int i = 0; i < count; i++) { XSParticleDecl particle1 = (XSParticleDecl)children.elementAt(i); particleValidRestriction(particle1, dSGHandler, wildcard, null, false); } } // REVISIT: should we really just ignore original cause of this error? // how can we report it? catch (XMLSchemaException e) { throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null); } } private static void checkRecurse(Vector dChildren, int min1, int max1, SubstitutionGroupHandler dSGHandler, Vector bChildren, int min2, int max2, SubstitutionGroupHandler bSGHandler) throws XMLSchemaException { // check Occurrence ranges 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 // // // // // // // // // // check Occurrence ranges 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= 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, // who has the same name/namespace with element1 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, // as defined in constraint UPA public static boolean overlapUPA(XSElementDecl element, XSWildcardDecl wildcard, SubstitutionGroupHandler sgHandler) { // if the wildcard allows the element if (wildcard.allowNamespace(element.fTargetNamespace)) return true; // or if the wildcard allows any element in the substitution group 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) { // if the intersection of the two wildcard is not empty list XSWildcardDecl intersect = wildcard1.performIntersectionWith(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 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