All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.impl.xs.SubstitutionGroupHandler Maven / Gradle / Ivy

Go to download

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy