/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id$ */ // --------------------------------------------------------------------------- // Includes // --------------------------------------------------------------------------- #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // AllContentModel: Constructors and Destructor // --------------------------------------------------------------------------- AllContentModel::AllContentModel( ContentSpecNode* const parentContentSpec , const bool isMixed , MemoryManager* const manager) : fMemoryManager(manager) , fCount(0) , fChildren(0) , fChildOptional(0) , fNumRequired(0) , fIsMixed(isMixed) , fHasOptionalContent(false) { // // Create a vector of unsigned ints that will be filled in with the // ids of the child nodes. It will be expanded as needed but we give // it an initial capacity of 64 which should be more than enough for // 99% of the scenarios. // ValueVectorOf children(64, fMemoryManager); ValueVectorOf childOptional(64, fMemoryManager); // // Get the parent element's content spec. This is the head of the tree // of nodes that describes the content model. We will iterate this // tree. // ContentSpecNode* curNode = parentContentSpec; if (!curNode) ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoParentCSN, fMemoryManager); // And now call the private recursive method that iterates the tree if (curNode->getType() == ContentSpecNode::All && curNode->getMinOccurs() == 0) { fHasOptionalContent = true; } buildChildList(curNode, children, childOptional); // // And now we know how many elements we need in our member list. So // fill them in. // fCount = children.size(); fChildren = (QName**) fMemoryManager->allocate(fCount * sizeof(QName*)); //new QName*[fCount]; fChildOptional = (bool*) fMemoryManager->allocate(fCount * sizeof(bool)); //new bool[fCount]; for (unsigned int index = 0; index < fCount; index++) { fChildren[index] = new (fMemoryManager) QName(*(children.elementAt(index))); fChildOptional[index] = childOptional.elementAt(index); } } AllContentModel::~AllContentModel() { for (XMLSize_t index = 0; index < fCount; index++) delete fChildren[index]; fMemoryManager->deallocate(fChildren); //delete [] fChildren; fMemoryManager->deallocate(fChildOptional); //delete [] fChildOptional; } // --------------------------------------------------------------------------- // AllContentModel: Implementation of the ContentModel virtual interface // --------------------------------------------------------------------------- // //Under the XML Schema mixed model, //the order and number of child elements appearing in an instance //must agree with //the order and number of child elements specified in the model. // bool AllContentModel::validateContent( QName** const children , XMLSize_t childCount , unsigned int , XMLSize_t* indexFailingChild , MemoryManager* const manager) const { // If had minOccurs of zero and there are // no children to validate, trivially validate if (childCount == 0 && (fHasOptionalContent || !fNumRequired)) return true; // keep track of the required element seen XMLSize_t numRequiredSeen = 0; if(childCount > 0) { // Check for duplicate element bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount]; const ArrayJanitor jan(elementSeen, manager); // initialize the array for (XMLSize_t i = 0; i < fCount; i++) elementSeen[i] = false; for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++) { // Get the current child out of the source index const QName* curChild = children[outIndex]; // If it's PCDATA, then we just accept that if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId) continue; // And try to find it in our list XMLSize_t inIndex = 0; for (; inIndex < fCount; inIndex++) { const QName* inChild = fChildren[inIndex]; if ((inChild->getURI() == curChild->getURI()) && (XMLString::equals(inChild->getLocalPart(), curChild->getLocalPart()))) { // found it // If this element was seen already, indicate an error was // found at the duplicate index. if (elementSeen[inIndex]) { *indexFailingChild=outIndex; return false; } else elementSeen[inIndex] = true; if (!fChildOptional[inIndex]) numRequiredSeen++; break; } } // We did not find this one, so the validation failed if (inIndex == fCount) { *indexFailingChild=outIndex; return false; } } } // Were all the required elements of the encountered? if (numRequiredSeen != fNumRequired) { *indexFailingChild=childCount; return false; } // Everything seems to be ok, so return success return true; } bool AllContentModel::validateContentSpecial(QName** const children , XMLSize_t childCount , unsigned int , GrammarResolver* const pGrammarResolver , XMLStringPool* const pStringPool , XMLSize_t* indexFailingChild , MemoryManager* const manager) const { // If had minOccurs of zero and there are // no children to validate, trivially validate if (childCount == 0 && (fHasOptionalContent || !fNumRequired)) return true; // keep track of the required element seen XMLSize_t numRequiredSeen = 0; if(childCount > 0) { SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool); // Check for duplicate element bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount]; const ArrayJanitor jan(elementSeen, manager); // initialize the array for (XMLSize_t i = 0; i < fCount; i++) elementSeen[i] = false; for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++) { // Get the current child out of the source index QName* const curChild = children[outIndex]; // If it's PCDATA, then we just accept that if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId) continue; // And try to find it in our list XMLSize_t inIndex = 0; for (; inIndex < fCount; inIndex++) { QName* const inChild = fChildren[inIndex]; if ( comparator.isEquivalentTo(curChild, inChild)) { // match // If this element was seen already, indicate an error was // found at the duplicate index. if (elementSeen[inIndex]) { *indexFailingChild=outIndex; return false; } else elementSeen[inIndex] = true; if (!fChildOptional[inIndex]) numRequiredSeen++; break; } } // We did not find this one, so the validation failed if (inIndex == fCount) { *indexFailingChild=outIndex; return false; } } } // Were all the required elements of the encountered? if (numRequiredSeen != fNumRequired) { *indexFailingChild=childCount; return false; } // Everything seems to be ok, so return success return true; } void AllContentModel::checkUniqueParticleAttribution ( SchemaGrammar* const pGrammar , GrammarResolver* const pGrammarResolver , XMLStringPool* const pStringPool , XMLValidator* const pValidator , unsigned int* const pContentSpecOrgURI , const XMLCh* pComplexTypeName /*= 0*/ ) { SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool); XMLSize_t i, j; // rename back for (i = 0; i < fCount; i++) { unsigned int orgURIIndex = fChildren[i]->getURI(); fChildren[i]->setURI(pContentSpecOrgURI[orgURIIndex]); } // check whether there is conflict between any two leaves for (i = 0; i < fCount; i++) { for (j = i+1; j < fCount; j++) { // If this is text in a Schema mixed content model, skip it. if ( fIsMixed && (( fChildren[i]->getURI() == XMLElementDecl::fgPCDataElemId) || ( fChildren[j]->getURI() == XMLElementDecl::fgPCDataElemId))) continue; if (XercesElementWildcard::conflict(pGrammar, ContentSpecNode::Leaf, fChildren[i], ContentSpecNode::Leaf, fChildren[j], &comparator)) { pValidator->emitError(XMLValid::UniqueParticleAttributionFail, pComplexTypeName, fChildren[i]->getRawName(), fChildren[j]->getRawName()); } } } } // --------------------------------------------------------------------------- // AllContentModel: Private helper methods // --------------------------------------------------------------------------- void AllContentModel::buildChildList(ContentSpecNode* const curNode , ValueVectorOf& toFill , ValueVectorOf& toOptional) { // Get the type of spec node our current node is const ContentSpecNode::NodeTypes curType = curNode->getType(); if (curType == ContentSpecNode::All) { // Get both the child node pointers ContentSpecNode* leftNode = curNode->getFirst(); ContentSpecNode* rightNode = curNode->getSecond(); // Recurse on the left and right nodes buildChildList(leftNode, toFill, toOptional); if(rightNode) buildChildList(rightNode, toFill, toOptional); } else if (curType == ContentSpecNode::Leaf) { // At leaf, add the element to list of elements permitted in the all toFill.addElement(curNode->getElement()); toOptional.addElement(false); fNumRequired++; } else if (curType == ContentSpecNode::ZeroOrOne) { // At ZERO_OR_ONE node, subtree must be an element // that was specified with minOccurs=0, maxOccurs=1 ContentSpecNode* leftNode = curNode->getFirst(); if (leftNode->getType() != ContentSpecNode::Leaf) ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager); toFill.addElement(leftNode->getElement()); toOptional.addElement(true); } // only allow ZeroOrMore when it's the father of a Loop else if (curType == ContentSpecNode::ZeroOrMore && curNode->getFirst()!=0 && curNode->getFirst()->getType()==ContentSpecNode::Loop) { ContentSpecNode* leftNode = curNode->getFirst(); buildChildList(leftNode, toFill, toOptional); } else if (curType == ContentSpecNode::Loop) { // At leaf, add the element to list of elements permitted in the all int i; for(i=0;igetMinOccurs();i++) { toFill.addElement(curNode->getElement()); toOptional.addElement(false); fNumRequired++; } if(curNode->getMaxOccurs()!=-1) for(i=0;i<(curNode->getMaxOccurs() - curNode->getMinOccurs());i++) { toFill.addElement(curNode->getElement()); toOptional.addElement(true); } } else ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager); } XERCES_CPP_NAMESPACE_END