bool SchemaValidator::checkContent()

in src/xercesc/validators/schema/SchemaValidator.cpp [86:315]


bool SchemaValidator::checkContent (XMLElementDecl* const elemDecl
                                 , QName** const          children
                                 , XMLSize_t              childCount
                                 , XMLSize_t*             indexFailingChild)
{
    fErrorOccurred = false;
    fElemIsSpecified = false;

    //
    //  Look up the element id in our element decl pool. This will get us
    //  the element decl in our own way of looking at them.
    //
    if (!elemDecl)
        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Val_InvalidElemId, fMemoryManager);

    //
    //  Get the content spec type of this element. This will tell us what
    //  to do to validate it.
    //
    // the top of the type stack always knows best...
    ComplexTypeInfo* currType = fTypeStack->pop();

    const SchemaElementDecl::ModelTypes modelType = (currType)
            ? (SchemaElementDecl::ModelTypes)(currType->getContentType())
            : ((SchemaElementDecl*)elemDecl)->getModelType();

    if (modelType == SchemaElementDecl::Empty  ||
        modelType == SchemaElementDecl::ElementOnlyEmpty)
    {
        //
        //  We can do this one here. It cannot have any children. If it does
        //  we return 0 as the index of the first bad child.
        //
        if (childCount) {
            fErrorOccurred = true;
            *indexFailingChild=0;
            return false;
        }
    }
    else if ((modelType == SchemaElementDecl::Mixed_Simple)
         ||  (modelType == SchemaElementDecl::Mixed_Complex)
         ||  (modelType == SchemaElementDecl::Children))
    {
        // if nillable, it's an error to have value
        // XML Schema REC: Validation Rule: Element Locally Valid (Element)
        // 3.2.1 The element information item must have no
        // character or element information item [children].
        //
        if (fNil) {
            if (childCount > 0 || !XMLString::equals(fDatatypeBuffer.getRawBuffer(), XMLUni::fgZeroLenString)) {
                emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName());
                fErrorOccurred = true;
            }
        }
        else {
            // Get the element's content model or fault it in
            XMLContentModel* elemCM = (currType)
                    ? currType->getContentModel()
                    : ((SchemaElementDecl*)elemDecl)->getContentModel();

            // Ask it to validate and return its return
            unsigned int emptyNS = getScanner()->getEmptyNamespaceId();
            bool result = elemCM->validateContent(children, childCount, emptyNS, indexFailingChild, getScanner()->getMemoryManager());
            if (!result) {
                result = elemCM->validateContentSpecial(children
                                                      , childCount
                                                      , emptyNS
                                                      , fGrammarResolver
                                                      , fGrammarResolver->getStringPool()
                                                      , indexFailingChild
													  , getScanner()->getMemoryManager());
            }

            if(!result) {
                fErrorOccurred = true;
            }

            return result;
        }
    }
    else if (modelType == SchemaElementDecl::Simple || modelType == SchemaElementDecl::Any)
    {
        // Normally for SchemaElementDecl::Any, We pass no judgement on it and anything goes
        // but if there is a fXsiTypeValidator, we need to use it for validation
        if (modelType == SchemaElementDecl::Simple && childCount > 0) {
            emitError(XMLValid::SimpleTypeHasChild, elemDecl->getFullName());
            fErrorOccurred = true;
        }
        else
        {
            XMLCh* value = fDatatypeBuffer.getRawBuffer();
            XMLCh* elemDefaultValue = ((SchemaElementDecl*) elemDecl)->getDefaultValue();

            if (fNil)
            {
                if ((!XMLString::equals(value, XMLUni::fgZeroLenString))
                    || elemDefaultValue)
                {
                    emitError(XMLValid::NilAttrNotEmpty, elemDecl->getFullName());
                    fErrorOccurred = true;
                }
            }
			else if (fCurrentDatatypeValidator)
            {
                DatatypeValidator::ValidatorType eleDefDVType = fCurrentDatatypeValidator->getType();
                bool validateCanonical = false;
                if (eleDefDVType == DatatypeValidator::NOTATION)
                {
                    // if notation, need to bind URI to notation first
                    if (!fNotationBuf)
                        fNotationBuf = new (fMemoryManager) XMLBuffer(1023, fMemoryManager);

                    //  Make sure that this value maps to one of the
                    //  notation values in the enumList parameter. We don't have to
                    //  look it up in the notation pool (if a notation) because we
                    //  will look up the enumerated values themselves. If they are in
                    //  the notation pool (after the Grammar is parsed), then obviously
                    //  this value will be legal since it matches one of them.
                    int colonPos = -1;
                    unsigned int uriId = getScanner()->resolveQName(value, *fNotationBuf, ElemStack::Mode_Element, colonPos);

                    const XMLCh* uriText = getScanner()->getURIText(uriId);
                    if (uriText && *uriText) {
                        fNotationBuf->set(uriText);
                        fNotationBuf->append(chColon);
                        fNotationBuf->append(&value[colonPos + 1]);
                        value = fNotationBuf->getRawBuffer();
                    }
                }

                if (elemDefaultValue)
                {
                    if (XMLString::equals(value, XMLUni::fgZeroLenString))
                    {
                        fElemIsSpecified = true;
                        // if this element didn't specified any value
                        // use default value
                        if (getScanner()->getDocHandler())
                            getScanner()->getDocHandler()->docCharacters(elemDefaultValue, XMLString::stringLen(elemDefaultValue), false);

                        // Normally for default value, it has been validated already during TraverseSchema
                        // But if there was a xsi:type and this validator is fXsiTypeValidator,
                        // need to validate again
                        // we determine this if the current content dataype validator
                        // is neither the one in the element nor the one in the current
                        // complex type (if any)
                        if ((fCurrentDatatypeValidator != ((SchemaElementDecl*)elemDecl)->getDatatypeValidator())
                            && (!fTypeStack->peek() || (fCurrentDatatypeValidator != fTypeStack->peek()->getDatatypeValidator()))) {
                            value = elemDefaultValue;
                            validateCanonical = true;
                        }
                        else
                            value = 0;
                    }
                    else
                    {
                        // this element has specified some value
                        // if the flag is FIXED, then this value must be same as default value
                        if ((((SchemaElementDecl*)elemDecl)->getMiscFlags() & SchemaSymbols::XSD_FIXED) != 0)
                        {
                            if (fCurrentDatatypeValidator->compare(value, elemDefaultValue, fMemoryManager) != 0 )
                            {
                                emitError(XMLValid::FixedDifferentFromActual, elemDecl->getFullName());
                                fErrorOccurred = true;
                            }
                        }
                    }
                }

                if ((!fErrorOccurred) && value)
                {
                    try {
                        fCurrentDatatypeValidator->validate(value, getScanner()->getValidationContext(), fMemoryManager);
                        if (validateCanonical) {
                            XMLCh* canonical = (XMLCh*) fCurrentDatatypeValidator->getCanonicalRepresentation(value, fMemoryManager);
                            ArrayJanitor<XMLCh> tempCanonical(canonical, fMemoryManager);
                            fCurrentDatatypeValidator->validate(canonical, getScanner()->getValidationContext(), fMemoryManager);
                        }
                    }
                    catch (XMLException& idve)
                    {
                        emitError (XMLValid::DatatypeError, idve.getCode(), idve.getMessage());
                        fErrorOccurred = true;
                    }
                    catch(const OutOfMemoryException&) {
                        throw;
                    }
                    catch (...)
                    {
                        emitError(XMLValid::GenericError);
                        throw;
                    }
                }
            }
            else if (modelType == SchemaElementDecl::Simple)
            {
                emitError(XMLValid::NoDatatypeValidatorForSimpleType, elemDecl->getFullName());
                fErrorOccurred = true;
            }
            // modelType is any
            else if (elemDefaultValue)
            {
                if (XMLString::equals(value, XMLUni::fgZeroLenString))
                {
                    fElemIsSpecified = true;
                    // if this element didn't specified any value
                    // use default value
                    if (getScanner()->getDocHandler()) {
                        getScanner()->getDocHandler()->docCharacters(elemDefaultValue, XMLString::stringLen(elemDefaultValue), false);
                    }
                }
            }
        }
    }
    else
    {
        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMType, fMemoryManager);
    }

    // must rely on scanner to clear fDatatypeBuffer
    // since it may need to query its contents after this method completes
    fNil = false;
    fNilFound = false;
    fTrailing=false;
    fSeenNonWhiteSpace = false;
    fCurrentDatatypeValidator = 0;

    // Went ok, so return success
    return true;
}