GME  13
DTDElementDecl.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: DTDElementDecl.cpp 471747 2006-11-06 14:31:56Z amassari $
00020  */
00021 
00022 
00023 // ---------------------------------------------------------------------------
00024 //  Includes
00025 // ---------------------------------------------------------------------------
00026 #include <xercesc/util/XMLString.hpp>
00027 #include <xercesc/util/XMLUniDefs.hpp>
00028 #include <xercesc/util/XMLUni.hpp>
00029 #include <xercesc/framework/XMLBuffer.hpp>
00030 #include <xercesc/validators/common/DFAContentModel.hpp>
00031 #include <xercesc/validators/common/ContentSpecNode.hpp>
00032 #include <xercesc/validators/common/MixedContentModel.hpp>
00033 #include <xercesc/validators/common/SimpleContentModel.hpp>
00034 #include <xercesc/validators/DTD/DTDAttDefList.hpp>
00035 #include <xercesc/validators/DTD/DTDElementDecl.hpp>
00036 
00037 #include <xercesc/internal/XTemplateSerializer.hpp>
00038 
00039 XERCES_CPP_NAMESPACE_BEGIN
00040 
00041 // ---------------------------------------------------------------------------
00042 //  DTDElementDecl: Constructors and Destructor
00043 // ---------------------------------------------------------------------------
00044 DTDElementDecl::DTDElementDecl(MemoryManager* const manager) :
00045 
00046     XMLElementDecl(manager)
00047     , fModelType(Any)
00048     , fAttDefs(0)
00049     , fAttList(0)
00050     , fContentSpec(0)
00051     , fContentModel(0)
00052     , fFormattedModel(0)
00053 {
00054 }
00055 
00056 DTDElementDecl::DTDElementDecl( const XMLCh* const               elemRawName
00057                               , const unsigned int               uriId
00058                               , const DTDElementDecl::ModelTypes type
00059                               , MemoryManager* const             manager) :
00060     XMLElementDecl(manager)
00061     , fModelType(type)
00062     , fAttDefs(0)
00063     , fAttList(0)
00064     , fContentSpec(0)
00065     , fContentModel(0)
00066     , fFormattedModel(0)
00067 {
00068     setElementName(elemRawName, uriId);
00069 }
00070 
00071 DTDElementDecl::DTDElementDecl( QName* const                     elementName
00072                               , const DTDElementDecl::ModelTypes type
00073                               , MemoryManager* const             manager) :
00074     XMLElementDecl(manager)
00075     , fModelType(type)
00076     , fAttDefs(0)
00077     , fAttList(0)
00078     , fContentSpec(0)
00079     , fContentModel(0)
00080     , fFormattedModel(0)
00081 {
00082     setElementName(elementName);
00083 }
00084 
00085 DTDElementDecl::~DTDElementDecl()
00086 {
00087     delete fAttDefs;
00088     delete fAttList;
00089     delete fContentSpec;
00090     delete fContentModel;
00091     getMemoryManager()->deallocate(fFormattedModel);//delete [] fFormattedModel;
00092 }
00093 
00094 
00095 
00096 // ---------------------------------------------------------------------------
00097 //  The virtual element decl interface
00098 // ---------------------------------------------------------------------------
00099 XMLAttDefList& DTDElementDecl::getAttDefList() const
00100 {
00101     if (!fAttList)
00102     {
00103         // If the att def list is not made yet, then fault it in too
00104         if (!fAttDefs)
00105             faultInAttDefList();
00106 
00107         ((DTDElementDecl*)this)->fAttList = new (getMemoryManager()) DTDAttDefList(fAttDefs,getMemoryManager());
00108     }
00109 
00110     return *fAttList;
00111 }
00112 
00113 
00114 XMLElementDecl::CharDataOpts DTDElementDecl::getCharDataOpts() const
00115 {
00116     XMLElementDecl::CharDataOpts retVal;
00117     switch(fModelType)
00118     {
00119         case Children :
00120             retVal = XMLElementDecl::SpacesOk;
00121             break;
00122 
00123         case Empty :
00124             retVal = XMLElementDecl::NoCharData;
00125             break;
00126 
00127         default :
00128             retVal = XMLElementDecl::AllCharData;
00129             break;
00130     }
00131     return retVal;
00132 }
00133 
00134 
00135 bool DTDElementDecl::hasAttDefs() const
00136 {
00137     // If the collection hasn't been faulted in, then no att defs
00138     if (!fAttDefs)
00139         return false;
00140 
00141     return !fAttDefs->isEmpty();
00142 }
00143 
00144 void
00145 DTDElementDecl::setContentSpec(ContentSpecNode* toAdopt)
00146 {
00147     delete fContentSpec;
00148     fContentSpec = toAdopt;
00149 
00150     //reset Content Model
00151     setContentModel(0);
00152 
00153 }
00154 
00155 const XMLCh*
00156 DTDElementDecl::getFormattedContentModel() const
00157 {
00158     //
00159     //  If its not already built, then call the protected virtual method
00160     //  to allow the derived class to build it (since only it knows.)
00161     //  Otherwise, just return the previously formatted methods.
00162     //
00163     //  Since we are faulting this in, within a const getter, we have to
00164     //  cast off the const-ness.
00165     //
00166     if (!fFormattedModel)
00167         ((DTDElementDecl*)this)->fFormattedModel = formatContentModel();
00168 
00169     return fFormattedModel;
00170 }
00171 
00172 
00173 // ---------------------------------------------------------------------------
00174 //  DTDElementDecl: Getter methods
00175 // ---------------------------------------------------------------------------
00176 const DTDAttDef* DTDElementDecl::getAttDef(const XMLCh* const attName) const
00177 {
00178     // If no list, then return a null
00179     if (!fAttDefs)
00180         return 0;
00181 
00182     return fAttDefs->get(attName);
00183 }
00184 
00185 
00186 DTDAttDef* DTDElementDecl::getAttDef(const XMLCh* const attName)
00187 {
00188     // If no list, then return a null
00189     if (!fAttDefs)
00190         return 0;
00191 
00192     return fAttDefs->get(attName);
00193 }
00194 
00195 
00196 // ---------------------------------------------------------------------------
00197 //  DTDElementDecl: Implementation of the protected virtual interface
00198 // ---------------------------------------------------------------------------
00199 void DTDElementDecl::addAttDef(DTDAttDef* const toAdd)
00200 {
00201     // Fault in the att list if required
00202     if (!fAttDefs)
00203             faultInAttDefList();
00204 
00205     // Tell this guy the element id of its parent (us)
00206     toAdd->setElemId(getId());
00207 
00208     fAttDefs->put((void*)(toAdd->getFullName()), toAdd);
00209     // update and/or create fAttList
00210     if(!fAttList)
00211         ((DTDElementDecl*)this)->fAttList = new (getMemoryManager()) DTDAttDefList(fAttDefs,getMemoryManager());
00212     fAttList->addAttDef(toAdd);
00213 }
00214 
00215 
00216 // ---------------------------------------------------------------------------
00217 //  DTDElementDecl: Private helper methods
00218 // ---------------------------------------------------------------------------
00219 XMLCh* DTDElementDecl::formatContentModel() const
00220 {
00221     XMLCh* newValue = 0;
00222     if (fModelType == Any)
00223     {
00224         newValue = XMLString::replicate(XMLUni::fgAnyString, getMemoryManager());
00225     }
00226      else if (fModelType == Empty)
00227     {
00228         newValue = XMLString::replicate(XMLUni::fgEmptyString, getMemoryManager());
00229     }
00230      else
00231     {
00232         //
00233         //  Use a temp XML buffer to format into. Content models could be
00234         //  pretty long, but very few will be longer than one K. The buffer
00235         //  will expand to handle the more pathological ones.
00236         //
00237         XMLBuffer bufFmt(1023, getMemoryManager());
00238         getContentSpec()->formatSpec(bufFmt);
00239         newValue = XMLString::replicate(bufFmt.getRawBuffer(), getMemoryManager());
00240     }
00241     return newValue;
00242 }
00243 
00244 XMLContentModel* DTDElementDecl::makeContentModel()
00245 {
00246     XMLContentModel* cmRet = 0;
00247     if (fModelType == Mixed_Simple)
00248     {
00249         //
00250         //  Just create a mixel content model object. This type of
00251         //  content model is optimized for mixed content validation.
00252         //
00253         cmRet = new (getMemoryManager()) MixedContentModel(true, this->getContentSpec(), false, getMemoryManager());
00254     }
00255      else if (fModelType == Children)
00256     {
00257         //
00258         //  This method will create an optimal model for the complexity
00259         //  of the element's defined model. If its simple, it will create
00260         //  a SimpleContentModel object. If its a simple list, it will
00261         //  create a SimpleListContentModel object. If its complex, it
00262         //  will create a DFAContentModel object.
00263         //
00264         cmRet = createChildModel();
00265     }
00266      else
00267     {
00268         ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_MustBeMixedOrChildren, getMemoryManager());
00269     }
00270     return cmRet;
00271 }
00272 
00273 
00274 XMLContentModel* DTDElementDecl::createChildModel()
00275 {
00276     // Get the content spec node of the element
00277     ContentSpecNode* specNode = getContentSpec();
00278 
00279     if(!specNode)
00280         ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, getMemoryManager());
00281 
00282     //
00283     //  Do a sanity check that the node does not have a PCDATA id. Since,
00284     //  if it was, it should have already gotten taken by the Mixed model.
00285     //
00286     if (specNode->getElement()) {
00287         if (specNode->getElement()->getURI() == XMLElementDecl::fgPCDataElemId)
00288             ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_NoPCDATAHere, getMemoryManager());
00289     }
00290 
00291     //
00292     //  According to the type of node, we will create the correct type of
00293     //  content model.
00294     //
00295     if (specNode->getType() == ContentSpecNode::Leaf)
00296     {
00297         // Create a simple content model
00298         return new (getMemoryManager()) SimpleContentModel
00299         (
00300             true
00301             , specNode->getElement()
00302             , 0
00303             , ContentSpecNode::Leaf
00304             , getMemoryManager()
00305         );
00306     }
00307      else if ((specNode->getType() == ContentSpecNode::Choice)
00308           ||  (specNode->getType() == ContentSpecNode::Sequence))
00309     {
00310         //
00311         //  Lets see if both of the children are leafs. If so, then it has to
00312         //  be a simple content model
00313         //
00314         if ((specNode->getFirst()->getType() == ContentSpecNode::Leaf)
00315         &&  (specNode->getSecond()->getType() == ContentSpecNode::Leaf))
00316         {
00317             return new (getMemoryManager()) SimpleContentModel
00318             (
00319                 true
00320                 , specNode->getFirst()->getElement()
00321                 , specNode->getSecond()->getElement()
00322                 , specNode->getType()
00323                 , getMemoryManager()
00324             );
00325         }
00326     }
00327      else if ((specNode->getType() == ContentSpecNode::OneOrMore)
00328           ||  (specNode->getType() == ContentSpecNode::ZeroOrMore)
00329           ||  (specNode->getType() == ContentSpecNode::ZeroOrOne))
00330     {
00331         //
00332         //  Its a repetition, so see if its one child is a leaf. If so its a
00333         //  repetition of a single element, so we can do a simple content
00334         //  model for that.
00335         //
00336         if (specNode->getFirst()->getType() == ContentSpecNode::Leaf)
00337         {
00338             return new (getMemoryManager()) SimpleContentModel
00339             (
00340                 true
00341                 , specNode->getFirst()->getElement()
00342                 , 0
00343                 , specNode->getType()
00344                 , getMemoryManager()
00345             );
00346         }
00347     }
00348      else
00349     {
00350         ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMSpecType, getMemoryManager());
00351     }
00352 
00353     // Its not any simple type of content, so create a DFA based content model
00354     return new (getMemoryManager()) DFAContentModel
00355     (
00356         true
00357         , this->getContentSpec()
00358         , getMemoryManager()
00359     );
00360 }
00361 
00362 
00363 void DTDElementDecl::faultInAttDefList() const
00364 {
00365     // Use a hash modulus of 29 and tell it owns its elements
00366     ((DTDElementDecl*)this)->fAttDefs = new (getMemoryManager()) RefHashTableOf<DTDAttDef>(29, true, getMemoryManager());
00367 }
00368 
00369 /***
00370  * Support for Serialization/De-serialization
00371  ***/
00372 
00373 IMPL_XSERIALIZABLE_TOCREATE(DTDElementDecl)
00374 
00375 void DTDElementDecl::serialize(XSerializeEngine& serEng)
00376 {
00377 
00378     XMLElementDecl::serialize(serEng);
00379 
00380     if (serEng.isStoring())
00381     {
00382         serEng<<(int) fModelType;
00383 
00384         /***
00385          *
00386          * Serialize RefHashTableOf<DTDAttDef>
00387          *
00388          ***/
00389         XTemplateSerializer::storeObject(fAttDefs, serEng);
00390 
00391         serEng<<fAttList;
00392         serEng<<fContentSpec;
00393 
00394         /***
00395          *   don't serialize
00396          *
00397          *   XMLContentModel*            fContentModel;
00398          *   XMLCh*                      fFormattedModel;
00399          *
00400          ***/
00401 
00402     }
00403     else
00404     {
00405         int i;
00406         serEng>>i;
00407         fModelType=(ModelTypes)i;
00408 
00409         /***
00410          *
00411          * Deserialize RefHashTableOf<DTDAttDef>           
00412          *
00413          ***/
00414         XTemplateSerializer::loadObject(&fAttDefs, 29, true, serEng);
00415 
00416         serEng>>fAttList;
00417         serEng>>fContentSpec;
00418 
00419         /***
00420          *   don't deserialize
00421          *
00422          *   XMLContentModel*            fContentModel;
00423          *   XMLCh*                      fFormattedModel;
00424          *
00425          ***/
00426         fContentModel   = 0;
00427         fFormattedModel = 0;
00428     }
00429 
00430 }
00431 
00432 XMLElementDecl::objectType  DTDElementDecl::getObjectType() const
00433 {
00434     return DTD;
00435 }
00436 
00437 XERCES_CPP_NAMESPACE_END