SchemaValidator.cpp

Go to the documentation of this file.
00001 /* 
00002  * wsdlpull - A C++ parser  for WSDL  (Web services description language)
00003  * Copyright (C) 2005-2007 Vivek Krishna
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the Free
00017  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018  *
00019  *
00020  */
00021 #include <sstream>
00022 #include "schemaparser/SchemaValidator.h"
00023 using namespace std;
00024 
00025 namespace Schema {
00026 /*
00027   This class validates an incoming Xml instance against a given type
00028   whose schema has been processed by a given SchemaParser instance
00029 
00030 */
00031 SchemaValidator::SchemaValidator(const SchemaParser * sp,
00032                                  std::ostream& os)
00033   :ostr_(os),
00034    sParser_(sp)
00035 {
00036 
00037   
00038 }
00039 
00040 SchemaValidator::~SchemaValidator()
00041 {
00042 }
00043 
00044 
00045 /*
00046   Main entry method for validation
00047   Inputs
00048   1. XmlStream ,xpp.getName() muct return the name of the  type
00049   which must be validated
00050   2. typeId of the type against which this stream must be
00051   validated against
00052   3.An Input type container  (default  0)
00053 */
00054 TypeContainer *
00055 SchemaValidator::validate(XmlPullParser * xpp, 
00056                           int typeId,
00057                           TypeContainer * ipTc)
00058 {
00059   TypeContainer *t=0;
00060 
00061   try{  
00062     string elemName = xpp->getName();
00063     const SchemaParser * s1Parser = sParser_;
00064     int typeId1= typeId;
00065 
00066     if (!ipTc)
00067       t = new TypeContainer(typeId, sParser_);
00068     else
00069       t = ipTc;
00070 
00071 
00072 
00073     if (t->getTypeId() != typeId)
00074       error("Fatal error ,container's type is not same as the validated type",xpp);
00075 
00076     // a schema definition inside an instance
00077     if (typeId == Schema::XSD_SCHEMA){
00078       
00079       SchemaParser * ssParser_ = new SchemaParser(xpp);
00080       if (!ssParser_->parseSchemaTag()){
00081 
00082         delete ssParser_;
00083         return 0;
00084       }
00085       delete ssParser_;
00086       return t;
00087     }
00088 
00089     //ignore ANY
00090     if (typeId == Schema::XSD_ANY){
00091       
00092       xpp->skipSubTree();
00093       return t;
00094     }
00095 
00096     // check if this type belongs to the current schema, if not we need to switch contexts
00097     if (!sParser_->isBasicType(typeId)){
00098       
00099       const XSDType * pType = sParser_->getType(typeId);
00100       
00101       if (sParser_->isImported(pType->getNamespace())) {
00102         
00103         sParser_ = sParser_->getImportedSchemaParser(pType->getNamespace());
00104         typeId = const_cast<SchemaParser*>(sParser_)->getTypeId(pType->getQname());
00105         
00106         t->sParser_ = sParser_;
00107         t->typeId_ = (Schema::Type)typeId;
00108 
00109       }
00110     }
00111 
00112     
00113     if (sParser_->getType(typeId) == 0
00114         || sParser_->getType(typeId)->isSimple()) {
00115 
00116       //simple type validation
00117       string val;
00118       xpp->nextToken();
00119       if (xpp->getEventType() == XmlPullParser::TEXT ||
00120           xpp->getEventType() == XmlPullParser::ENTITY_REF){
00121 
00122         val = xpp->getText();
00123 
00124         xpp->nextToken();
00125         while (xpp->getEventType() == XmlPullParser::ENTITY_REF ||
00126                xpp->getEventType() == XmlPullParser::TEXT){
00127 
00128           val += xpp->getText();
00129           xpp->nextToken();
00130             
00131         }
00132         validate(val, typeId, t,xpp);
00133       }
00134       else{
00135         //text was probably empty,nevertheless create  a type container 
00136         validate(val, typeId, t, xpp);
00137       }
00138       if (xpp->getEventType() == XmlPullParser::END_TAG)
00139         {
00140           if (xpp->getName() != elemName)
00141             error("Syntax error "+elemName,xpp);
00142         }
00143       else
00144         error("Expected a closing tag for " + elemName,xpp);
00145     }
00146     else {
00147 
00148       /*
00149         Perform Validation of Complex types
00150         Check for
00151         1.Is the tag name correct (this has to be right !!)
00152         2.Attributes ,if any should be valid
00153         3.Are there any mandatory (#required) attributes
00154         4. Validate its content model 
00155         6.Return the type container which has the
00156         correctly filled in values
00157 
00158       */
00159       const ComplexType *ct =
00160         static_cast<const ComplexType *>(sParser_->getType(typeId));
00161         
00162       const ComplexType * bt = 0;
00163       TypeContainer * btCnt = 0;
00164       if (ct->getBaseTypeId()!=Schema::XSD_ANYTYPE) {
00165 
00166         bt = static_cast<const ComplexType*>
00167           (sParser_->getType(ct->getBaseTypeId()));
00168         btCnt = t->getBaseTypeContainer(true);
00169       }
00170         
00171       int attcnt = xpp->getAttributeCount();
00172         
00173       for (int i = 0; i < attcnt; i++) {
00174           
00175         std::string attName = xpp->getAttributeName(i);
00176         std::string attVal = xpp->getAttributeValue("", attName);
00177         std::string attNsp = xpp->getAttributeNamespace(i);
00178         if (!attNsp.empty() && attNsp != sParser_->getNamespace())
00179           continue;
00180 
00181         const Attribute*at = 0;
00182         TypeContainer *atCnt = 0;
00183         at = ct->getAttribute(attName);
00184 
00185         if (!at && bt){
00186           at  = bt->getAttribute(attName);
00187           if (at)
00188             atCnt = btCnt->getAttributeContainer(attName, true);
00189         }
00190         else{
00191           atCnt = t->getAttributeContainer(attName, true);
00192         }
00193 
00194         if (!at)
00195           error("Unknown attribute \"" + attName +  "\"",xpp);
00196 
00197         validate(attVal, at->getType(), atCnt, xpp);
00198       }
00199         
00200       //see if some required attributes are missing
00201       checkAttributeOccurence(ct,xpp);
00202       if (bt)
00203         checkAttributeOccurence(bt,xpp);
00204 
00205 
00206       if (ct->getContentModel() == Schema::Simple)
00207         {
00208           //complex types with a simple content model
00209 
00210           string val;
00211           xpp->nextToken();
00212           if (xpp->getEventType() == xpp->TEXT){
00213             val = xpp->getText();
00214             validate(val, ct->getContentType(), t, xpp);
00215             xpp->nextTag();
00216           }
00217           else{
00218             //text was probably empty,nevertheless create  a type container 
00219             validate(val, ct->getContentType(), t, xpp);
00220           }
00221 
00222           if (xpp->getEventType() == XmlPullParser::END_TAG)
00223             {
00224               if (xpp->getName() != elemName)
00225                 error("Syntax error",xpp);
00226             }
00227           else
00228             error("Expected a closing tag for " + elemName,xpp);
00229         }
00230       else if (ct->getContentModel() == Schema::Complex){
00231         //a complex type with complex content model
00232         ContentModel* cm=ct->getContents();
00233         ContentModel * bCm = 0;
00234         if (bt)
00235           bCm = bt ->getContents();
00236         if(cm)
00237           validateContentModel(xpp,
00238                                cm,
00239                                t->getChildContainer(cm,true),
00240                                elemName,
00241                                false,
00242                                btCnt);
00243         else if (bCm)
00244           validateContentModel(xpp,
00245                                bCm,
00246                                btCnt->getChildContainer(bCm,true),
00247                                elemName);
00248         else
00249           xpp->nextTag();
00250       }
00251       else{
00252         // a complex type with mixed content model.no support yet
00253       }
00254     }
00255     typeId = typeId1;
00256     sParser_ = s1Parser;
00257     return t;
00258     
00259   }catch (SchemaParserException spe){
00260    
00261     if (!ipTc && t) delete t;
00262     
00263     if(xpp){
00264     
00265       spe.line=xpp->getLineNumber();
00266       spe.col=xpp->getColumnNumber();    
00267       throw spe;
00268     }
00269   }
00270   return 0;
00271 }
00272 
00273 TypeContainer*
00274 SchemaValidator::validateContentModel(XmlPullParser * xpp, 
00275                                       ContentModel* cm,
00276                                       TypeContainer * ipTc,
00277                                       const string & elemName,
00278                                       bool nested,
00279                                       TypeContainer * btCnt)
00280 {
00281   ContentModel::ContentsIterator cit_b=cm->begin();
00282   ContentModel::ContentsIterator cit_e=cm->end();
00283   ContentModel::ContentsIterator ci=cit_e;
00284 
00285   ContentModel::ContentsIterator bci;//base content model iterator
00286   ContentModel * bCm=0;
00287 
00288   
00289   for (ci=cit_b;ci!=cit_e;ci++){
00290     if(ci->second==ContentModel::Particle)
00291       ci->first.e->nOccurrences=0;
00292   }
00293   ci=cit_b;
00294 
00295   if (btCnt) {
00296     int t = btCnt->getTypeId();
00297     const ComplexType* ct = static_cast<const ComplexType*>(btCnt->schemaParser()->getType(t));
00298     bCm = ct->getContents();
00299     bci =bCm->begin();
00300   }
00301 
00302   switch (cm->getCompositor()) {
00303     
00304   case Schema::All:
00305     {
00306       do
00307         {
00308           if (!nested)
00309             xpp->nextTag();
00310           if (xpp->getEventType() == XmlPullParser::END_TAG)
00311             {
00312               if (xpp->getName() == elemName)
00313                 break;
00314               while (xpp->getEventType() != XmlPullParser::START_TAG)
00315                 xpp->nextTag();
00316             }
00317           //All cannot have another content model inside like group/choice etc
00318  
00319           if(!findElement(cit_b,cit_e,xpp->getName(),ci))
00320             error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
00321           ci->first.e->nOccurrences++;
00322 
00323           validate(xpp, ci->first.e->getType(),
00324                    ipTc->getChildContainer(ci->first.e->getName(), true));
00325           //ipTc->getChildContainer(xpp->getName(), true));
00326         }
00327       while (true);
00328 
00329       /*
00330         check for occurrence constraints
00331       */
00332       for (ci=cit_b;ci!=cit_e;ci++){
00333         if(ci->second==ContentModel::Particle && 
00334            (ci->first.e->nOccurrences<ci->first.e->getMin()||
00335             ci->first.e->nOccurrences>ci->first.e->getMax()))
00336           error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
00337       }
00338         
00339       break;
00340     }
00341   case Schema::Sequence:
00342     {
00343       do
00344         {
00345           if (!nested)
00346             xpp->nextTag();
00347             
00348           if(xpp->getEventType() == XmlPullParser::END_TAG){
00349 
00350             if (xpp->getName() == elemName)
00351               break;
00352             if(ci==cit_e)
00353               break;
00354 
00355             //position the xml parser to the next element
00356             while ((xpp->getEventType() != XmlPullParser::START_TAG)&&
00357                    ((xpp->getEventType() != XmlPullParser::END_TAG)||
00358                     (xpp->getName() != elemName)))
00359               xpp->nextTag();
00360           }
00361           //loop through all the contents inside
00362           //the child elements in the content model must be in the same
00363           //order as defined in the <sequence> tag of the schema
00364 
00365           if(ci->second==ContentModel::Container){
00366             
00367             if ((xpp->getEventType() == xpp->END_TAG)&&
00368                 (xpp->getName() == elemName))
00369               break;
00370             //nested content model
00371             validateContentModel(xpp,ci->first.c,
00372                                  ipTc->getChildContainer(ci->first.c,true),
00373                                  elemName,true,btCnt);
00374             ci++;
00375           }
00376           else{
00377 
00378            
00379             if(cm->anyContents() || 
00380                findElement(ci,cit_e,xpp->getName(), ci)){
00381 
00382               ci->first.e->nOccurrences++;
00383               validate(xpp,ci->first.e->getType(),
00384                        ipTc->getChildContainer(ci->first.e->getName(), true));
00385               
00386             }else if (bCm && (bCm->anyContents() ||
00387                       findElement(bCm->begin(),bCm->end(),xpp->getName(), bci))){
00388 
00389               TypeContainer * t = btCnt->getChildContainer(bCm,true);
00390               validate(xpp,bci->first.e->getType(),t->getChildContainer(bci->first.e->getName(),true));
00391 
00392             } else {
00393 
00394               error("Could not find element " +xpp->getName()+" in "+elemName,xpp);           
00395             }
00396 
00397           }
00398         }
00399       while (true);
00400 
00401       /*
00402         check for occurrence constraints
00403       */
00404       for (ci=cit_b;ci!=cit_e;ci++){
00405         if(ci->second==ContentModel::Particle && 
00406            (ci->first.e->nOccurrences<ci->first.e->getMin()||
00407             ci->first.e->nOccurrences>ci->first.e->getMax()))
00408           error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
00409       }
00410       break;
00411     }      
00412   case Schema::Choice:
00413     {
00414 
00415       if (!nested)
00416         xpp->nextTag();
00417         
00418         
00419       if(findElement(ci,cit_e,xpp->getName(), ci)) {
00420         
00421         std::string choiceElem = xpp->getName();
00422         do {
00423         //see if one of the choices is a particle and it occurs in the instance
00424         ci->first.e->nOccurrences++;
00425         validate(xpp, ci->first.e->getType(),
00426                  ipTc->getChildContainer(ci->first.e->getName(), true));
00427         xpp->nextTag();
00428         }while(xpp->getName() == choiceElem);
00429         xpp->prevTag();  
00430         break;
00431       } 
00432       else {
00433         //its a choice which has a content model
00434         ci++;
00435       }
00436       if (ci->second == ContentModel::Container){
00437         
00438         try {
00439           validateContentModel(xpp,ci->first.c,
00440                                ipTc->getChildContainer(ci->first.c,true),
00441                                elemName,true,btCnt);
00442         }
00443         catch (SchemaParserException spe){
00444 
00445           ci++;
00446           //try the other content model
00447           validateContentModel(xpp,ci->first.c,
00448                                ipTc->getChildContainer(ci->first.c,true),
00449                                elemName,true,btCnt);
00450         }
00451       }
00452       else{
00453         
00454         error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
00455       }
00456          
00457       /*
00458        * Only one of the choices is allowed
00459        */
00460         
00461       /*
00462        * check for occurrence constraints
00463        */
00464       if(ci->second==ContentModel::Particle && 
00465          (ci->first.e->nOccurrences<ci->first.e->getMin()||
00466           ci->first.e->nOccurrences>ci->first.e->getMax()))
00467         error(ci->first.e->getName()+"did not meet occurrence constraints",xpp);
00468       
00469       break;
00470     }
00471   }
00472   /*
00473    * reset occurence ocunters
00474    */
00475   for (ci=cit_b;ci!=cit_e;ci++){
00476     
00477     if(ci->second==ContentModel::Particle)
00478       ci->first.e->nOccurrences=0;
00479   }
00480   return ipTc;
00481 }
00482   
00483 
00484 
00485 /*
00486  *  This method validates all supported simple types
00487  *  Both native atomic types and schema defined 
00488  */
00489 
00490 TypeContainer * 
00491 SchemaValidator::validate(void* value ,
00492                           int typeId,
00493                           TypeContainer * ipTc,
00494                           XmlPullParser * xpp)
00495 {
00496   
00497   int basetype = sParser_->getBasicContentType(typeId);
00498   
00499   const XSDType * pType = sParser_->getType(typeId);
00500   if (pType && !pType->isSimple()){
00501     
00502     return 0;
00503   }
00504   const SimpleType  *st = static_cast<const SimpleType*>(pType);
00505   
00506   //check for the validity of the value
00507   //if available also check against restrictions in the schema
00508 
00509   if (!ipTc)
00510     ipTc = new TypeContainer(typeId, sParser_);
00511 
00512   if (st && (st->isList() || st->isUnion())){
00513             
00514     std::string val = *((std::string*)value);
00515     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
00516     return ipTc;
00517   }
00518   switch (basetype)
00519     {
00520     case Schema::XSD_INTEGER:
00521     case Schema::XSD_INT:
00522       {
00523         int x= *((int*)value);
00524         if (!st) {
00525           ipTc->setValue(x);
00526         }
00527         else{
00528 
00529           ipTc->setValue(x,st->isValidInt(x));
00530         }
00531         break;
00532       }
00533     case Schema::XSD_BYTE:
00534       {
00535         char c= *((char*)value);
00536         ipTc->setValue(c);
00537       }
00538       break;
00539     case Schema::XSD_FLOAT:
00540       {
00541         float f = *((float*)value);
00542         if (!st) {
00543           
00544           ipTc->setValue(f);
00545           
00546         }else{
00547           
00548           ipTc->setValue(f,st->isValidFloat(f));
00549         }
00550         break;
00551       }
00552     case Schema::XSD_DOUBLE:
00553     case Schema::XSD_DECIMAL:
00554       {
00555         double db = *((double*)value);
00556         ipTc->setValue(db);
00557       }
00558       break;
00559     case Schema::XSD_LONG:
00560       {
00561         long l = *((long*)value);
00562         ipTc->setValue(l);
00563       }
00564       break;
00565     case Schema::XSD_POSINT:
00566     case Schema::XSD_ULONG:
00567       {
00568         unsigned long  ul= *((unsigned  long*)value);
00569         ipTc->setValue(ul);
00570       }
00571       break;
00572     case Schema::XSD_BOOLEAN:
00573       {
00574         bool b  = *((bool*)value);
00575         ipTc->setValue(b);
00576         break;
00577       }
00578     case Schema::XSD_QNAME:
00579       {
00580         Qname q  = *((Qname* )value);
00581         ipTc->setValue(q);
00582       }
00583       break;
00584     case Schema::XSD_STRING:
00585     default: 
00586       {
00587         std::string val = *((std::string* )value);
00588         if (!st) {
00589           
00590           ipTc->setValue(val);
00591         }
00592         else{
00593           
00594           ipTc->setValue(val,st->isValidString(val));
00595         }
00596       }
00597       break;
00598     }
00599 
00600   return  ipTc;
00601 }
00602 
00603 /*
00604  *  This method validates all supported simple types
00605  *  Both native atomic types and schema defined 
00606  */
00607 
00608 TypeContainer *
00609 SchemaValidator::validate(const string & val,
00610                           int typeId,
00611                           TypeContainer *ipTc,
00612                           XmlPullParser * xpp)
00613 {
00614 
00615   int basetype = sParser_->getBasicContentType(typeId);
00616   if (basetype == Schema::XSD_INVALID) {
00617     
00618     return 0;
00619   }
00620   
00621   const XSDType * pType = sParser_->getType(typeId);
00622   if (pType && 
00623       !pType->isSimple() && 
00624       pType->getContentModel() != Schema::Simple){
00625     
00626     return 0;
00627   }
00628 
00629   if (pType && !pType->isSimple() && 
00630       pType->getContentModel() ==Schema::Simple) {
00631     //this is a complex type but has a simple content model
00632     
00633     const ComplexType * ct = static_cast<const ComplexType*>(pType);
00634     int contentType = ct->getContentType();
00635     return validate(val,contentType,ipTc,xpp);
00636 
00637   }
00638   const SimpleType  *st = static_cast<const SimpleType*>(pType);
00639   
00640   //check for the validity of the value
00641   //if available also check against restrictions in the schema
00642 
00643   if (!ipTc)
00644     ipTc = new TypeContainer(typeId, sParser_);
00645   ipTc->setValAsString(val);
00646 
00647   while(ipTc->isValueValid()){
00648     
00649     extractSimpleType(val, basetype, ipTc, st, xpp);
00650 
00651     
00652     if(!st || (st && (st->isList() || st->isUnion()))){
00653       
00654       break;
00655       //if we validated an atomic type we are done
00656       //if we just validated a list or union,there is no need 
00657       //to continue checking base types
00658     }
00659 
00660     if (!sParser_->isBasicType(st->getBaseTypeId())){
00661       
00662       st=static_cast<const SimpleType*>(sParser_->getType(st->getBaseTypeId()));
00663     }
00664     else{
00665       st = 0;
00666     }
00667   }
00668   return ipTc;
00669 }
00670 
00671 
00672 void 
00673 SchemaValidator::extractSimpleType(const std::string & val,
00674                                    int basetype,
00675                                    TypeContainer * ipTc,
00676                                    const SimpleType * st,
00677                                    XmlPullParser * xpp)
00678 {
00679 
00680   if (st && (st->isList() || st->isUnion())){
00681             
00682     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
00683     return;
00684   }
00685   
00686   istringstream istr(val);
00687   int x;
00688   double db;
00689   long l;
00690   char c;
00691   unsigned long  ul;
00692   float f;
00693 
00694   switch (basetype)
00695     {
00696     case Schema::XSD_INTEGER:
00697     case Schema::XSD_INT:
00698       {
00699         istr >> x;
00700         if (!st) {
00701           ipTc->setValue(x,!istr.fail());
00702         }
00703         else{
00704 
00705           ipTc->setValue(x,!istr.fail() && st->isValidInt(x));
00706         }
00707         break;
00708       }
00709     case Schema::XSD_BYTE:
00710       istr >> c;
00711       ipTc->setValue(c,!istr.fail());
00712       break;
00713     case Schema::XSD_FLOAT:
00714       {
00715         istr >> f;
00716         if (!st) {
00717           ipTc->setValue(f,!istr.fail());
00718         }else{
00719           ipTc->setValue(f,!istr.fail() && st->isValidFloat(f));
00720         }
00721         break;
00722       }
00723     case Schema::XSD_DOUBLE:
00724     case Schema::XSD_DECIMAL:
00725       istr >> db;
00726       ipTc->setValue(db,!istr.fail());
00727       break;
00728     case Schema::XSD_LONG:
00729       istr >> l;
00730       ipTc->setValue(l,!istr.fail());
00731       break;
00732     case Schema::XSD_POSINT:
00733     case Schema::XSD_ULONG:
00734       istr >> ul;
00735       ipTc->setValue(ul,!istr.fail());
00736       break;
00737     case Schema::XSD_BOOLEAN:
00738       {
00739 
00740         if(val=="true" ||
00741            val=="yes" ||
00742            val=="1")
00743         
00744           ipTc->setValue(true);
00745         else
00746           ipTc->setValue(false);
00747         break;
00748       }
00749     case Schema::XSD_QNAME:
00750       {
00751         Qname q(val);
00752         if (xpp)
00753           q.setNamespace(xpp->getNamespace(q.getPrefix()));
00754         ipTc->setValue(q);
00755         break;
00756       }
00757     case Schema::XSD_STRING:
00758     default: 
00759       {
00760         if (!st) {
00761             
00762           ipTc->setValue(val);
00763         }
00764         else{
00765           if (basetype == Schema::XSD_STRING)
00766             ipTc->setValue(val,st->isValidString(val));
00767           else
00768             ipTc->setValue(val);//other types such as date for which no validation is done
00769         }
00770       }
00771       break;
00772     }
00773 }
00774 
00775 /*
00776  * This function validates a string as a list or union 
00777  * for the simple type 
00778  */
00779 
00780 bool
00781 SchemaValidator::validateListOrUnion(const SimpleType* st,
00782                                      const std::string &val,
00783                                      XmlPullParser * xpp)
00784 {
00785   if (st->isList()){
00786    
00787     size_t s = 0;
00788 
00789     while(s < val.length()){
00790       while(val[s]==' ')s++;
00791       std::string t = val.substr(s,val.find(' ',s)-s);
00792       TypeContainer * tc = validate(t,st->getBaseTypeId(),0,xpp);
00793       if (!(tc && tc->isValueValid()))
00794         return false;
00795       s+=t.length()+1;
00796     }
00797     return true ;
00798   
00799   }else if (st->isUnion()){
00800     
00801     std::list<int>::const_iterator it= st->unionTypes()->begin();
00802     while (it!=st->unionTypes()->end()){
00803       
00804       TypeContainer * tc = validate(val,*it,0,xpp);
00805       
00806       if (tc && tc->isValueValid())
00807         return true;
00808       it++;
00809     }
00810     return false;
00811   }
00812   else{
00813     return false;
00814   }
00815 }
00816 /*
00817  * This function searches for a child element in a complex type 
00818  * The iterator pElem is set to point to the found element
00819  * rewind controls whether a search is to be done by resetting pElem 
00820  * to the begining of the list 
00821  * Returns true if element is found else false 
00822  */
00823 
00824 bool
00825 SchemaValidator::findElement(ContentModel::ContentsIterator start, 
00826                              ContentModel::ContentsIterator end, 
00827                              std::string name,
00828                              ContentModel::ContentsIterator & found)
00829 {
00830   for (ContentModel::ContentsIterator ci=start;
00831        ci!=end;
00832        ci++){
00833     
00834     if(ci->second==ContentModel::Particle){
00835 #ifdef LOGGING
00836       std::cout<<"Looking for "<< name<<" found "<<ci->first.e->getName()<<std::endl;
00837 #endif
00838       if(ci->first.e->getName()==name ||
00839          ci->first.e->getName() == "*")//* is  a hack for soap arrays
00840         {
00841           found=ci;
00842           return true;
00843         }
00844     }
00845   }
00846   return false;
00847 }
00848 
00849 void SchemaValidator::error(const std::string& mesg,XmlPullParser* xpp)
00850 {
00851     
00852   SchemaParserException spe(mesg + "\nError validating schema instance\n");
00853   if(xpp){
00854     
00855     spe.line=xpp->getLineNumber();
00856     spe.col=xpp->getColumnNumber();
00857   }
00858   throw spe;
00859 }
00860 
00861 
00862 bool
00863 SchemaValidator::checkAttributeOccurence(const ComplexType* ct ,
00864                                          XmlPullParser* xpp)
00865 {
00866 
00867   if (ct->getNumAttributes() > 0)
00868     {
00869       for (int i = 0; i < ct->getNumAttributes(); i++)
00870         {
00871           const Attribute*at = ct->getAttribute(i);
00872               
00873           /*
00874             Check for the correctness of each attribute
00875           */
00876           string attVal = xpp->getAttributeValue("", at->getName());
00877           if (attVal.empty())
00878             {
00879               if (at->isRequired())
00880                 error("Required attribute \"" + at->getName() +
00881                       "\" missing or empty",xpp);
00882 
00883               else
00884                 continue;
00885             }
00886         }
00887     }
00888   return true;
00889 }
00890 
00891 
00892 
00893 bool
00894 SchemaValidator::instance(const std::string& tag,
00895                           Schema::Type type_id)
00896 
00897 {
00898 
00899   //generate an instance of the given type
00900   std::string nsp = sParser_->getNamespace();
00901   xmlStream_ = new XmlSerializer(ostr_); //xml serializer
00902   
00903   if (!nsp.empty()) 
00904     xmlStream_->setPrefix("s",nsp);
00905   
00906   xmlStream_->setPrefix("xsi",Schema::SchemaInstaceUri);
00907   xmlStream_->startDocument("UTF-8",false);
00908 
00909   return instance1(tag,type_id);
00910 }
00911 
00912 bool
00913 SchemaValidator::instance1(const std::string &tag,
00914                            Schema::Type type_id)
00915 {
00916 
00917   std::string nsp = sParser_->getNamespace();
00918   static bool first = false;
00919   xmlStream_->startTag(nsp,tag);
00920   if (!first){
00921     xmlStream_->attribute("",
00922                           "xmlns",
00923                           nsp);
00924     first = true;
00925   }
00926 
00927 
00928   //  xmlStream_->attribute(Schema::SchemaInstaceUri,
00929   //            "type",
00930   //            "s:"+sParser_->getTypeName(type_id));
00931   const XSDType * pType = sParser_->getType(type_id);
00932 
00933   if ( pType== 0 ||
00934        pType->isSimple()){
00935 
00936     xmlStream_->text(""); //simple content types
00937     
00938   }
00939   else {
00940 
00941     const ComplexType * ct =
00942       static_cast<const ComplexType*>(pType);
00943     
00944     //print attributes if any
00945     if (ct->getNumAttributes() > 0) {
00946       
00947       for (int i = 0; i < ct->getNumAttributes(); i++) {
00948         
00949         const Attribute*at = ct->getAttribute(i);
00950         xmlStream_->attribute(sParser_->getNamespace(),at->getName(),"");
00951       }
00952     }
00953   
00954 
00955     if (ct->getContentModel() == Schema::Simple) {
00956       
00957       xmlStream_->text("");
00958     }
00959     else{
00960 
00961       ContentModel* cm=ct->getContents();
00962       instanceCM(cm);
00963       
00964     }
00965   }
00966   xmlStream_->endTag(nsp,tag);
00967   return  true;
00968 }
00969 
00970 
00971 
00972 
00973 void
00974 SchemaValidator::instanceCM(ContentModel *cm)
00975         
00976 {
00977   
00978   ContentModel::ContentsIterator cit_b=cm->begin();
00979   ContentModel::ContentsIterator cit_e=cm->end();
00980   ContentModel::ContentsIterator ci=cit_b;
00981 
00982   switch (cm->getCompositor())
00983     {
00984     case Schema::All:
00985     case Schema::Sequence:
00986     case Schema::Choice:
00987       {
00988         // a simple logic to start with
00989         // not taking care of all,choice ,sequence as of now
00990         
00991         for (ci=cit_b;ci!=cit_e;ci++){
00992           
00993           if(ci->second==ContentModel::Particle &&
00994              ci->first.e->getMax() > 0){
00995 
00996             const SchemaParser* s1Parser = sParser_;
00997             Schema::Type t=(Schema::Type)ci->first.e->getType();
00998             
00999             if (!ci->first.e->getTypeNamespace().empty() &&
01000                 sParser_->isImported(ci->first.e->getTypeNamespace()) &&
01001                 sParser_->getNamespace() != ci->first.e->getTypeNamespace()) {
01002         
01003               //here the type of the element is defined in another imported schemaparser
01004               //so try to get the pointer.
01005               t = (Schema::Type)sParser_->getType(t)->getTypeId();
01006               sParser_ = sParser_->getImportedSchemaParser(ci->first.e->getTypeNamespace());
01007             }
01008            
01009             instance1(ci->first.e->getName(),t);
01010             sParser_ = s1Parser;
01011           }
01012           else if (ci->second==ContentModel::Container) {
01013             
01014             //nested xsd:sequence inside choice..nested content models
01015             instanceCM(ci->first.c);
01016               
01017           }
01018           else if (ci->second==ContentModel::ParticleGroup){
01019             
01020             //xsd:group inside 
01021             instanceCM(ci->first.g->getContents());
01022                                 
01023           }
01024         }
01025         break;
01026       }
01027     }
01028 }
01029 
01030 }
01031 //TODO validation of <any>
01032 //TODO validation of base64binary,hexBinary
01033 //TODO validation of types derived by extension/restriction of complex types
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by  doxygen 1.6.2