in src/xercesc/validators/schema/SchemaValidator.cpp [531:754]
void SchemaValidator::validateElement(const XMLElementDecl* elemDef)
{
ComplexTypeInfo* elemTypeInfo = ((SchemaElementDecl*)elemDef)->getComplexTypeInfo();
fTypeStack->push(elemTypeInfo);
fCurrentDatatypeValidator = (elemTypeInfo)
? elemTypeInfo->getDatatypeValidator()
: ((SchemaElementDecl*)elemDef)->getDatatypeValidator();
fErrorOccurred = false;
if (fXsiType) {
// handle "xsi:type" right here
DatatypeValidator *xsiTypeDV = 0;
unsigned int uri = fXsiType->getURI();
const XMLCh* localPart = fXsiType->getLocalPart();
if (uri != XMLElementDecl::fgInvalidElemId &&
uri != XMLElementDecl::fgPCDataElemId &&
uri != XMLContentModel::gEpsilonFakeId &&
uri != XMLContentModel::gEOCFakeId) {
// retrieve Grammar for the uri
const XMLCh* uriStr = getScanner()->getURIText(uri);
SchemaGrammar* sGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(uriStr);
if (!sGrammar) {
// Check built-in simple types
if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
xsiTypeDV = fGrammarResolver->getDatatypeValidator(uriStr, localPart);
if (!xsiTypeDV) {
emitError(XMLValid::BadXsiType, fXsiType->getRawName());
fErrorOccurred = true;
}
else {
if (elemTypeInfo || (fCurrentDatatypeValidator
&& !fCurrentDatatypeValidator->isSubstitutableBy(xsiTypeDV))) {
// the type is not derived from ancestor
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
else if(fCurrentDatatypeValidator != xsiTypeDV)
{
// the type is derived from ancestor
if ((((SchemaElementDecl*)elemDef)->getBlockSet() & SchemaSymbols::XSD_RESTRICTION) != 0) {
emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
fErrorOccurred = true;
}
if (elemDef->hasAttDefs()) {
// if we have an attribute but xsi:type's type is simple, we have a problem...
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
}
fCurrentDatatypeValidator = xsiTypeDV;
}
}
else {
// Grammar not found
emitError(XMLValid::GrammarNotFound, uriStr);
fErrorOccurred = true;
}
}
else if (sGrammar->getGrammarType() != Grammar::SchemaGrammarType) {
emitError(XMLValid::GrammarNotFound, uriStr);
fErrorOccurred = true;
}
else {
// retrieve complexType registry and DatatypeValidator registry
RefHashTableOf<ComplexTypeInfo>* complexTypeRegistry = sGrammar->getComplexTypeRegistry();
if (!complexTypeRegistry) {
emitError(XMLValid::BadXsiType, fXsiType->getRawName());
fErrorOccurred = true;
}
else {
// retrieve the typeInfo specified in xsi:type
XMLBuffer aBuffer(1023, fMemoryManager);
aBuffer.set(uriStr);
aBuffer.append(chComma);
aBuffer.append(localPart);
ComplexTypeInfo* typeInfo = complexTypeRegistry->get(aBuffer.getRawBuffer());
if (typeInfo) {
// typeInfo is found
if (typeInfo->getAbstract()) {
emitError(XMLValid::NoAbstractInXsiType, aBuffer.getRawBuffer());
fErrorOccurred = true;
}
else
{
if (elemTypeInfo)
{
ComplexTypeInfo* tempType = typeInfo;
while (tempType) {
if (tempType == elemTypeInfo)
break;
tempType = tempType->getBaseComplexTypeInfo();
}
if (!tempType) {
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
else if(elemTypeInfo != typeInfo) {
// perform the check on the entire inheritance chain
ComplexTypeInfo* tempType = typeInfo;
while (tempType) {
if (tempType == elemTypeInfo)
break;
int derivationMethod = tempType->getDerivedBy();
if ((((SchemaElementDecl*)elemDef)->getBlockSet() & derivationMethod) != 0) {
emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
fErrorOccurred = true;
}
if ((elemTypeInfo->getBlockSet() & derivationMethod) != 0) {
emitError(XMLValid::TypeNoSubforBlock, elemTypeInfo->getTypeName());
fErrorOccurred = true;
}
tempType = tempType->getBaseComplexTypeInfo();
}
}
}
else
{
// if the original type is a simple type, check derivation ok.
if (fCurrentDatatypeValidator && !fCurrentDatatypeValidator->isSubstitutableBy(typeInfo->getDatatypeValidator())) {
// the type is not derived from ancestor
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
}
if (!fErrorOccurred)
{
fTypeStack->pop();
fTypeStack->push(typeInfo);
fCurrentDatatypeValidator = typeInfo->getDatatypeValidator();
}
}
}
else
{
// typeInfo not found
xsiTypeDV = fGrammarResolver->getDatatypeValidator(uriStr, localPart);
if (!xsiTypeDV) {
emitError(XMLValid::BadXsiType, fXsiType->getRawName());
fErrorOccurred = true;
}
else {
if (fCurrentDatatypeValidator && !fCurrentDatatypeValidator->isSubstitutableBy(xsiTypeDV)) {
// the type is not derived from ancestor
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
else if(fCurrentDatatypeValidator != xsiTypeDV)
{
DatatypeValidator::ValidatorType derivedType=xsiTypeDV->getType();
if((derivedType == DatatypeValidator::List || derivedType == DatatypeValidator::Union) && fCurrentDatatypeValidator==0)
{
// the substitution is always allowed if the type is list or union and the base type was xs:anySimpleType
}
else
{
// the type is derived from ancestor
if ((((SchemaElementDecl*)elemDef)->getBlockSet() & SchemaSymbols::XSD_RESTRICTION) != 0) {
emitError(XMLValid::ElemNoSubforBlock, elemDef->getFullName());
fErrorOccurred = true;
}
if (elemDef->hasAttDefs()) {
// if we have an attribute but xsi:type's type is simple, we have a problem...
emitError(XMLValid::NonDerivedXsiType, fXsiType->getRawName(), elemDef->getFullName());
fErrorOccurred = true;
}
}
}
fCurrentDatatypeValidator = xsiTypeDV;
}
}
}
}
}
delete fXsiType;
fXsiType = 0;
}
else {
//
// xsi:type was not specified...
// If the corresponding type is abstract, detect an error
//
if (elemTypeInfo && elemTypeInfo->getAbstract()) {
emitError(XMLValid::NoUseAbstractType, elemDef->getFullName());
fErrorOccurred = true;
}
}
//
// Check whether this element is abstract. If so, an error
//
int miscFlags = ((SchemaElementDecl*)elemDef)->getMiscFlags();
if ((miscFlags & SchemaSymbols::XSD_ABSTRACT) != 0) {
emitError(XMLValid::NoDirectUseAbstractElement, elemDef->getFullName());
fErrorOccurred = true;
}
//
// Check whether this element allows Nillable
//
if (fNilFound && (miscFlags & SchemaSymbols::XSD_NILLABLE) == 0 ) {
fNil = false;
fNilFound = false;
emitError(XMLValid::NillNotAllowed, elemDef->getFullName());
fErrorOccurred = true;
}
fDatatypeBuffer.reset();
fTrailing = false;
fSeenNonWhiteSpace = false;
fSeenId = false;
}