void TraverseSchema::traverseSimpleContentDecl()

in src/xercesc/validators/schema/TraverseSchema.cpp [3657:4031]


void TraverseSchema::traverseSimpleContentDecl(const XMLCh* const typeName,
                                               const XMLCh* const qualifiedName,
                                               const DOMElement* const contentDecl,
                                               ComplexTypeInfo* const typeInfo,
                                               Janitor<XSAnnotation>* const janAnnot)
{
    NamespaceScopeManager nsMgr(contentDecl, fSchemaInfo, this);

    // -----------------------------------------------------------------------
    // Check Attributes
    // -----------------------------------------------------------------------
    bool preProcessFlag = typeInfo->getPreprocessed();

    if (!preProcessFlag) {
        fAttributeCheck.checkAttributes(
            contentDecl, GeneralAttributeCheck::E_SimpleContent
            , this, false, fNonXSAttList
        );
    }

    // -----------------------------------------------------------------------
    // Set the content type to be simple, and initialize content spec handle
    // -----------------------------------------------------------------------
    typeInfo->setContentType(SchemaElementDecl::Simple);

    // -----------------------------------------------------------------------
    // Process annotation if any
    // -----------------------------------------------------------------------
    DOMElement* simpleContent = checkContent(contentDecl, XUtil::getFirstChildElement(contentDecl), false, !preProcessFlag);
    if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
    {
        fAnnotation = generateSyntheticAnnotation(contentDecl, fNonXSAttList);
    }
    if (fAnnotation)
    {
        if (janAnnot->isDataNull())
            janAnnot->reset(fAnnotation);
        else
            janAnnot->get()->setNext(fAnnotation);
    }

    // If there are no children, return
    if (simpleContent == 0) {

        reportSchemaError(contentDecl, XMLUni::fgXMLErrDomain, XMLErrs::EmptySimpleTypeContent);
        throw TraverseSchema::InvalidComplexTypeInfo;
    }

    NamespaceScopeManager nsMgr2(simpleContent, fSchemaInfo, this);
    // -----------------------------------------------------------------------
    // The content should be either "restriction" or "extension"
    // -----------------------------------------------------------------------
    if (!preProcessFlag) {
        const XMLCh* const contentName = simpleContent->getLocalName();

        if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_RESTRICTION)) {

            fAttributeCheck.checkAttributes(
                simpleContent, GeneralAttributeCheck::E_Restriction
                , this, false, fNonXSAttList
            );
            typeInfo->setDerivedBy(SchemaSymbols::XSD_RESTRICTION);
        }
        else if (XMLString::equals(contentName, SchemaSymbols::fgATTVAL_EXTENSION)) {

            fAttributeCheck.checkAttributes(
                simpleContent, GeneralAttributeCheck::E_Extension
                , this, false, fNonXSAttList
            );
            typeInfo->setDerivedBy(SchemaSymbols::XSD_EXTENSION);
        }
        else {
            reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContent);
            throw TraverseSchema::InvalidComplexTypeInfo;
        }
    }

    //Skip over any annotations in the restriction or extension elements
    DOMElement* content = checkContent(simpleContent, XUtil::getFirstChildElement(simpleContent), true, !preProcessFlag);
    if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
    {
        fAnnotation = generateSyntheticAnnotation(simpleContent, fNonXSAttList);
    }
    if (fAnnotation)
    {
        if (janAnnot->isDataNull())
            janAnnot->reset(fAnnotation);
        else
            janAnnot->get()->setNext(fAnnotation);
    }

    // -----------------------------------------------------------------------
    // Handle the base type name
    // -----------------------------------------------------------------------
    const XMLCh* baseName = getElementAttValue(simpleContent, SchemaSymbols::fgATT_BASE, DatatypeValidator::QName);

    if (!baseName || !*baseName) {

        reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::UnspecifiedBase);
        throw TraverseSchema::InvalidComplexTypeInfo;
    }

    const XMLCh* prefix = getPrefix(baseName);
    const XMLCh* localPart = getLocalPart(baseName);
    const XMLCh* uri = resolvePrefixToURI(simpleContent, prefix);

    // check for 'anyType'
    if (XMLString::equals(uri, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)
        && XMLString::equals(localPart, SchemaSymbols::fgATTVAL_ANYTYPE)) {

        reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName);
        throw TraverseSchema::InvalidComplexTypeInfo;
    }

    processBaseTypeInfo(simpleContent, baseName, localPart, uri, typeInfo);

    ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
    DatatypeValidator* baseValidator = typeInfo->getBaseDatatypeValidator();

    if (baseValidator != 0 && baseTypeInfo == 0) {

        // check that the simpleType does not preclude derivation by extension
        if ((baseValidator->getFinalSet() & SchemaSymbols::XSD_EXTENSION) == typeInfo->getDerivedBy()) {

            reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DisallowedSimpleTypeExtension,
                              baseName, typeName);
            throw TraverseSchema::InvalidComplexTypeInfo;
        }

        //Schema Spec: 5.11: Complex Type Definition Properties Correct: 2
        if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) {

            reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidComplexTypeBase, baseName);
            throw TraverseSchema::InvalidComplexTypeInfo;
        }
    }

    // check that the base isn't a complex type with complex content
    // and that derivation method is not included in 'final'
    bool simpleTypeRequired = false;

    if (baseTypeInfo) {

        if (baseTypeInfo->getContentType() != SchemaElementDecl::Simple) {

            // Schema Errata: E1-27
            if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION
                && ((baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Simple
                    || baseTypeInfo->getContentType() == SchemaElementDecl::Mixed_Complex)
                    && emptiableParticle(baseTypeInfo->getContentSpec()))) {
                simpleTypeRequired = true;
            }
            else {
                reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidSimpleContentBase, baseName);
                throw TraverseSchema::InvalidComplexTypeInfo;
            }
        }

        if ((baseTypeInfo->getFinalSet() & typeInfo->getDerivedBy()) != 0) {
            reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivation, baseName);
            throw TraverseSchema::InvalidComplexTypeInfo;
        }
    }

    // -----------------------------------------------------------------------
    // Process the content of the derivation
    // -----------------------------------------------------------------------
    if (typeInfo->getDerivedBy() == SchemaSymbols::XSD_RESTRICTION) {

        if(baseTypeInfo)
            typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator());

        if (content != 0) {

            // ---------------------------------------------------------------
            // There may be a simple type definition in the restriction
            // element. The data type validator will be based on it, if
            // specified
            // ---------------------------------------------------------------
            if (XMLString::equals(content->getLocalName(), SchemaSymbols::fgELT_SIMPLETYPE)) {

                DatatypeValidator* simpleTypeDV = traverseSimpleTypeDecl(content, false);

                if (simpleTypeDV) {

                    // Check that the simpleType validator is validly derived
                    // from base
                    DatatypeValidator* baseDV = typeInfo->getBaseDatatypeValidator();

                    if (baseDV  && !baseDV->isSubstitutableBy(simpleTypeDV)) {

                        reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::InvalidContentRestriction);
                        throw TraverseSchema::InvalidComplexTypeInfo;
                    }

                    typeInfo->setBaseDatatypeValidator(simpleTypeDV);
                    content = XUtil::getNextSiblingElement(content);
                }
                else {
                    throw TraverseSchema::InvalidComplexTypeInfo;
                }
            }
            // Schema Errata E1-27
            // Complex Type Definition Restriction OK: 2.2
            else if (simpleTypeRequired) {

                reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired);
                throw TraverseSchema::InvalidComplexTypeInfo;
            }

            // ---------------------------------------------------------------
            // Build up the facet info
            // ---------------------------------------------------------------
            RefHashTableOf<KVStringPair>*  facets = 0;
            RefArrayVectorOf<XMLCh>*       enums = 0;
            XMLBuffer                      pattern(128, fGrammarPoolMemoryManager);
            XMLCh                          fixedFlagStr[16];
            unsigned int                   fixedFlag = 0;
            unsigned short                 scope = 0;
            bool                           isFirstPattern = true;

            while (content != 0) {

                const XMLCh* facetName = content->getLocalName();

                bool bDoBreak=false;    // workaround for Borland bug with 'break' in 'catch'
                // if not a valid facet, break from the loop
                try {
                    scope = fAttributeCheck.getFacetId(facetName, fMemoryManager);
                }
                catch(const OutOfMemoryException&)
                {
                    throw;
                }
                catch(...) {
                    bDoBreak=true;
                }
                if(bDoBreak)
                    break;

                if (content->getNodeType() == DOMNode::ELEMENT_NODE) {

                    fAttributeCheck.checkAttributes(content, scope, this);

                    const XMLCh* attValue = content->getAttribute(SchemaSymbols::fgATT_VALUE);

                    if (facets == 0) {
                        facets = new (fGrammarPoolMemoryManager) RefHashTableOf<KVStringPair>(29, true, fGrammarPoolMemoryManager);
                    }

                    if (XMLString::equals(facetName, SchemaSymbols::fgELT_ENUMERATION)) {

                        if (!enums) {
                            enums = new (fGrammarPoolMemoryManager) RefArrayVectorOf<XMLCh>(8, true, fGrammarPoolMemoryManager);
                        }

                        enums->addElement(XMLString::replicate(attValue, fGrammarPoolMemoryManager));
                    }
                    else if (XMLString::equals(facetName, SchemaSymbols::fgELT_PATTERN)) {

                        if (isFirstPattern) { // fBuffer.isEmpty() - overhead call

                            isFirstPattern = false;
                            pattern.set(attValue);
                        }
                        else { //datatypes: 5.2.4 pattern

                            pattern.append(chPipe);
                            pattern.append(attValue);
                        }
                    }
                    else {

                        if (facets->containsKey(facetName)) {
                            reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateFacet, facetName);
                        }
                        else {

                            const XMLCh* facetNameStr =
                                fStringPool->getValueForId(fStringPool->addOrFind(facetName));

                            facets->put((void*) facetNameStr, new (fGrammarPoolMemoryManager) KVStringPair(facetNameStr, attValue, fGrammarPoolMemoryManager));
                            checkFixedFacet(content, facetNameStr, typeInfo->getBaseDatatypeValidator(), fixedFlag);
                        }
                    }
                }

                content = XUtil::getNextSiblingElement(content);
            }

            if (facets) {

                if (!pattern.isEmpty()) {
                    facets->put
                    (
                        (void*) SchemaSymbols::fgELT_PATTERN,
                        new (fGrammarPoolMemoryManager) KVStringPair
                            (
                                SchemaSymbols::fgELT_PATTERN
                                , pattern.getRawBuffer()
                                , pattern.getLen()
                                , fGrammarPoolMemoryManager
                            )
                    );
                }

                if (fixedFlag) {

                    XMLString::binToText(fixedFlag, fixedFlagStr, 15, 10, fGrammarPoolMemoryManager);
                    facets->put((void*) SchemaSymbols::fgATT_FIXED,
                        new (fGrammarPoolMemoryManager) KVStringPair(SchemaSymbols::fgATT_FIXED, fixedFlagStr, fGrammarPoolMemoryManager));
                }

                try {

                    DatatypeValidator* simpleDV =
                        fDatatypeRegistry->createDatatypeValidator
                        (
                            qualifiedName,
                            typeInfo->getBaseDatatypeValidator(),
                            facets, enums, false, 0, true, fGrammarPoolMemoryManager
                        );
                    simpleDV->setAnonymous();
                    typeInfo->setDatatypeValidator(simpleDV);
                }
                catch (const XMLException& excep) {
                    reportSchemaError(simpleContent, excep);
                }
                catch(const OutOfMemoryException&)
                {
                    throw;
                }
                catch(...) {
                    reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::DatatypeValidatorCreationError, typeName);
                }
            }
            else {
                typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
            }
        }
        else {

            // Schema Errata E1-27
            // Complex Type Definition Restriction OK: 2.2
            if (simpleTypeRequired) {

                reportSchemaError(content, XMLUni::fgXMLErrDomain, XMLErrs::CT_SimpleTypeChildRequired);
                throw TraverseSchema::InvalidComplexTypeInfo;
            }

            typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
        }
    } // end RESTRICTION
    else { // EXTENSION

        ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();

        if (baseTypeInfo!= 0) {

            typeInfo->setBaseDatatypeValidator(baseTypeInfo->getDatatypeValidator());
        }

        typeInfo->setDatatypeValidator(typeInfo->getBaseDatatypeValidator());
    }

    // -----------------------------------------------------------------------
    // Process attributes if any
    // -----------------------------------------------------------------------
    processAttributes(simpleContent, content, typeInfo);

    if (XUtil::getNextSiblingElement(simpleContent) != 0) {
        reportSchemaError(simpleContent, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInSimpleContent);
    }

} // End of function traverseSimpleContentDecl