GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: AllContentModel.cpp 676911 2008-07-15 13:27:32Z amassari $ 00020 */ 00021 00022 00023 // --------------------------------------------------------------------------- 00024 // Includes 00025 // --------------------------------------------------------------------------- 00026 #include <xercesc/util/Janitor.hpp> 00027 #include <xercesc/util/RuntimeException.hpp> 00028 #include <xercesc/framework/XMLElementDecl.hpp> 00029 #include <xercesc/framework/XMLValidator.hpp> 00030 #include <xercesc/validators/common/ContentSpecNode.hpp> 00031 #include <xercesc/validators/common/AllContentModel.hpp> 00032 #include <xercesc/validators/schema/SubstitutionGroupComparator.hpp> 00033 #include <xercesc/validators/schema/XercesElementWildcard.hpp> 00034 00035 XERCES_CPP_NAMESPACE_BEGIN 00036 00037 // --------------------------------------------------------------------------- 00038 // AllContentModel: Constructors and Destructor 00039 // --------------------------------------------------------------------------- 00040 AllContentModel::AllContentModel( ContentSpecNode* const parentContentSpec 00041 , const bool isMixed 00042 , MemoryManager* const manager) : 00043 fMemoryManager(manager) 00044 , fCount(0) 00045 , fChildren(0) 00046 , fChildOptional(0) 00047 , fNumRequired(0) 00048 , fIsMixed(isMixed) 00049 , fHasOptionalContent(false) 00050 { 00051 // 00052 // Create a vector of unsigned ints that will be filled in with the 00053 // ids of the child nodes. It will be expanded as needed but we give 00054 // it an initial capacity of 64 which should be more than enough for 00055 // 99% of the scenarios. 00056 // 00057 00058 ValueVectorOf<QName*> children(64, fMemoryManager); 00059 ValueVectorOf<bool> childOptional(64, fMemoryManager); 00060 00061 // 00062 // Get the parent element's content spec. This is the head of the tree 00063 // of nodes that describes the content model. We will iterate this 00064 // tree. 00065 // 00066 ContentSpecNode* curNode = parentContentSpec; 00067 if (!curNode) 00068 ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoParentCSN, fMemoryManager); 00069 00070 // And now call the private recursive method that iterates the tree 00071 if (curNode->getType() == ContentSpecNode::All 00072 && curNode->getMinOccurs() == 0) { 00073 fHasOptionalContent = true; 00074 } 00075 buildChildList(curNode, children, childOptional); 00076 00077 // 00078 // And now we know how many elements we need in our member list. So 00079 // fill them in. 00080 // 00081 fCount = children.size(); 00082 fChildren = (QName**) fMemoryManager->allocate(fCount * sizeof(QName*)); //new QName*[fCount]; 00083 fChildOptional = (bool*) fMemoryManager->allocate(fCount * sizeof(bool)); //new bool[fCount]; 00084 for (unsigned int index = 0; index < fCount; index++) { 00085 fChildren[index] = new (fMemoryManager) QName(*(children.elementAt(index))); 00086 fChildOptional[index] = childOptional.elementAt(index); 00087 } 00088 } 00089 00090 AllContentModel::~AllContentModel() 00091 { 00092 for (XMLSize_t index = 0; index < fCount; index++) 00093 delete fChildren[index]; 00094 fMemoryManager->deallocate(fChildren); //delete [] fChildren; 00095 fMemoryManager->deallocate(fChildOptional); //delete [] fChildOptional; 00096 } 00097 00098 // --------------------------------------------------------------------------- 00099 // AllContentModel: Implementation of the ContentModel virtual interface 00100 // --------------------------------------------------------------------------- 00101 // 00102 //Under the XML Schema mixed model, 00103 //the order and number of child elements appearing in an instance 00104 //must agree with 00105 //the order and number of child elements specified in the model. 00106 // 00107 bool 00108 AllContentModel::validateContent( QName** const children 00109 , XMLSize_t childCount 00110 , unsigned int 00111 , XMLSize_t* indexFailingChild 00112 , MemoryManager* const manager) const 00113 { 00114 // If <all> had minOccurs of zero and there are 00115 // no children to validate, trivially validate 00116 if (childCount == 0 && (fHasOptionalContent || !fNumRequired)) 00117 return true; 00118 00119 // keep track of the required element seen 00120 XMLSize_t numRequiredSeen = 0; 00121 00122 if(childCount > 0) 00123 { 00124 // Check for duplicate element 00125 bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount]; 00126 00127 const ArrayJanitor<bool> jan(elementSeen, manager); 00128 00129 // initialize the array 00130 for (XMLSize_t i = 0; i < fCount; i++) 00131 elementSeen[i] = false; 00132 00133 for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++) { 00134 // Get the current child out of the source index 00135 const QName* curChild = children[outIndex]; 00136 00137 // If it's PCDATA, then we just accept that 00138 if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId) 00139 continue; 00140 00141 // And try to find it in our list 00142 XMLSize_t inIndex = 0; 00143 for (; inIndex < fCount; inIndex++) 00144 { 00145 const QName* inChild = fChildren[inIndex]; 00146 if ((inChild->getURI() == curChild->getURI()) && 00147 (XMLString::equals(inChild->getLocalPart(), curChild->getLocalPart()))) { 00148 // found it 00149 // If this element was seen already, indicate an error was 00150 // found at the duplicate index. 00151 if (elementSeen[inIndex]) { 00152 *indexFailingChild=outIndex; 00153 return false; 00154 } 00155 else 00156 elementSeen[inIndex] = true; 00157 00158 if (!fChildOptional[inIndex]) 00159 numRequiredSeen++; 00160 00161 break; 00162 } 00163 } 00164 00165 // We did not find this one, so the validation failed 00166 if (inIndex == fCount) { 00167 *indexFailingChild=outIndex; 00168 return false; 00169 } 00170 00171 } 00172 } 00173 00174 // Were all the required elements of the <all> encountered? 00175 if (numRequiredSeen != fNumRequired) { 00176 *indexFailingChild=childCount; 00177 return false; 00178 } 00179 00180 // Everything seems to be ok, so return success 00181 return true; 00182 } 00183 00184 00185 bool AllContentModel::validateContentSpecial(QName** const children 00186 , XMLSize_t childCount 00187 , unsigned int 00188 , GrammarResolver* const pGrammarResolver 00189 , XMLStringPool* const pStringPool 00190 , XMLSize_t* indexFailingChild 00191 , MemoryManager* const manager) const 00192 { 00193 // If <all> had minOccurs of zero and there are 00194 // no children to validate, trivially validate 00195 if (childCount == 0 && (fHasOptionalContent || !fNumRequired)) 00196 return true; 00197 00198 // keep track of the required element seen 00199 XMLSize_t numRequiredSeen = 0; 00200 00201 if(childCount > 0) 00202 { 00203 SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool); 00204 00205 // Check for duplicate element 00206 bool* elementSeen = (bool*) manager->allocate(fCount*sizeof(bool)); //new bool[fCount]; 00207 00208 const ArrayJanitor<bool> jan(elementSeen, manager); 00209 00210 // initialize the array 00211 for (XMLSize_t i = 0; i < fCount; i++) 00212 elementSeen[i] = false; 00213 00214 for (XMLSize_t outIndex = 0; outIndex < childCount; outIndex++) { 00215 // Get the current child out of the source index 00216 QName* const curChild = children[outIndex]; 00217 00218 // If it's PCDATA, then we just accept that 00219 if (fIsMixed && curChild->getURI() == XMLElementDecl::fgPCDataElemId) 00220 continue; 00221 00222 // And try to find it in our list 00223 XMLSize_t inIndex = 0; 00224 for (; inIndex < fCount; inIndex++) 00225 { 00226 QName* const inChild = fChildren[inIndex]; 00227 if ( comparator.isEquivalentTo(curChild, inChild)) { 00228 // match 00229 // If this element was seen already, indicate an error was 00230 // found at the duplicate index. 00231 if (elementSeen[inIndex]) { 00232 *indexFailingChild=outIndex; 00233 return false; 00234 } 00235 else 00236 elementSeen[inIndex] = true; 00237 00238 if (!fChildOptional[inIndex]) 00239 numRequiredSeen++; 00240 00241 break; 00242 } 00243 } 00244 00245 // We did not find this one, so the validation failed 00246 if (inIndex == fCount) { 00247 *indexFailingChild=outIndex; 00248 return false; 00249 } 00250 00251 } 00252 } 00253 00254 // Were all the required elements of the <all> encountered? 00255 if (numRequiredSeen != fNumRequired) { 00256 *indexFailingChild=childCount; 00257 return false; 00258 } 00259 00260 // Everything seems to be ok, so return success 00261 return true; 00262 00263 } 00264 00265 void AllContentModel::checkUniqueParticleAttribution 00266 ( 00267 SchemaGrammar* const pGrammar 00268 , GrammarResolver* const pGrammarResolver 00269 , XMLStringPool* const pStringPool 00270 , XMLValidator* const pValidator 00271 , unsigned int* const pContentSpecOrgURI 00272 , const XMLCh* pComplexTypeName /*= 0*/ 00273 ) 00274 { 00275 SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool); 00276 00277 XMLSize_t i, j; 00278 00279 // rename back 00280 for (i = 0; i < fCount; i++) { 00281 unsigned int orgURIIndex = fChildren[i]->getURI(); 00282 fChildren[i]->setURI(pContentSpecOrgURI[orgURIIndex]); 00283 } 00284 00285 // check whether there is conflict between any two leaves 00286 for (i = 0; i < fCount; i++) { 00287 for (j = i+1; j < fCount; j++) { 00288 // If this is text in a Schema mixed content model, skip it. 00289 if ( fIsMixed && 00290 (( fChildren[i]->getURI() == XMLElementDecl::fgPCDataElemId) || 00291 ( fChildren[j]->getURI() == XMLElementDecl::fgPCDataElemId))) 00292 continue; 00293 00294 if (XercesElementWildcard::conflict(pGrammar, 00295 ContentSpecNode::Leaf, 00296 fChildren[i], 00297 ContentSpecNode::Leaf, 00298 fChildren[j], 00299 &comparator)) { 00300 pValidator->emitError(XMLValid::UniqueParticleAttributionFail, 00301 pComplexTypeName, 00302 fChildren[i]->getRawName(), 00303 fChildren[j]->getRawName()); 00304 } 00305 } 00306 } 00307 } 00308 00309 // --------------------------------------------------------------------------- 00310 // AllContentModel: Private helper methods 00311 // --------------------------------------------------------------------------- 00312 void 00313 AllContentModel::buildChildList(ContentSpecNode* const curNode 00314 , ValueVectorOf<QName*>& toFill 00315 , ValueVectorOf<bool>& toOptional) 00316 { 00317 // Get the type of spec node our current node is 00318 const ContentSpecNode::NodeTypes curType = curNode->getType(); 00319 00320 if (curType == ContentSpecNode::All) 00321 { 00322 // Get both the child node pointers 00323 ContentSpecNode* leftNode = curNode->getFirst(); 00324 ContentSpecNode* rightNode = curNode->getSecond(); 00325 00326 // Recurse on the left and right nodes 00327 buildChildList(leftNode, toFill, toOptional); 00328 if(rightNode) 00329 buildChildList(rightNode, toFill, toOptional); 00330 } 00331 else if (curType == ContentSpecNode::Leaf) 00332 { 00333 // At leaf, add the element to list of elements permitted in the all 00334 toFill.addElement(curNode->getElement()); 00335 toOptional.addElement(false); 00336 fNumRequired++; 00337 } 00338 else if (curType == ContentSpecNode::ZeroOrOne) 00339 { 00340 // At ZERO_OR_ONE node, subtree must be an element 00341 // that was specified with minOccurs=0, maxOccurs=1 00342 ContentSpecNode* leftNode = curNode->getFirst(); 00343 if (leftNode->getType() != ContentSpecNode::Leaf) 00344 ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager); 00345 00346 toFill.addElement(leftNode->getElement()); 00347 toOptional.addElement(true); 00348 } 00349 // only allow ZeroOrMore when it's the father of a Loop 00350 else if (curType == ContentSpecNode::ZeroOrMore && 00351 curNode->getFirst()!=0 && 00352 curNode->getFirst()->getType()==ContentSpecNode::Loop) 00353 { 00354 ContentSpecNode* leftNode = curNode->getFirst(); 00355 buildChildList(leftNode, toFill, toOptional); 00356 } 00357 else if (curType == ContentSpecNode::Loop) 00358 { 00359 // At leaf, add the element to list of elements permitted in the all 00360 int i; 00361 for(i=0;i<curNode->getMinOccurs();i++) 00362 { 00363 toFill.addElement(curNode->getElement()); 00364 toOptional.addElement(false); 00365 fNumRequired++; 00366 } 00367 if(curNode->getMaxOccurs()!=-1) 00368 for(i=0;i<(curNode->getMaxOccurs() - curNode->getMinOccurs());i++) 00369 { 00370 toFill.addElement(curNode->getElement()); 00371 toOptional.addElement(true); 00372 } 00373 } 00374 else 00375 ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, fMemoryManager); 00376 } 00377 00378 XERCES_CPP_NAMESPACE_END