org.apache.xerces.impl.xs.SubstitutionGroupHandler 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.Hashtable;
import java.util.Vector;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSSimpleTypeDefinition;
import org.apache.xerces.xs.XSTypeDefinition;
/**
* To store and validate information about substitutionGroup
*
* @xerces.internal
*
* @author Sandy Gao, IBM
*
* @version $Id$
*/
public class SubstitutionGroupHandler {
private static final XSElementDecl[] EMPTY_GROUP = new XSElementDecl[0];
// global element declaration resolver
private final XSElementDeclHelper fXSElementDeclHelper;
/**
* Default constructor
*/
public SubstitutionGroupHandler(XSElementDeclHelper elementDeclHelper) {
fXSElementDeclHelper = elementDeclHelper;
}
// 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3
// check whether one element decl matches an element with the given qname
public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar, short schemaVersion) {
if (element.localpart == exemplar.fName &&
element.uri == exemplar.fTargetNamespace) {
return exemplar;
}
// if the exemplar is not a global element decl, then it's not possible
// to be substituted by another element.
if (exemplar.fScope != XSConstants.SCOPE_GLOBAL) {
return null;
}
// if the decl blocks substitution, return false
if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) {
return null;
}
// get the decl for the element
XSElementDecl eDecl = fXSElementDeclHelper.getGlobalElementDecl(element);
if (eDecl == null) {
return null;
}
// and check by using substitutionGroup information
if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock, schemaVersion)) {
return eDecl;
}
return null;
}
// 3.3.6 Substitution Group OK (Transitive)
// check whether element can substitute exemplar
protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint, short schemaVersion) {
// For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true:
// 1. D and C are the same element declaration.
if (element == exemplar) {
return true;
}
// 2 All of the following must be true:
// 2.1 The blocking constraint does not contain substitution.
if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0) {
return false;
}
// 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . .
XSElementDecl[] subGroup = element.fSubGroup;
if (subGroup == null || !checkSubstitutionGroupAffil(subGroup, exemplar)) {
return false;
}
// 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}.
// prepare the combination of {derivation method} and
// {disallowed substitution}
return typeDerivationOK(element.fType, exemplar.fType, blockingConstraint, schemaVersion);
}
// Recursively check if there is a element in substitution group matching exemplar
private boolean checkSubstitutionGroupAffil(XSElementDecl[] subGroupArray, XSElementDecl examplar) {
for (int i=0; i= 0; i--) {
element = elements[i];
subHeads = element.fSubGroup;
// check whether this an entry for this element
for (int j=0; j= 0; i--) {
// Check whether this element is blocked. If so, ignore it.
XSElementDecl sub = (XSElementDecl)group.elementAt(i);
if (!getDBMethods(sub.fType, element.fType, methods, schemaVersion))
continue;
// Remember derivation methods and blocks from the types
dMethod = methods.dMethod;
bMethod = methods.bMethod;
// Add this one to potential group
newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod));
// Get potential group for this element
group1 = getSubGroupB(sub, methods, schemaVersion);
for (j = group1.length-1; j >= 0; j--) {
// For each of them, check whether it's blocked (by type)
dSubMethod = (short)(dMethod | group1[j].dMethod);
bSubMethod = (short)(bMethod | group1[j].bMethod);
// Ignore it if it's blocked
if ((dSubMethod & bSubMethod) != 0)
continue;
newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod));
}
}
// Convert to an array
OneSubGroup[] ret = new OneSubGroup[newGroup.size()];
for (int i = newGroup.size()-1; i >= 0; i--) {
ret[i] = (OneSubGroup)newGroup.elementAt(i);
}
// Store the potential sub group
fSubGroupsB.put(element, ret);
return ret;
}
private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb,
OneSubGroup methods, short schemaVersion) {
short dMethod = 0, bMethod = 0;
while (typed != typeb && !SchemaGrammar.isAnyType(typed)) {
if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy;
else
dMethod |= XSConstants.DERIVATION_RESTRICTION;
typed = typed.getBaseType();
// type == null means the current type is anySimpleType,
// whose base type should be anyType
if (typed == null)
typed = SchemaGrammar.getXSAnyType(schemaVersion);
if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
bMethod |= ((XSComplexTypeDecl)typed).fBlock;
}
// No derivation relation, or blocked, return false
if (typed != typeb || (dMethod & bMethod) != 0)
return false;
// Remember the derivation methods and blocks, return true.
methods.dMethod = dMethod;
methods.bMethod = bMethod;
return true;
}
// Record the information about how one element substitute another one
private static final class OneSubGroup {
OneSubGroup() {}
OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) {
this.sub = sub;
this.dMethod = dMethod;
this.bMethod = bMethod;
}
// The element that substitutes another one
XSElementDecl sub;
// The combination of all derivation methods from sub's type to
// the head's type
short dMethod;
// The combination of {block} of the types in the derivation chain
// excluding sub's type
short bMethod;
}
} // class SubstitutionGroupHandler