GME  13
AllContentModel.cpp
Go to the documentation of this file.
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