FileDocCategorySizeDatePackage
SubstitutionGroupHandler.javaAPI DocApache Xerces 3.0.115953Fri Sep 14 20:33:54 BST 2007org.apache.xerces.impl.xs

SubstitutionGroupHandler

public class SubstitutionGroupHandler extends Object
To store and validate information about substitutionGroup
xerces.internal
author
Sandy Gao, IBM
version
$Id: SubstitutionGroupHandler.java 520257 2007-03-20 03:37:12Z mrglavas $

Fields Summary
private static final XSElementDecl[]
EMPTY_GROUP
XSGrammarBucket
fGrammarBucket
Hashtable
fSubGroupsB
private static final OneSubGroup[]
EMPTY_VECTOR
Hashtable
fSubGroups
Constructors Summary
public SubstitutionGroupHandler(XSGrammarBucket grammarBucket)
Default constructor


           
       
        fGrammarBucket = grammarBucket;
    
Methods Summary
public voidaddSubstitutionGroup(XSElementDecl[] elements)
add a list of substitution group information.

        XSElementDecl subHead, element;
        Vector subGroup;
        // for all elements with substitution group affiliation
        for (int i = elements.length-1; i >= 0; i--) {
            element = elements[i];
            subHead = element.fSubGroup;
            // check whether this an entry for this element
            subGroup = (Vector)fSubGroupsB.get(subHead);
            if (subGroup == null) {
                // if not, create a new one
                subGroup = new Vector();
                fSubGroupsB.put(subHead, subGroup);
            }
            // add to the vactor
            subGroup.addElement(element);
        }
    
private booleangetDBMethods(org.apache.xerces.xs.XSTypeDefinition typed, org.apache.xerces.xs.XSTypeDefinition typeb, org.apache.xerces.impl.xs.SubstitutionGroupHandler$OneSubGroup methods)

        short dMethod = 0, bMethod = 0;
        while (typed != typeb && typed != SchemaGrammar.fAnyType) {
            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.fAnyType;
            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;
    
public XSElementDeclgetMatchingElemDecl(org.apache.xerces.xni.QName element, XSElementDecl exemplar)

        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 grammar of the element
        SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri);
        if (sGrammar == null) {
            return null;
        }

        // get the decl for the element
        XSElementDecl eDecl = sGrammar.getGlobalElementDecl(element.localpart);
        if (eDecl == null) {
            return null;
        }

        // and check by using substitutionGroup information
        if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock)) {
            return eDecl;
        }

        return null;
    
private org.apache.xerces.impl.xs.SubstitutionGroupHandler$OneSubGroup[]getSubGroupB(XSElementDecl element, org.apache.xerces.impl.xs.SubstitutionGroupHandler$OneSubGroup methods)

        Object subGroup = fSubGroupsB.get(element);

        // substitution group for this one is empty
        if (subGroup == null) {
            fSubGroupsB.put(element, EMPTY_VECTOR);
            return EMPTY_VECTOR;
        }
        
        // we've already calculated the element, just return.
        if (subGroup instanceof OneSubGroup[])
            return (OneSubGroup[])subGroup;
        
        // we only have the *direct* substitutions
        Vector group = (Vector)subGroup, newGroup = new Vector();
        OneSubGroup[] group1;
        // then for each of the direct substitutions, get its substitution
        // group, and combine the groups together.
        short dMethod, bMethod, dSubMethod, bSubMethod;
        for (int i = group.size()-1, j; i >= 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))
                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);
            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;
    
public XSElementDecl[]getSubstitutionGroup(XSElementDecl element)
get all elements that can substitute the given element, according to the spec, we shouldn't consider the {block} constraints. from the spec, substitution group of a given element decl also contains the element itself. but the array returned from this method doesn't containt this element.

        // If we already have sub group for this element, just return it.
        Object subGroup = fSubGroups.get(element);
        if (subGroup != null)
            return (XSElementDecl[])subGroup;
        
        if ((element.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) {
            fSubGroups.put(element, EMPTY_GROUP);
            return EMPTY_GROUP;
        }
        
        // Otherwise, get all potential sub group elements
        // (without considering "block" on this element
        OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup());
        int len = groupB.length, rlen = 0;
        XSElementDecl[] ret = new XSElementDecl[len];
        // For each of such elements, check whether the derivation methods
        // overlap with "block". If not, add it to the sub group
        for (int i = 0 ; i < len; i++) {
            if ((element.fBlock & groupB[i].dMethod) == 0)
                ret[rlen++] = groupB[i].sub;
        }
        // Resize the array if necessary
        if (rlen < len) {
            XSElementDecl[] ret1 = new XSElementDecl[rlen];
            System.arraycopy(ret, 0, ret1, 0, rlen);
            ret = ret1;
        }
        // Store the subgroup
        fSubGroups.put(element, ret);

        return ret;
    
public booleaninSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar)

        // [Definition:]  Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows:
        // Define PSG, the potential substitution group for HEAD, as follows:
        // 1 The element declaration itself is in PSG;
        // 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself.
        // HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true:
        // 1 Its {abstract} is false.
        // 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6).
        return substitutionGroupOK(element, exemplar, exemplar.fBlock);
    
public voidreset()
clear the internal registry of substitutionGroup information


                
       
        fSubGroupsB.clear();
        fSubGroups.clear();
    
protected booleansubstitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint)

        // 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;
        while (subGroup != null && subGroup != exemplar) {
            subGroup = subGroup.fSubGroup;
        }

        if (subGroup == null) {
            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);   
    
private booleantypeDerivationOK(org.apache.xerces.xs.XSTypeDefinition derived, org.apache.xerces.xs.XSTypeDefinition base, short blockingConstraint)

        
        short devMethod = 0, blockConstraint = blockingConstraint;

        // "derived" should be derived from "base"
        // add derivation methods of derived types to devMethod;
        // add block of base types to blockConstraint.
        XSTypeDefinition type = derived;
        while (type != base && type != SchemaGrammar.fAnyType) {
            if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
                devMethod |= ((XSComplexTypeDecl)type).fDerivedBy;
            }
            else {
                devMethod |= XSConstants.DERIVATION_RESTRICTION;
            }
            type = type.getBaseType();
            // type == null means the current type is anySimpleType,
            // whose base type should be anyType
            if (type == null) {
                type = SchemaGrammar.fAnyType;
            }
            if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
                blockConstraint |= ((XSComplexTypeDecl)type).fBlock;
            }
        }
        if (type != base) {
            // If the base is a union, check if "derived" is allowed through any of the member types.
            if (base.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
                XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) base;
                if (st.getVariety() ==  XSSimpleTypeDefinition.VARIETY_UNION) {
                    XSObjectList memberTypes = st.getMemberTypes();
                    final int length = memberTypes.getLength();
                    for (int i = 0; i < length; ++i) {
                        if (typeDerivationOK(derived, (XSTypeDefinition) memberTypes.item(i), blockingConstraint)) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        if ((devMethod & blockConstraint) != 0) {
            return false;
        }
        return true;