void TraverseSchema::traverseAttributeDecl()

in src/xercesc/validators/schema/TraverseSchema.cpp [2259:2631]


void TraverseSchema::traverseAttributeDecl(const DOMElement* const elem,
                                           ComplexTypeInfo* const typeInfo,
                                           const bool topLevel) {

    NamespaceScopeManager nsMgr(elem, fSchemaInfo, this);

    const XMLCh*   name = getElementAttValue(elem, SchemaSymbols::fgATT_NAME, DatatypeValidator::NCName);
    const XMLCh*   ref = getElementAttValue(elem, SchemaSymbols::fgATT_REF, DatatypeValidator::QName);
    bool           nameEmpty = (!name || !*name);
    bool           refEmpty = (!ref || !*ref);

    if (nameEmpty && refEmpty) {
        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NoNameRefAttribute);
        return;
    }

    if (topLevel && nameEmpty) {

        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::TopLevelNoNameAttribute);
        return;
    }

    // ------------------------------------------------------------------
    // Check attributes
    // ------------------------------------------------------------------
    unsigned short scope = (topLevel)
        ? GeneralAttributeCheck::E_AttributeGlobal
        : (refEmpty) ? GeneralAttributeCheck::E_AttributeLocal
                     : GeneralAttributeCheck::E_AttributeRef;

    fAttributeCheck.checkAttributes(elem, scope, this, topLevel, fNonXSAttList);

    const XMLCh* defaultVal = getElementAttValue(elem, SchemaSymbols::fgATT_DEFAULT);
    const XMLCh* fixedVal = getElementAttValue(elem, SchemaSymbols::fgATT_FIXED);
    const XMLCh* useVal = getElementAttValue(elem, SchemaSymbols::fgATT_USE);
    const XMLCh* attForm = getElementAttValue(elem, SchemaSymbols::fgATT_FORM);
    const XMLCh* dvType = getElementAttValue(elem, SchemaSymbols::fgATT_TYPE, DatatypeValidator::QName);
    DOMElement* simpleType = checkContent(elem, XUtil::getFirstChildElement(elem), true);
    Janitor<XSAnnotation> janAnnot(fAnnotation);
    bool         badContent = false;

    while (simpleType != 0) {

        const XMLCh* contentName = simpleType->getLocalName();

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

            if (XUtil::getNextSiblingElement(simpleType) != 0) {
                badContent = true;
            }
            break;
        }

        badContent = true;
        simpleType = XUtil::getNextSiblingElement(simpleType);
    }

    if (badContent) {
        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttributeContent,
                          (name) ? name : ref);
    }

    if (defaultVal) {

        if (fixedVal) {

            fixedVal = 0;
            reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeDefaultFixedValue,
                              (name) ? name : ref);
        }

        if ((useVal && *useVal)
            && !XMLString::equals(useVal, SchemaSymbols::fgATTVAL_OPTIONAL)) {

            useVal = 0;
            reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::NotOptionalDefaultAttValue,
                              (name) ? name : ref);
        }
    }

    // processing ref
    if (!refEmpty && !topLevel) {

        // Check ref representation OK - 3.2.3::3.2
        if (attForm || dvType || (simpleType != 0)) {
            reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeRefContentError,
                              (name) ? name : ref);
        }

        processAttributeDeclRef(elem, typeInfo, ref, useVal, defaultVal, fixedVal);
        return;
    }

    if (fScanner->getGenerateSyntheticAnnotations() && !fAnnotation && fNonXSAttList->size())
    {
        fAnnotation = generateSyntheticAnnotation(elem, fNonXSAttList);
        janAnnot.reset(fAnnotation);
    }

    // processing 'name'
    if (!XMLChar1_0::isValidNCName(name, XMLString::stringLen(name))
        || XMLString::equals(name, XMLUni::fgXMLNSString)) {

        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidDeclarationName, SchemaSymbols::fgELT_ATTRIBUTE, name);
        return;
    }

    // Check for duplicate declaration
    const XMLCh* qualified = SchemaSymbols::fgATTVAL_QUALIFIED;
    int uriIndex = fEmptyNamespaceURI;

    if ((fTargetNSURIString && *fTargetNSURIString)
        && (topLevel || XMLString::equals(attForm, qualified)
            || ((fSchemaInfo->getElemAttrDefaultQualified() & Attr_Def_Qualified)
                && (!attForm || !*attForm)))) {
        uriIndex = fTargetNSURI;
    }

    // make sure that attribute namespace is not xsi uri
    if (XMLString::equals(fTargetNSURIString, SchemaSymbols::fgURI_XSI)) {

        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidAttTNS, name);
        return;
    }

    if (typeInfo && typeInfo->getAttDef(name, uriIndex) != 0) {

        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name);
        return;
    }
    else if (fCurrentAttGroupInfo && fCurrentAttGroupInfo->containsAttribute(name, uriIndex)) {

        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::DuplicateAttribute, name);
        return;
    }

    DatatypeValidator*  dv = 0;
    XMLAttDef::AttTypes attType = XMLAttDef::Simple;
    SchemaInfo* saveInfo = fSchemaInfo;

    if (simpleType != 0) {

        if (dvType && *dvType) {
            reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttributeWithTypeAndSimpleType, name);
        }

        dv = traverseSimpleTypeDecl(simpleType, false);
    }
    else if (!dvType || !*dvType) {
        dv = fDatatypeRegistry->getDatatypeValidator(SchemaSymbols::fgDT_ANYSIMPLETYPE);
    }
    else {

        checkEnumerationRequiredNotation(elem, name, dvType);

        const XMLCh* localPart = getLocalPart(dvType);
        const XMLCh* prefix = getPrefix(dvType);
        const XMLCh* typeURI = resolvePrefixToURI(elem, prefix);
        DatatypeValidator*  dvBack = 0;

        if (XMLString::equals(typeURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
            dv = fDatatypeRegistry->getDatatypeValidator(localPart);
            dvBack = dv;
        }
        else { //isn't of the schema for schemas namespace...

            dv = getAttrDatatypeValidatorNS(elem, localPart, typeURI);
            dvBack = dv;

            while(dv != 0 && !XMLString::equals(dv->getTypeUri(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
                dv = dv->getBaseValidator();
            }

            if(dv)
                localPart = dv->getTypeLocalName();
        }

        if(dv) {
            if (XMLString::equals(localPart,XMLUni::fgIDString)) {
                attType = XMLAttDef::ID;
            }
            else if (XMLString::equals(localPart,XMLUni::fgIDRefString)) {
                attType = XMLAttDef::IDRef;
            }
            else if (XMLString::equals(localPart,XMLUni::fgIDRefsString)) {
                attType = XMLAttDef::IDRefs;
            }
            else if (XMLString::equals(localPart,XMLUni::fgEntityString)) {
                attType = XMLAttDef::Entity;
            }
            else if (XMLString::equals(localPart,XMLUni::fgEntitiesString)) {
                attType = XMLAttDef::Entities;
            }
            else if (XMLString::equals(localPart,XMLUni::fgNmTokenString)) {
                attType = XMLAttDef::NmToken;
            }
            else if (XMLString::equals(localPart,XMLUni::fgNmTokensString)) {
                attType = XMLAttDef::NmTokens;
            }
            else if (XMLString::equals(localPart,XMLUni::fgNotationString)) {
                attType = XMLAttDef::Notation;
            }
            else {
                attType = XMLAttDef::Simple;
            }
        }
        else
            attType = XMLAttDef::Simple;

        dv = dvBack;

        if (!dv) {
            reportSchemaError
            (
                elem
                , XMLUni::fgXMLErrDomain
                , XMLErrs::AttributeSimpleTypeNotFound
                , typeURI
                , localPart
                , name
            );
        }
    }

    // restore schema information, if necessary
    fSchemaInfo = saveInfo;

    bool required = false;
    bool prohibited = false;

    if (useVal && *useVal) {

        if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_REQUIRED)) {
            required = true;
        }
        else if (XMLString::equals(useVal, SchemaSymbols::fgATTVAL_PROHIBITED)) {
            prohibited = true;
        }
    }

    // validate fixed/default values
    const XMLCh* valueToCheck = defaultVal ? defaultVal : fixedVal;
    bool  ofTypeID = (dv && dv->getType() == DatatypeValidator::ID);

    if (attType == XMLAttDef::Simple && dv && valueToCheck) {

        short wsFacet = dv->getWSFacet();
        if((wsFacet == DatatypeValidator::REPLACE && !XMLString::isWSReplaced(valueToCheck)) ||
           (wsFacet == DatatypeValidator::COLLAPSE && !XMLString::isWSCollapsed(valueToCheck)))
        {
            XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager);
            ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager);
            if(wsFacet == DatatypeValidator::REPLACE)
                XMLString::replaceWS(normalizedValue, fMemoryManager);
            else if(wsFacet == DatatypeValidator::COLLAPSE)
                XMLString::collapseWS(normalizedValue, fMemoryManager);
            valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
        }
        try {
            dv->validate(valueToCheck
                      , fSchemaInfo->getValidationContext()
                      , fMemoryManager);
        }
        catch (const XMLException& excep) {
            reportSchemaError(elem, excep);
        }
        catch(const OutOfMemoryException&)
        {
            throw;
        }
        catch(...) {
            reportSchemaError(elem, XMLUni::fgValidityDomain, XMLValid::DatatypeValidationFailure, valueToCheck);
        }
    }
    else if((attType == XMLAttDef::NmTokens || attType==XMLAttDef::IDRefs || attType==XMLAttDef::Entities) &&
            valueToCheck && !XMLString::isWSCollapsed(valueToCheck))
    {
        XMLCh* normalizedValue=XMLString::replicate(valueToCheck, fMemoryManager);
        ArrayJanitor<XMLCh> tempURIName(normalizedValue, fMemoryManager);
        XMLString::collapseWS(normalizedValue, fMemoryManager);
        valueToCheck=fStringPool->getValueForId(fStringPool->addOrFind(normalizedValue));
    }

    if (ofTypeID && valueToCheck) {
        reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect3, name);
    }

    // check for multiple attributes with type derived from ID
    if (!topLevel && ofTypeID) {

        if (fCurrentAttGroupInfo) {

            if (fCurrentAttGroupInfo->containsTypeWithId()) {

                reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttGrpPropCorrect3, name);
                return;
            }

            fCurrentAttGroupInfo->setTypeWithId(true);
        }
        else {

            if (typeInfo->containsAttWithTypeId()) {

                reportSchemaError(elem, XMLUni::fgXMLErrDomain, XMLErrs::AttDeclPropCorrect5, name);
                return;
            }

            typeInfo->setAttWithTypeId(true);
        }
    }

    // create SchemaAttDef
    SchemaAttDef* attDef = new (fGrammarPoolMemoryManager) SchemaAttDef
    (
        XMLUni::fgZeroLenString
        , name
        , uriIndex
        , attType
        , XMLAttDef::Implied
        , fGrammarPoolMemoryManager
    );

    attDef->setDatatypeValidator(dv);

    if (prohibited) {
        attDef->setDefaultType(XMLAttDef::Prohibited);
    }
    else if (required) {

        if (fixedVal) {
            attDef->setDefaultType(XMLAttDef::Required_And_Fixed);
        }
        else {
            attDef->setDefaultType(XMLAttDef::Required);
        }
    }
    else {

        if (fixedVal) {
            attDef->setDefaultType(XMLAttDef::Fixed);
        }
        else if (defaultVal) {
            attDef->setDefaultType(XMLAttDef::Default);
        }
    }

    if (valueToCheck) {
        attDef->setValue(valueToCheck);
    }

    if (!janAnnot.isDataNull())
        fSchemaGrammar->putAnnotation(attDef, janAnnot.release());

    if (topLevel)
    {
        fAttributeDeclRegistry->put((void*) fStringPool->getValueForId(fStringPool->addOrFind(name)), attDef);
        attDef->setPSVIScope(PSVIDefs::SCP_GLOBAL);
    }
    else
    {
        if (typeInfo)
        {
            typeInfo->addAttDef(attDef);
            if (!fCurrentAttGroupInfo)
                attDef->setPSVIScope(PSVIDefs::SCP_LOCAL);
        }

        if (fCurrentAttGroupInfo) {
            fCurrentAttGroupInfo->addAttDef(attDef, (typeInfo != 0));
        }
    }
}