void TraverseSchema::processComplexContent()

in src/xercesc/validators/schema/TraverseSchema.cpp [6167:6471]


void TraverseSchema::processComplexContent(const DOMElement* const ctElem,
                                           const XMLCh* const typeName,
                                           const DOMElement* const childElem,
                                           ComplexTypeInfo* const typeInfo,
                                           const XMLCh* const baseLocalPart,
                                           const bool isMixed,
                                           const bool isBaseAnyType) {

    NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this);

    Janitor<ContentSpecNode>    specNodeJan(0);
    ContentSpecNode* specNode = specNodeJan.get();
    const DOMElement* attrNode = 0;
    int                 typeDerivedBy = typeInfo->getDerivedBy();
    ComplexTypeInfo*    baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
    int baseContentType = (baseTypeInfo) ? baseTypeInfo->getContentType() : SchemaElementDecl::Empty;

    if (baseTypeInfo) {

        if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {

            // check to see if the baseType permits derivation by restriction
            if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {

                reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByRestriction,
                                  baseLocalPart);
                throw TraverseSchema::InvalidComplexTypeInfo;
            }
        }
        else {

            // check to see if the baseType permits derivation by extension
            if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {

                reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByExtension, baseLocalPart);
                throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
            }

            processElements(ctElem, baseTypeInfo, typeInfo);
        }
    }

    bool effectiveContent_hasChild = false;

    if (childElem != 0) {

        fCircularCheckIndex = fCurrentTypeNameStack->size();

        // --------------------------------------------------------------------
        // GROUP, ALL, SEQUENCE or CHOICE, followed by attributes, if specified.
        // Note that it's possible that only attributes are specified.
        // --------------------------------------------------------------------
        const XMLCh* childName = childElem->getLocalName();

        if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) {

            XercesGroupInfo* grpInfo = traverseGroupDecl(childElem, false);

            if (grpInfo) {

                ContentSpecNode* const groupSpecNode = grpInfo->getContentSpec();

                if (groupSpecNode) {

                    int contentContext = groupSpecNode->hasAllContent() ? Group_Ref_With_All : Not_All_Context;
                    specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*groupSpecNode));
                    specNode = specNodeJan.get();
                    checkMinMax(specNode, childElem, contentContext);
                }
            }

            attrNode = XUtil::getNextSiblingElement(childElem);

        }
        else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) {

            specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Sequence, effectiveContent_hasChild));
            specNode = specNodeJan.get();
            checkMinMax(specNode, childElem);
            attrNode = XUtil::getNextSiblingElement(childElem);
        }
        else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) {

            specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Choice, effectiveContent_hasChild));
            specNode = specNodeJan.get();
            int minOccurs = checkMinMax(specNode, childElem);
            if (!effectiveContent_hasChild && minOccurs != 0) {
                effectiveContent_hasChild = true;
            }

            attrNode = XUtil::getNextSiblingElement(childElem);
        }
        else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) {

            specNodeJan.reset(traverseAll(childElem, effectiveContent_hasChild));
            specNode = specNodeJan.get();
            checkMinMax(specNode, childElem, All_Group);
            attrNode = XUtil::getNextSiblingElement(childElem);
        }
        else if (isAttrOrAttrGroup(childElem)) {
            // reset the contentType
            typeInfo->setContentType(SchemaElementDecl::Any);
            attrNode = childElem;
        }
        else {
            reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName);
        }
    }

    typeInfo->setContentSpec(specNode);
    typeInfo->setAdoptContentSpec(true);
    specNodeJan.release();
    bool specNodeWasNull = false;

    // -----------------------------------------------------------------------
    // Merge in information from base, if it exists
    // -----------------------------------------------------------------------
    if (baseTypeInfo) {

        ContentSpecNode* baseSpecNode = baseTypeInfo->getContentSpec();

        if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {

            //check derivation valid - content type is empty (5.2)
            if (!typeInfo->getContentSpec()) {

                if (baseContentType != SchemaElementDecl::Empty
                    && !emptiableParticle(baseSpecNode)) {
                    reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptyComplexRestrictionDerivation);
                }
            }

            // Delay particle constraint checking (5.3) until we have processed
            // the whole schema.
        }
        else {

            // Compose the final content model by concatenating the base and
            // the current in sequence
            if (!specNode) {
                specNodeWasNull = true;
                if (isMixed) {
                    if (baseSpecNode && baseSpecNode->hasAllContent()) {
                        reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
                        throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
                    }
                }
                if (baseSpecNode) {
                    specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode));
                    specNode = specNodeJan.get();
                    typeInfo->setContentSpec(specNode);
                    typeInfo->setAdoptContentSpec(true);
                    specNodeJan.release();
                }
            }
            else if (baseSpecNode) {

                if (specNode->hasAllContent() || baseSpecNode->hasAllContent()) {

                    reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
                    throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
                }

                // Check for derivation valid (extension) - 1.4.3.2.2.1
                if ((isMixed && baseContentType == SchemaElementDecl::Children)
                    || (!isMixed && baseContentType != SchemaElementDecl::Children)) {

                    reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
                    throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
                }

                typeInfo->setAdoptContentSpec(false);
                typeInfo->setContentSpec
                (
                    new (fGrammarPoolMemoryManager) ContentSpecNode
                    (
                        ContentSpecNode::ModelGroupSequence
                        , new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode)
                        , specNode
                        , true
                        , true
                        , fGrammarPoolMemoryManager
                    )
                );
                typeInfo->setAdoptContentSpec(true);
            }
        }
    }
    else {
        typeInfo->setDerivedBy(0);
    }

    // -------------------------------------------------------------
    // Set the content type
    // -------------------------------------------------------------
    if (isBaseAnyType && typeDerivedBy == SchemaSymbols::XSD_EXTENSION) {

        ContentSpecNode* anySpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode
        (
            new (fGrammarPoolMemoryManager) QName
            (
                XMLUni::fgZeroLenString
                , XMLUni::fgZeroLenString
                , fEmptyNamespaceURI, fGrammarPoolMemoryManager
            )
            , false
            , fGrammarPoolMemoryManager
        );

        anySpecNode->setType(ContentSpecNode::Any_Lax);
        anySpecNode->setMinOccurs(0);
        anySpecNode->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED);

        if (!specNode) {
            typeInfo->setContentSpec(anySpecNode);
            typeInfo->setDerivedBy(typeDerivedBy);
        }
        else {

            typeInfo->setAdoptContentSpec(false);
            typeInfo->setContentSpec
            (
                new (fGrammarPoolMemoryManager) ContentSpecNode
                (
                    ContentSpecNode::ModelGroupSequence
                    , anySpecNode
                    , specNode
                    , true
                    , true
                    , fGrammarPoolMemoryManager
                )
            );
            typeInfo->setAdoptContentSpec(true);

            if (!isMixed) {

                reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
                throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
            }
        }

        typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
    }
    else if (isMixed) {

        if (specNode != 0) {
            typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
        }
        else {
            // add #PCDATA leaf and set its minOccurs to 0
            ContentSpecNode* pcdataNode = new (fGrammarPoolMemoryManager) ContentSpecNode
            (
                new (fGrammarPoolMemoryManager) QName
                (
                    XMLUni::fgZeroLenString
                    , XMLUni::fgZeroLenString
                    , XMLElementDecl::fgPCDataElemId
                    , fGrammarPoolMemoryManager
                )
                , false
                , fGrammarPoolMemoryManager
            );

            pcdataNode->setMinOccurs(0);
            typeInfo->setContentSpec(pcdataNode);
            typeInfo->setAdoptContentSpec(true);
            typeInfo->setContentType(SchemaElementDecl::Mixed_Simple);
        }
    }
    else if (specNodeWasNull &&
            (typeDerivedBy == SchemaSymbols::XSD_EXTENSION) &&
             baseTypeInfo) {
        typeInfo->setBaseDatatypeValidator(baseTypeInfo->getBaseDatatypeValidator());
        typeInfo->setDatatypeValidator(baseTypeInfo->getDatatypeValidator());
        typeInfo->setContentType(baseTypeInfo->getContentType());
    }
    else if (typeInfo->getContentSpec() == 0) {
        if (!effectiveContent_hasChild) {
            typeInfo->setContentType(SchemaElementDecl::Empty);
        }
        else {
            typeInfo->setContentType(SchemaElementDecl::ElementOnlyEmpty);
        }
    }
    else {
        typeInfo->setContentType(SchemaElementDecl::Children);
    }

    // -------------------------------------------------------------
    // Now, check attributes and handle
    // -------------------------------------------------------------
    if (attrNode != 0) {

        if (!isAttrOrAttrGroup(attrNode)) {
            reportSchemaError(attrNode, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType,
                              attrNode->getLocalName());
        }
        else {
            processAttributes(ctElem, attrNode, typeInfo, isBaseAnyType);
        }
    }
    else if (baseTypeInfo != 0 || isBaseAnyType) {
        processAttributes(ctElem, 0, typeInfo, isBaseAnyType);
    }
}