in src/xercesc/internal/SGXMLScanner.cpp [842:1052]
void SGXMLScanner::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;
// Make sure that its the end of the element that we expect
const XMLCh *elemName = fElemStack.getCurrentSchemaElemName();
const ElemStack::StackElem* topElem = fElemStack.topElement();
if (!fReaderMgr.skippedStringLong(elemName))
{
emitError
(
XMLErrs::ExpectedEndOfTagX
, elemName
);
fReaderMgr.skipPastChar(chCloseAngle);
fElemStack.popTop();
return;
}
fPSVIElemContext.fErrorOccurred = fErrorStack->pop();
// 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 (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)
{
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()
);
}
}
// update PSVI info
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 (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 (!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) {
// Restore the grammar
fGrammar = fElemStack.getCurrentGrammar();
fGrammarType = fGrammar->getGrammarType();
fValidator->setGrammar(fGrammar);
// Restore the validation flag
fValidate = fElemStack.getValidationFlag();
}
}