void IGXMLScanner::scanEndTag()

in src/xercesc/internal/IGXMLScanner.cpp [927:1225]


void IGXMLScanner::scanEndTag(bool& gotData)
{
    //  Assume we will still have data until proven otherwise. It will only
    //  ever be false if this is the end of the root element.
    gotData = true;

    //  Check if the element stack is empty. If so, then this is an unbalanced
    //  element (i.e. more ends than starts, perhaps because of bad text
    //  causing one to be skipped.)
    if (fElemStack.isEmpty())
    {
        emitError(XMLErrs::MoreEndThanStartTags);
        fReaderMgr.skipPastChar(chCloseAngle);
        ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd, fMemoryManager);
    }

    //  Pop the stack of the element we are supposed to be ending. Remember
    //  that we don't own this. The stack just keeps them and reuses them.
    unsigned int uriId = (fDoNamespaces)
        ? fElemStack.getCurrentURI() : fEmptyNamespaceId;

    // these get initialized below
    const ElemStack::StackElem* topElem = 0;
    const XMLCh *elemName = 0;

    // Make sure that its the end of the element that we expect
    // special case for schema validation, whose element decls,
    // obviously don't contain prefix information
    if(fGrammarType == Grammar::SchemaGrammarType)
    {
        elemName = fElemStack.getCurrentSchemaElemName();
        topElem = fElemStack.topElement();
    }
    else
    {
        topElem = fElemStack.topElement();
        elemName = topElem->fThisElement->getFullName();
    }
    if (!fReaderMgr.skippedStringLong(elemName))
    {
        emitError
        (
            XMLErrs::ExpectedEndOfTagX
            , elemName
        );
        fReaderMgr.skipPastChar(chCloseAngle);
        fElemStack.popTop();
        return;
    }

    // Make sure we are back on the same reader as where we started
    if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
        emitError(XMLErrs::PartialTagMarkupError);

    // Skip optional whitespace
    fReaderMgr.skipPastSpaces();

    // Make sure we find the closing bracket
    if (!fReaderMgr.skippedChar(chCloseAngle))
    {
        emitError
        (
            XMLErrs::UnterminatedEndTag
            , topElem->fThisElement->getFullName()
        );
    }

    if (fGrammarType == Grammar::SchemaGrammarType)
    {
        // reset error occurred
        fPSVIElemContext.fErrorOccurred = fErrorStack->pop();
        if (fValidate && topElem->fThisElement->isDeclared())
        {
            fPSVIElemContext.fCurrentTypeInfo = ((SchemaValidator*) fValidator)->getCurrentTypeInfo();
            if(!fPSVIElemContext.fCurrentTypeInfo)
                fPSVIElemContext.fCurrentDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
            else
                fPSVIElemContext.fCurrentDV = 0;
            if(fPSVIHandler)
            {
                fPSVIElemContext.fNormalizedValue = ((SchemaValidator*) fValidator)->getNormalizedValue();

                if (XMLString::equals(fPSVIElemContext.fNormalizedValue, XMLUni::fgZeroLenString))
                    fPSVIElemContext.fNormalizedValue = 0;
            }
        }
        else
        {
            fPSVIElemContext.fCurrentDV = 0;
            fPSVIElemContext.fCurrentTypeInfo = 0;
            fPSVIElemContext.fNormalizedValue = 0;
        }
    }

    //  If validation is enabled, then lets pass him the list of children and
    //  this element and let him validate it.
    DatatypeValidator* psviMemberType = 0;
    if (fValidate)
    {

       //
       // XML1.0-3rd
       // Validity Constraint:
       // The declaration matches EMPTY and the element has no content (not even
       // entity references, comments, PIs or white space).
       //
       if ( (fGrammarType == Grammar::DTDGrammarType) &&
            (topElem->fCommentOrPISeen)               &&
            (((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Empty))
       {
           fValidator->emitError
               (
               XMLValid::EmptyElemHasContent
               , topElem->fThisElement->getFullName()
               );
       }

       //
       // XML1.0-3rd
       // Validity Constraint:
       //
       // The declaration matches children and the sequence of child elements
       // belongs to the language generated by the regular expression in the
       // content model, with optional white space, comments and PIs
       // (i.e. markup matching production [27] Misc) between the start-tag and
       // the first child element, between child elements, or between the last
       // child element and the end-tag.
       //
       // Note that
       //    a CDATA section containing only white space or
       //    a reference to an entity whose replacement text is character references
       //       expanding to white space do not match the nonterminal S, and hence
       //       cannot appear in these positions; however,
       //    a reference to an internal entity with a literal value consisting
       //       of character references expanding to white space does match S,
       //       since its replacement text is the white space resulting from expansion
       //       of the character references.
       //
       if ( (fGrammarType == Grammar::DTDGrammarType)  &&
            (topElem->fReferenceEscaped)               &&
            (((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Children))
       {
           fValidator->emitError
               (
               XMLValid::ElemChildrenHasInvalidWS
               , topElem->fThisElement->getFullName()
               );
       }
        XMLSize_t failure;
        bool res = fValidator->checkContent
        (
            topElem->fThisElement
            , topElem->fChildren
            , topElem->fChildCount
            , &failure
        );

        if (!res)
        {
            //  One of the elements is not valid for the content. NOTE that
            //  if no children were provided but the content model requires
            //  them, it comes back with a zero value. But we cannot use that
            //  to index the child array in this case, and have to put out a
            //  special message.
            if (!topElem->fChildCount)
            {
                fValidator->emitError
                (
                    XMLValid::EmptyNotValidForContent
                    , topElem->fThisElement->getFormattedContentModel()
                );
            }
            else if (failure >= topElem->fChildCount)
            {
                fValidator->emitError
                (
                    XMLValid::NotEnoughElemsForCM
                    , topElem->fThisElement->getFormattedContentModel()
                );
            }
            else
            {
                fValidator->emitError
                (
                    XMLValid::ElementNotValidForContent
                    , topElem->fChildren[failure]->getRawName()
                    , topElem->fThisElement->getFormattedContentModel()
                );
            }
        }


        if (fGrammarType == Grammar::SchemaGrammarType) {
            if (((SchemaValidator*) fValidator)->getErrorOccurred())
                fPSVIElemContext.fErrorOccurred = true;
            else if (fPSVIElemContext.fCurrentDV && fPSVIElemContext.fCurrentDV->getType() == DatatypeValidator::Union)
                psviMemberType = fValidationContext->getValidatingMemberType();

            if (fPSVIHandler)
            {
                fPSVIElemContext.fIsSpecified = ((SchemaValidator*) fValidator)->getIsElemSpecified();
                if(fPSVIElemContext.fIsSpecified)
                    fPSVIElemContext.fNormalizedValue = ((SchemaElementDecl *)topElem->fThisElement)->getDefaultValue();
            }

            // call matchers and de-activate context
            if (toCheckIdentityConstraint())
            {
                fICHandler->deactivateContext
                             (
                              (SchemaElementDecl *) topElem->fThisElement
                            , fContent.getRawBuffer()
                            , fValidationContext
                            , fPSVIElemContext.fCurrentDV
                             );
            }

        }
    }

    // QName dv needed topElem to resolve URIs on the checkContent
    fElemStack.popTop();

    // See if it was the root element, to avoid multiple calls below
    const bool isRoot = fElemStack.isEmpty();

    if (fGrammarType == Grammar::SchemaGrammarType)
    {
        if (fPSVIHandler)
        {
            endElementPSVI(
                (SchemaElementDecl*)topElem->fThisElement, psviMemberType);
        }
        // now we can reset the datatype buffer, since the
        // application has had a chance to copy the characters somewhere else
        ((SchemaValidator *)fValidator)->clearDatatypeBuffer();
    }

    // If we have a doc handler, tell it about the end tag
    if (fDocHandler)
    {
        if (fGrammarType == Grammar::SchemaGrammarType) {
            if (topElem->fPrefixColonPos != -1)
                fPrefixBuf.set(elemName, topElem->fPrefixColonPos);
            else
                fPrefixBuf.reset();
        }
        else {
            fPrefixBuf.set(topElem->fThisElement->getElementName()->getPrefix());
        }
        fDocHandler->endElement
        (
            *topElem->fThisElement
            , uriId
            , isRoot
            , fPrefixBuf.getRawBuffer()
        );
    }

    if (fGrammarType == Grammar::SchemaGrammarType) {
        if (!isRoot)
        {
            // update error information
            fErrorStack->push((fErrorStack->size() && fErrorStack->pop()) || fPSVIElemContext.fErrorOccurred);


        }
    }

    // If this was the root, then done with content
    gotData = !isRoot;

    if (gotData) {
        if (fDoNamespaces) {
            // Restore the grammar
            fGrammar = fElemStack.getCurrentGrammar();
            fGrammarType = fGrammar->getGrammarType();
            if (fGrammarType == Grammar::SchemaGrammarType && !fValidator->handlesSchema()) {
                if (fValidatorFromUser)
                    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoSchemaValidator, fMemoryManager);
                else {
                    fValidator = fSchemaValidator;
                }
            }
            else if (fGrammarType == Grammar::DTDGrammarType && !fValidator->handlesDTD()) {
                if (fValidatorFromUser)
                    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
                else {
                    fValidator = fDTDValidator;
                }
            }

            fValidator->setGrammar(fGrammar);
        }

        // Restore the validation flag
        fValidate = fElemStack.getValidationFlag();
    }
}