void SchemaValidator::validateElement()

in src/xercesc/validators/schema/SchemaValidator.cpp [531:754]


void SchemaValidator::validateElement(const   XMLElementDecl*  elemDef)
{
    ComplexTypeInfo* elemTypeInfo = ((SchemaElementDecl*)elemDef)->getComplexTypeInfo();
    fTypeStack->push(elemTypeInfo);
    fCurrentDatatypeValidator = (elemTypeInfo)
            ? elemTypeInfo->getDatatypeValidator()
            : ((SchemaElementDecl*)elemDef)->getDatatypeValidator();

    fErrorOccurred = false;

    if (fXsiType) {
        // handle "xsi:type" right here
        DatatypeValidator *xsiTypeDV = 0;
        unsigned int uri = fXsiType->getURI();
        const XMLCh* localPart = fXsiType->getLocalPart();

        if (uri != XMLElementDecl::fgInvalidElemId &&
            uri != XMLElementDecl::fgPCDataElemId &&
            uri != XMLContentModel::gEpsilonFakeId &&
            uri != XMLContentModel::gEOCFakeId) {

            // retrieve Grammar for the uri
            const XMLCh* uriStr = getScanner()->getURIText(uri);
            SchemaGrammar* sGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(uriStr);
            if (!sGrammar) {

                // Check built-in simple types
                if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {

                    xsiTypeDV = fGrammarResolver->getDatatypeValidator(uriStr, localPart);

                    if (!xsiTypeDV) {
                        emitError(XMLValid::BadXsiType, fXsiType->getRawName());
                        fErrorOccurred = true;
                    }
                    else {
                        if (elemTypeInfo || (fCurrentDatatypeValidator
                                && !fCurrentDatatypeValidator->isSubstitutableBy(xsiTypeDV))) {
                            // the type is not derived from ancestor
                            emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                            fErrorOccurred = true;
                        }
                        else if(fCurrentDatatypeValidator != xsiTypeDV) 
                        {
                            // the type is derived from ancestor
                            if ((((SchemaElementDecl*)elemDef)->getBlockSet() & SchemaSymbols::XSD_RESTRICTION) != 0) {
                                emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
                                fErrorOccurred = true;
                            }
                            if (elemDef->hasAttDefs()) {
                                // if we have an attribute but xsi:type's type is simple, we have a problem...
                                emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                                fErrorOccurred = true;
                            }
                        }
                        fCurrentDatatypeValidator = xsiTypeDV;
                    }
                }
                else {
                    // Grammar not found
                    emitError(XMLValid::GrammarNotFound, uriStr);
                    fErrorOccurred = true;
                }
            }
            else if (sGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
                emitError(XMLValid::GrammarNotFound, uriStr);
                fErrorOccurred = true;
            }
            else {
                // retrieve complexType registry and DatatypeValidator registry
                RefHashTableOf<ComplexTypeInfo>* complexTypeRegistry = sGrammar->getComplexTypeRegistry();
                if (!complexTypeRegistry) {
                    emitError(XMLValid::BadXsiType, fXsiType->getRawName());
                    fErrorOccurred = true;
                }
                else {

                    // retrieve the typeInfo specified in xsi:type
                    XMLBuffer aBuffer(1023, fMemoryManager);
                    aBuffer.set(uriStr);
                    aBuffer.append(chComma);
                    aBuffer.append(localPart);
                    ComplexTypeInfo* typeInfo = complexTypeRegistry->get(aBuffer.getRawBuffer());

                    if (typeInfo) {
                        // typeInfo is found
                        if (typeInfo->getAbstract()) {
                            emitError(XMLValid::NoAbstractInXsiType, aBuffer.getRawBuffer());
                            fErrorOccurred = true;
                        }
                        else
                        {
                            if (elemTypeInfo)
                            {
                                ComplexTypeInfo* tempType = typeInfo;
                                while (tempType) {
                                    if (tempType == elemTypeInfo)
                                        break;
                                    tempType = tempType->getBaseComplexTypeInfo();
                                }

                                if (!tempType) {
                                    emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                                    fErrorOccurred = true;
                                }
                                else if(elemTypeInfo != typeInfo) {
                                    // perform the check on the entire inheritance chain
                                    ComplexTypeInfo* tempType = typeInfo;
                                    while (tempType) {
                                        if (tempType == elemTypeInfo)
                                            break;
                                        int derivationMethod = tempType->getDerivedBy();
                                        if ((((SchemaElementDecl*)elemDef)->getBlockSet() & derivationMethod) != 0) {
                                            emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
                                            fErrorOccurred = true;
                                        }
                                        if ((elemTypeInfo->getBlockSet() & derivationMethod) != 0) {
                                            emitError(XMLValid::TypeNoSubforBlock, elemTypeInfo->getTypeName());
                                            fErrorOccurred = true;
                                        }
                                        tempType = tempType->getBaseComplexTypeInfo();
                                    }
                                }
                            }
                            else
                            {
                                // if the original type is a simple type, check derivation ok.
                                if (fCurrentDatatypeValidator && !fCurrentDatatypeValidator->isSubstitutableBy(typeInfo->getDatatypeValidator())) {
                                    // the type is not derived from ancestor
                                    emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                                    fErrorOccurred = true;
                                }
                            }

                            if (!fErrorOccurred)
                            {
                                fTypeStack->pop();
                                fTypeStack->push(typeInfo);
                                fCurrentDatatypeValidator = typeInfo->getDatatypeValidator();
                            }
                        }
                    }
                    else
                    {
                        // typeInfo not found
                        xsiTypeDV = fGrammarResolver->getDatatypeValidator(uriStr, localPart);

                        if (!xsiTypeDV) {
                            emitError(XMLValid::BadXsiType, fXsiType->getRawName());
                            fErrorOccurred = true;
                        }
                        else {
                            if (fCurrentDatatypeValidator && !fCurrentDatatypeValidator->isSubstitutableBy(xsiTypeDV)) {
                                // the type is not derived from ancestor
                                emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                                fErrorOccurred = true;
                            }
                            else if(fCurrentDatatypeValidator != xsiTypeDV)
                            {
                                DatatypeValidator::ValidatorType derivedType=xsiTypeDV->getType();
                                if((derivedType == DatatypeValidator::List || derivedType == DatatypeValidator::Union) && fCurrentDatatypeValidator==0)
                                {
                                    // the substitution is always allowed if the type is list or union and the base type was xs:anySimpleType
                                }
                                else
                                {
                                    // the type is derived from ancestor
                                    if ((((SchemaElementDecl*)elemDef)->getBlockSet() & SchemaSymbols::XSD_RESTRICTION) != 0) {
                                        emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
                                        fErrorOccurred = true;
                                    }
                                    if (elemDef->hasAttDefs()) {
                                        // if we have an attribute but xsi:type's type is simple, we have a problem...
                                        emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
                                        fErrorOccurred = true;
                                    }
                                }
                            }

                            fCurrentDatatypeValidator = xsiTypeDV;
                        }
                    }
                }
            }
        }

        delete fXsiType;
        fXsiType = 0;
    }
    else {
        //
        // xsi:type was not specified...
        // If the corresponding type is abstract, detect an error
        //
        if (elemTypeInfo && elemTypeInfo->getAbstract()) {
            emitError(XMLValid::NoUseAbstractType, elemDef->getFullName());
            fErrorOccurred = true;
        }
    }

    //
    // Check whether this element is abstract.  If so, an error
    //
    int miscFlags = ((SchemaElementDecl*)elemDef)->getMiscFlags();
    if ((miscFlags & SchemaSymbols::XSD_ABSTRACT) != 0) {
        emitError(XMLValid::NoDirectUseAbstractElement, elemDef->getFullName());
        fErrorOccurred = true;
    }

    //
    // Check whether this element allows Nillable
    //
    if (fNilFound && (miscFlags & SchemaSymbols::XSD_NILLABLE) == 0 ) {
        fNil = false;
        fNilFound = false;
        emitError(XMLValid::NillNotAllowed, elemDef->getFullName());
        fErrorOccurred = true;
    }

    fDatatypeBuffer.reset();
    fTrailing = false;
    fSeenNonWhiteSpace = false;
    fSeenId = false;
}