in src/xercesc/validators/schema/TraverseSchema.cpp [6167:6471]
void TraverseSchema::processComplexContent(const DOMElement* const ctElem,
const XMLCh* const typeName,
const DOMElement* const childElem,
ComplexTypeInfo* const typeInfo,
const XMLCh* const baseLocalPart,
const bool isMixed,
const bool isBaseAnyType) {
NamespaceScopeManager nsMgr(childElem, fSchemaInfo, this);
Janitor<ContentSpecNode> specNodeJan(0);
ContentSpecNode* specNode = specNodeJan.get();
const DOMElement* attrNode = 0;
int typeDerivedBy = typeInfo->getDerivedBy();
ComplexTypeInfo* baseTypeInfo = typeInfo->getBaseComplexTypeInfo();
int baseContentType = (baseTypeInfo) ? baseTypeInfo->getContentType() : SchemaElementDecl::Empty;
if (baseTypeInfo) {
if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {
// check to see if the baseType permits derivation by restriction
if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByRestriction,
baseLocalPart);
throw TraverseSchema::InvalidComplexTypeInfo;
}
}
else {
// check to see if the baseType permits derivation by extension
if((baseTypeInfo->getFinalSet() & typeDerivedBy) != 0) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::ForbiddenDerivationByExtension, baseLocalPart);
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
}
processElements(ctElem, baseTypeInfo, typeInfo);
}
}
bool effectiveContent_hasChild = false;
if (childElem != 0) {
fCircularCheckIndex = fCurrentTypeNameStack->size();
// --------------------------------------------------------------------
// GROUP, ALL, SEQUENCE or CHOICE, followed by attributes, if specified.
// Note that it's possible that only attributes are specified.
// --------------------------------------------------------------------
const XMLCh* childName = childElem->getLocalName();
if (XMLString::equals(childName, SchemaSymbols::fgELT_GROUP)) {
XercesGroupInfo* grpInfo = traverseGroupDecl(childElem, false);
if (grpInfo) {
ContentSpecNode* const groupSpecNode = grpInfo->getContentSpec();
if (groupSpecNode) {
int contentContext = groupSpecNode->hasAllContent() ? Group_Ref_With_All : Not_All_Context;
specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*groupSpecNode));
specNode = specNodeJan.get();
checkMinMax(specNode, childElem, contentContext);
}
}
attrNode = XUtil::getNextSiblingElement(childElem);
}
else if (XMLString::equals(childName, SchemaSymbols::fgELT_SEQUENCE)) {
specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Sequence, effectiveContent_hasChild));
specNode = specNodeJan.get();
checkMinMax(specNode, childElem);
attrNode = XUtil::getNextSiblingElement(childElem);
}
else if (XMLString::equals(childName, SchemaSymbols::fgELT_CHOICE)) {
specNodeJan.reset(traverseChoiceSequence(childElem, ContentSpecNode::Choice, effectiveContent_hasChild));
specNode = specNodeJan.get();
int minOccurs = checkMinMax(specNode, childElem);
if (!effectiveContent_hasChild && minOccurs != 0) {
effectiveContent_hasChild = true;
}
attrNode = XUtil::getNextSiblingElement(childElem);
}
else if (XMLString::equals(childName, SchemaSymbols::fgELT_ALL)) {
specNodeJan.reset(traverseAll(childElem, effectiveContent_hasChild));
specNode = specNodeJan.get();
checkMinMax(specNode, childElem, All_Group);
attrNode = XUtil::getNextSiblingElement(childElem);
}
else if (isAttrOrAttrGroup(childElem)) {
// reset the contentType
typeInfo->setContentType(SchemaElementDecl::Any);
attrNode = childElem;
}
else {
reportSchemaError(childElem, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType, childName);
}
}
typeInfo->setContentSpec(specNode);
typeInfo->setAdoptContentSpec(true);
specNodeJan.release();
bool specNodeWasNull = false;
// -----------------------------------------------------------------------
// Merge in information from base, if it exists
// -----------------------------------------------------------------------
if (baseTypeInfo) {
ContentSpecNode* baseSpecNode = baseTypeInfo->getContentSpec();
if (typeDerivedBy == SchemaSymbols::XSD_RESTRICTION) {
//check derivation valid - content type is empty (5.2)
if (!typeInfo->getContentSpec()) {
if (baseContentType != SchemaElementDecl::Empty
&& !emptiableParticle(baseSpecNode)) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::EmptyComplexRestrictionDerivation);
}
}
// Delay particle constraint checking (5.3) until we have processed
// the whole schema.
}
else {
// Compose the final content model by concatenating the base and
// the current in sequence
if (!specNode) {
specNodeWasNull = true;
if (isMixed) {
if (baseSpecNode && baseSpecNode->hasAllContent()) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
}
}
if (baseSpecNode) {
specNodeJan.reset(new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode));
specNode = specNodeJan.get();
typeInfo->setContentSpec(specNode);
typeInfo->setAdoptContentSpec(true);
specNodeJan.release();
}
}
else if (baseSpecNode) {
if (specNode->hasAllContent() || baseSpecNode->hasAllContent()) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::NotAllContent);
throw TraverseSchema::InvalidComplexTypeInfo; // REVISIT - should we continue
}
// Check for derivation valid (extension) - 1.4.3.2.2.1
if ((isMixed && baseContentType == SchemaElementDecl::Children)
|| (!isMixed && baseContentType != SchemaElementDecl::Children)) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
}
typeInfo->setAdoptContentSpec(false);
typeInfo->setContentSpec
(
new (fGrammarPoolMemoryManager) ContentSpecNode
(
ContentSpecNode::ModelGroupSequence
, new (fGrammarPoolMemoryManager) ContentSpecNode(*baseSpecNode)
, specNode
, true
, true
, fGrammarPoolMemoryManager
)
);
typeInfo->setAdoptContentSpec(true);
}
}
}
else {
typeInfo->setDerivedBy(0);
}
// -------------------------------------------------------------
// Set the content type
// -------------------------------------------------------------
if (isBaseAnyType && typeDerivedBy == SchemaSymbols::XSD_EXTENSION) {
ContentSpecNode* anySpecNode = new (fGrammarPoolMemoryManager) ContentSpecNode
(
new (fGrammarPoolMemoryManager) QName
(
XMLUni::fgZeroLenString
, XMLUni::fgZeroLenString
, fEmptyNamespaceURI, fGrammarPoolMemoryManager
)
, false
, fGrammarPoolMemoryManager
);
anySpecNode->setType(ContentSpecNode::Any_Lax);
anySpecNode->setMinOccurs(0);
anySpecNode->setMaxOccurs(SchemaSymbols::XSD_UNBOUNDED);
if (!specNode) {
typeInfo->setContentSpec(anySpecNode);
typeInfo->setDerivedBy(typeDerivedBy);
}
else {
typeInfo->setAdoptContentSpec(false);
typeInfo->setContentSpec
(
new (fGrammarPoolMemoryManager) ContentSpecNode
(
ContentSpecNode::ModelGroupSequence
, anySpecNode
, specNode
, true
, true
, fGrammarPoolMemoryManager
)
);
typeInfo->setAdoptContentSpec(true);
if (!isMixed) {
reportSchemaError(ctElem, XMLUni::fgXMLErrDomain, XMLErrs::MixedOrElementOnly, baseLocalPart, typeName);
throw TraverseSchema::InvalidComplexTypeInfo; //REVISIT - should we continue
}
}
typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
}
else if (isMixed) {
if (specNode != 0) {
typeInfo->setContentType(SchemaElementDecl::Mixed_Complex);
}
else {
// add #PCDATA leaf and set its minOccurs to 0
ContentSpecNode* pcdataNode = new (fGrammarPoolMemoryManager) ContentSpecNode
(
new (fGrammarPoolMemoryManager) QName
(
XMLUni::fgZeroLenString
, XMLUni::fgZeroLenString
, XMLElementDecl::fgPCDataElemId
, fGrammarPoolMemoryManager
)
, false
, fGrammarPoolMemoryManager
);
pcdataNode->setMinOccurs(0);
typeInfo->setContentSpec(pcdataNode);
typeInfo->setAdoptContentSpec(true);
typeInfo->setContentType(SchemaElementDecl::Mixed_Simple);
}
}
else if (specNodeWasNull &&
(typeDerivedBy == SchemaSymbols::XSD_EXTENSION) &&
baseTypeInfo) {
typeInfo->setBaseDatatypeValidator(baseTypeInfo->getBaseDatatypeValidator());
typeInfo->setDatatypeValidator(baseTypeInfo->getDatatypeValidator());
typeInfo->setContentType(baseTypeInfo->getContentType());
}
else if (typeInfo->getContentSpec() == 0) {
if (!effectiveContent_hasChild) {
typeInfo->setContentType(SchemaElementDecl::Empty);
}
else {
typeInfo->setContentType(SchemaElementDecl::ElementOnlyEmpty);
}
}
else {
typeInfo->setContentType(SchemaElementDecl::Children);
}
// -------------------------------------------------------------
// Now, check attributes and handle
// -------------------------------------------------------------
if (attrNode != 0) {
if (!isAttrOrAttrGroup(attrNode)) {
reportSchemaError(attrNode, XMLUni::fgXMLErrDomain, XMLErrs::InvalidChildInComplexType,
attrNode->getLocalName());
}
else {
processAttributes(ctElem, attrNode, typeInfo, isBaseAnyType);
}
}
else if (baseTypeInfo != 0 || isBaseAnyType) {
processAttributes(ctElem, 0, typeInfo, isBaseAnyType);
}
}