GME  13
ContentSpecNode.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: ContentSpecNode.cpp 933155 2010-04-12 09:07:02Z amassari $
00020  */
00021 
00022 
00023 // ---------------------------------------------------------------------------
00024 //  Includes
00025 // ---------------------------------------------------------------------------
00026 #include <xercesc/framework/XMLBuffer.hpp>
00027 #include <xercesc/validators/common/ContentSpecNode.hpp>
00028 #include <xercesc/validators/schema/SchemaSymbols.hpp>
00029 
00030 XERCES_CPP_NAMESPACE_BEGIN
00031 
00032 // ---------------------------------------------------------------------------
00033 //  ContentSpecNode: Copy Constructor
00034 //
00035 //  Note: this copy constructor has dependency on various get*() methods
00036 //        and shall be placed after those method's declaration.
00037 //        aka inline function compilation error on AIX 4.2, xlC 3 r ev.1
00038 // ---------------------------------------------------------------------------
00039 
00040 ContentSpecNode::ContentSpecNode(const ContentSpecNode& toCopy) :
00041     XSerializable(toCopy)
00042     , XMemory(toCopy)
00043     , fMemoryManager(toCopy.fMemoryManager)
00044     , fElement(0)
00045     , fElementDecl(toCopy.fElementDecl)
00046     , fFirst(0)
00047     , fSecond(0)
00048     , fType(toCopy.fType)
00049     , fAdoptFirst(true)
00050     , fAdoptSecond(true)
00051     , fMinOccurs(toCopy.fMinOccurs)
00052     , fMaxOccurs(toCopy.fMaxOccurs)
00053 {
00054     const QName* tempElement = toCopy.getElement();
00055     if (tempElement)
00056         fElement = new (fMemoryManager) QName(*tempElement);
00057 
00058     const ContentSpecNode *tmp = toCopy.getFirst();
00059     if (tmp)
00060         fFirst = new (fMemoryManager) ContentSpecNode(*tmp);
00061 
00062     tmp = toCopy.getSecond();
00063     if (tmp)
00064         fSecond = new (fMemoryManager) ContentSpecNode(*tmp);
00065 }
00066 
00067 // ---------------------------------------------------------------------------
00068 //  Local methods
00069 // ---------------------------------------------------------------------------
00070 static void formatNode( const   ContentSpecNode* const      curNode
00071                         , const ContentSpecNode::NodeTypes  parentType
00072                         ,       XMLBuffer&                  bufToFill)
00073 {
00074     if (!curNode)
00075         return;
00076 
00077     const ContentSpecNode* first = curNode->getFirst();
00078     const ContentSpecNode* second = curNode->getSecond();
00079     const ContentSpecNode::NodeTypes curType = curNode->getType();
00080 
00081     // Get the type of the first node
00082     const ContentSpecNode::NodeTypes firstType = first ?
00083                                                  first->getType() :
00084                                                  ContentSpecNode::Leaf;
00085 
00086     // Calculate the parens flag for the rep nodes
00087     bool doRepParens = false;
00088     if (((firstType != ContentSpecNode::Leaf)
00089             && (parentType != ContentSpecNode::UnknownType))
00090     ||  ((firstType == ContentSpecNode::Leaf)
00091             && (parentType == ContentSpecNode::UnknownType)))
00092     {
00093         doRepParens = true;
00094     }
00095 
00096     // Now handle our type
00097     switch(curType & 0x0f)
00098     {
00099         case ContentSpecNode::Leaf :
00100             if (curNode->getElement()->getURI() == XMLElementDecl::fgPCDataElemId)
00101                 bufToFill.append(XMLElementDecl::fgPCDataElemName);
00102             else
00103             {
00104                 bufToFill.append(curNode->getElement()->getRawName());
00105                 // show the + and * modifiers also when we have a non-infinite number of repetitions
00106                 if(curNode->getMinOccurs()==0 && (curNode->getMaxOccurs()==-1 || curNode->getMaxOccurs()>1))
00107                     bufToFill.append(chAsterisk);
00108                 else if(curNode->getMinOccurs()==0 && curNode->getMaxOccurs()==1)
00109                     bufToFill.append(chQuestion);
00110                 else if(curNode->getMinOccurs()==1 && (curNode->getMaxOccurs()==-1 || curNode->getMaxOccurs()>1))
00111                     bufToFill.append(chPlus);
00112             }
00113             break;
00114 
00115         case ContentSpecNode::ZeroOrOne :
00116             if (doRepParens)
00117                 bufToFill.append(chOpenParen);
00118             formatNode(first, curType, bufToFill);
00119             if (doRepParens)
00120                 bufToFill.append(chCloseParen);
00121             bufToFill.append(chQuestion);
00122             break;
00123 
00124         case ContentSpecNode::ZeroOrMore :
00125             if (doRepParens)
00126                 bufToFill.append(chOpenParen);
00127             formatNode(first, curType, bufToFill);
00128             if (doRepParens)
00129                 bufToFill.append(chCloseParen);
00130             bufToFill.append(chAsterisk);
00131             break;
00132 
00133         case ContentSpecNode::OneOrMore :
00134             if (doRepParens)
00135                 bufToFill.append(chOpenParen);
00136             formatNode(first, curType, bufToFill);
00137             if (doRepParens)
00138                 bufToFill.append(chCloseParen);
00139             bufToFill.append(chPlus);
00140             break;
00141 
00142         case ContentSpecNode::Choice :
00143             if ((parentType & 0x0f) != (curType & 0x0f))
00144                 bufToFill.append(chOpenParen);
00145             formatNode(first, curType, bufToFill);
00146             if(second!=NULL)
00147             {
00148                 bufToFill.append(chPipe);
00149                 formatNode(second, curType, bufToFill);
00150             }
00151             if ((parentType & 0x0f) != (curType & 0x0f))
00152                 bufToFill.append(chCloseParen);
00153             break;
00154 
00155         case ContentSpecNode::Sequence :
00156             if ((parentType & 0x0f) != (curType & 0x0f))
00157                 bufToFill.append(chOpenParen);
00158             formatNode(first, curType, bufToFill);
00159             if(second!=NULL)
00160             {
00161                 bufToFill.append(chComma);
00162                 formatNode(second, curType, bufToFill);
00163             }
00164             if ((parentType & 0x0f) != (curType & 0x0f))
00165                 bufToFill.append(chCloseParen);
00166             break;
00167 
00168         case ContentSpecNode::All :
00169             if ((parentType & 0x0f) != (curType & 0x0f))
00170                         {
00171                 bufToFill.append(chLatin_A);
00172                 bufToFill.append(chLatin_l);
00173                 bufToFill.append(chLatin_l);
00174                 bufToFill.append(chOpenParen);
00175                         }
00176             formatNode(first, curType, bufToFill);
00177             bufToFill.append(chComma);
00178             formatNode(second, curType, bufToFill);
00179             if ((parentType & 0x0f) != (curType & 0x0f))
00180                 bufToFill.append(chCloseParen);
00181             break;
00182     }
00183 }
00184 
00185 
00186 // ---------------------------------------------------------------------------
00187 //  ContentSpecNode: Miscellaneous
00188 // ---------------------------------------------------------------------------
00189 void ContentSpecNode::formatSpec(XMLBuffer&      bufToFill) const
00190 {
00191     // Clean out the buffer first
00192     bufToFill.reset();
00193 
00194     if (fType == ContentSpecNode::Leaf)
00195         bufToFill.append(chOpenParen);
00196     formatNode
00197     (
00198         this
00199         , UnknownType
00200         , bufToFill
00201     );
00202     if (fType == ContentSpecNode::Leaf)
00203         bufToFill.append(chCloseParen);
00204 }
00205 
00206 int ContentSpecNode::getMinTotalRange() const {
00207 
00208     int min = fMinOccurs;
00209 
00210     if ((fType & 0x0f) == ContentSpecNode::Sequence
00211         || fType == ContentSpecNode::All
00212         || (fType & 0x0f) == ContentSpecNode::Choice) {
00213 
00214         int minFirst = fFirst->getMinTotalRange();
00215 
00216         if (fSecond) {
00217 
00218             int minSecond = fSecond->getMinTotalRange();
00219 
00220             if ((fType & 0x0f) == ContentSpecNode::Choice) {
00221                 min = min * ((minFirst < minSecond)? minFirst : minSecond);
00222             }
00223             else {
00224                 min = min * (minFirst + minSecond);
00225             }
00226         }
00227         else
00228             min = min * minFirst;
00229     }
00230 
00231     return min;
00232 }
00233 
00234 int ContentSpecNode::getMaxTotalRange() const {
00235 
00236     int max = fMaxOccurs;
00237 
00238     if (max == SchemaSymbols::XSD_UNBOUNDED) {
00239          return SchemaSymbols::XSD_UNBOUNDED;
00240     }
00241 
00242     if ((fType & 0x0f) == ContentSpecNode::Sequence
00243         || fType == ContentSpecNode::All
00244         || (fType & 0x0f) == ContentSpecNode::Choice) {
00245 
00246         int maxFirst = fFirst->getMaxTotalRange();
00247 
00248         if (maxFirst == SchemaSymbols::XSD_UNBOUNDED) {
00249              return SchemaSymbols::XSD_UNBOUNDED;
00250         }
00251 
00252         if (fSecond) {
00253 
00254             int maxSecond = fSecond->getMaxTotalRange();
00255 
00256             if (maxSecond == SchemaSymbols::XSD_UNBOUNDED) {
00257                 return SchemaSymbols::XSD_UNBOUNDED;
00258             }
00259             else {
00260 
00261                 if ((fType & 0x0f) == ContentSpecNode::Choice) {
00262                     max = max * (maxFirst > maxSecond) ? maxFirst : maxSecond;
00263                 }
00264                 else {
00265                     max = max * (maxFirst + maxSecond);
00266                 }
00267             }
00268         }
00269         else {
00270             max = max * maxFirst;
00271         }
00272     }
00273 
00274     return max;
00275 }
00276 
00277 /***
00278  * Support for Serialization/De-serialization
00279  ***/
00280 
00281 IMPL_XSERIALIZABLE_TOCREATE(ContentSpecNode)
00282 
00283 void ContentSpecNode::serialize(XSerializeEngine& serEng)
00284 {
00285     /***
00286      *  Since fElement, fFirst, fSecond are NOT created by the default 
00287      *  constructor, we need to create them dynamically.
00288      ***/
00289 
00290     if (serEng.isStoring())
00291     {
00292         serEng<<fElement;
00293         XMLElementDecl::storeElementDecl(serEng, fElementDecl);
00294         serEng<<fFirst;
00295         serEng<<fSecond;
00296 
00297         serEng<<(int)fType;
00298         serEng<<fAdoptFirst;
00299         serEng<<fAdoptSecond;
00300         serEng<<fMinOccurs;
00301         serEng<<fMaxOccurs;
00302     }
00303     else
00304     {
00305         serEng>>fElement;
00306         fElementDecl = XMLElementDecl::loadElementDecl(serEng);
00307         serEng>>fFirst;
00308         serEng>>fSecond;
00309 
00310         int type;
00311         serEng>>type;
00312         fType = (NodeTypes)type;
00313 
00314         serEng>>fAdoptFirst;
00315         serEng>>fAdoptSecond;
00316         serEng>>fMinOccurs;
00317         serEng>>fMaxOccurs;
00318     }
00319 
00320 }
00321 
00322 XERCES_CPP_NAMESPACE_END
00323