src/schemaparser/SchemaValidator.cpp

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 {
00033   sParser = sp;
00034 }
00035 
00036 SchemaValidator::~SchemaValidator()
00037 {
00038 }
00039 
00040 
00041 /*
00042   Main entry method for validation
00043   Inputs
00044   1. XmlStream ,xpp.getName() muct return the name of the  type
00045   which must be validated
00046   2. typeId of the type against which this stream must be
00047   validated against
00048   3.An Input type container  (default  0)
00049 */
00050 TypeContainer *
00051 SchemaValidator::validate(XmlPullParser * xpp, 
00052                           int typeId,
00053                           TypeContainer * ipTc)
00054 {
00055   try{  
00056     TypeContainer *t;
00057     string elemName = xpp->getName();
00058 
00059 
00060     if (!ipTc)
00061       t = new TypeContainer(typeId, sParser);
00062     else
00063       t = ipTc;
00064 
00065     if (t->getTypeId() != typeId)
00066       error("Fatal error ,container's type is not same as the validated type",xpp);
00067 
00068     // a schema definition inside an instance
00069     if (typeId == Schema::XSD_SCHEMA){
00070       
00071       SchemaParser * ssParser = new SchemaParser(xpp);
00072       if (!ssParser->parseSchemaTag()){
00073         
00074         return 0;
00075       }
00076       return t;
00077     }
00078 
00079     //ignore ANY
00080     if (typeId == Schema::XSD_ANY){
00081       
00082       xpp->skipSubTree();
00083       return t;
00084     }
00085     
00086     if (sParser->getType(typeId) == 0
00087         || sParser->getType(typeId)->isSimple()) {
00088 
00089       //simple type validation
00090       string val;
00091       xpp->nextToken();
00092       if (xpp->getEventType() == XmlPullParser::TEXT ||
00093           xpp->getEventType() == XmlPullParser::ENTITY_REF){
00094 
00095         val = xpp->getText();
00096 
00097         xpp->nextToken();
00098         while (xpp->getEventType() == XmlPullParser::ENTITY_REF ||
00099                xpp->getEventType() == XmlPullParser::TEXT){
00100 
00101           val += xpp->getText();
00102           xpp->nextToken();
00103             
00104         }
00105         validate(val, typeId, t,xpp);
00106       }
00107       else{
00108         //text was probably empty,nevertheless create  a type container 
00109         validate(val, typeId, t, xpp);
00110       }
00111       if (xpp->getEventType() == XmlPullParser::END_TAG)
00112         {
00113           if (xpp->getName() != elemName)
00114             error("Syntax error "+elemName,xpp);
00115         }
00116       else
00117         error("Expected a closing tag for " + elemName,xpp);
00118     }
00119     else {
00120 
00121       /*
00122         Perform Validation of Complex types
00123         Check for
00124         1.Is the tag name correct (this has to be right !!)
00125         2.Attributes ,if any should be valid
00126         3.Are there any mandatory (#required) attributes
00127         4. Validate its content model 
00128         6.Return the type container which has the
00129         correctly filled in values
00130 
00131       */
00132       const ComplexType *ct =
00133         static_cast<const ComplexType *>(sParser->getType(typeId));
00134         
00135       const ComplexType * bt = 0;
00136       TypeContainer * btCnt = 0;
00137       if (ct->getBaseTypeId()!=Schema::XSD_ANYTYPE) {
00138 
00139         bt = static_cast<const ComplexType*>
00140           (sParser->getType(ct->getBaseTypeId()));
00141         btCnt = t->getBaseTypeContainer(true);
00142       }
00143         
00144       int attcnt = xpp->getAttributeCount();
00145         
00146       for (int i = 0; i < attcnt; i++) {
00147           
00148         std::string attName = xpp->getAttributeName(i);
00149         std::string attVal = xpp->getAttributeValue("", attName);
00150         std::string attNsp = xpp->getAttributeNamespace(i);
00151         if (!attNsp.empty() && attNsp != sParser->getNamespace())
00152           continue;
00153 
00154         const Attribute*at = 0;
00155         TypeContainer *atCnt = 0;
00156         at = ct->getAttribute(attName);
00157 
00158         if (!at && bt){
00159           at  = bt->getAttribute(attName);
00160           if (at)
00161             atCnt = btCnt->getAttributeContainer(attName, true);
00162         }
00163         else{
00164           atCnt = t->getAttributeContainer(attName, true);
00165         }
00166 
00167         if (!at)
00168           error("Unkown attribute \"" + attName +  "\"",xpp);
00169 
00170         validate(attVal, at->getType(), atCnt, xpp);
00171       }
00172         
00173       //see if some required attributes are missing
00174       checkAttributeOccurence(ct,xpp);
00175       if (bt)
00176         checkAttributeOccurence(bt,xpp);
00177 
00178 
00179       if (ct->getContentModel() == Schema::Simple)
00180         {
00181           //complex types with a simple content model
00182 
00183           string val;
00184           xpp->nextToken();
00185           if (xpp->getEventType() == xpp->TEXT){
00186             val = xpp->getText();
00187             validate(val, ct->getContentType(), t, xpp);
00188             xpp->nextTag();
00189           }
00190           else{
00191             //text was probably empty,nevertheless create  a type container 
00192             validate(val, ct->getContentType(), t, xpp);
00193           }
00194 
00195           if (xpp->getEventType() == XmlPullParser::END_TAG)
00196             {
00197               if (xpp->getName() != elemName)
00198                 error("Syntax error",xpp);
00199             }
00200           else
00201             error("Expected a closing tag for " + elemName,xpp);
00202         }
00203       else if (ct->getContentModel() == Schema::Complex){
00204         //a complex type with complex content model
00205         ContentModel* cm=ct->getContents();
00206         if(cm)
00207           validateContentModel(xpp,
00208                                cm,
00209                                t->getChildContainer(cm,true),
00210                                elemName);
00211         else
00212           xpp->nextTag();
00213       }
00214       else{
00215         // a complex type with mixed content model.no support yet
00216       }
00217     }
00218     return t;
00219   }catch (SchemaParserException spe){
00220     if(xpp){
00221       spe.line=xpp->getLineNumber();
00222       spe.col=xpp->getColumnNumber();    
00223       throw spe;
00224     }
00225   }
00226   return 0;
00227 }
00228 
00229 TypeContainer*
00230 SchemaValidator::validateContentModel(XmlPullParser * xpp, 
00231                                       ContentModel* cm,
00232                                       TypeContainer * ipTc,
00233                                       const string & elemName,
00234                                       bool nested)
00235 {
00236   ContentModel::ContentsIterator cit_b=cm->begin();
00237   ContentModel::ContentsIterator cit_e=cm->end();
00238   ContentModel::ContentsIterator ci=cit_e;
00239   
00240   for (ci=cit_b;ci!=cit_e;ci++){
00241     if(ci->second==ContentModel::Particle)
00242       ci->first.e->nOccurrences=0;
00243   }
00244   ci=cit_b;
00245   switch (cm->getCompositor()) {
00246     
00247   case Schema::All:
00248     {
00249       do
00250         {
00251           if (!nested)
00252             xpp->nextTag();
00253           if (xpp->getEventType() == XmlPullParser::END_TAG)
00254             {
00255               if (xpp->getName() == elemName)
00256                 break;
00257               while (xpp->getEventType() != XmlPullParser::START_TAG)
00258                 xpp->nextTag();
00259             }
00260           //All cannot have another content model inside like group/choice etc
00261  
00262           if(!findElement(cit_b,cit_e,xpp->getName(),ci))
00263             error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
00264           ci->first.e->nOccurrences++;
00265 
00266           validate(xpp, ci->first.e->getType(),
00267                    ipTc->getChildContainer(ci->first.e->getName(), true));
00268           //ipTc->getChildContainer(xpp->getName(), true));
00269         }
00270       while (true);
00271 
00272       /*
00273         check for occurrence constraints
00274       */
00275       for (ci=cit_b;ci!=cit_e;ci++){
00276         if(ci->second==ContentModel::Particle && 
00277            (ci->first.e->nOccurrences<ci->first.e->getMin()||
00278             ci->first.e->nOccurrences>ci->first.e->getMax()))
00279           error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
00280       }
00281         
00282       break;
00283     }
00284   case Schema::Sequence:
00285     {
00286       do
00287         {
00288           if (!nested)
00289             xpp->nextTag();
00290             
00291           if(xpp->getEventType() != XmlPullParser::END_TAG){
00292 
00293             if(ci->second==ContentModel::Particle &&
00294                xpp->getName()!=ci->first.e->getName() &&
00295                ci->first.e->getName()!="*") 
00296               ci++;
00297             //check for multiple occurrences of the same element
00298             //if the same element occurrs more than once dont advance iterator ci
00299 
00300             //TODO multiple occurrences of a content model like sequence
00301             //cant be validated as yet
00302           }else {
00303               
00304             if (xpp->getName() == elemName)
00305               break;
00306             if(ci==cit_e)
00307               break;
00308             /*      while (xpp->getEventType() != XmlPullParser::START_TAG)
00309                     xpp->nextTag();*/
00310 
00311             while ((xpp->getEventType() != XmlPullParser::START_TAG)&&
00312                    ((xpp->getEventType() != XmlPullParser::END_TAG)||
00313                     (xpp->getName() != elemName)))
00314               xpp->nextTag();
00315           }
00316 
00317           if(ci->second==ContentModel::Container){
00318             
00319             if ((xpp->getEventType() == xpp->END_TAG)&&
00320                 (xpp->getName() == elemName))
00321               break;
00322             validateContentModel(xpp,ci->first.c,
00323                                  ipTc->getChildContainer(ci->first.c,true),
00324                                  elemName,true);
00325             ci++;
00326           }
00327           else{
00328 
00329             if(!findElement(ci,cit_e,xpp->getName(), ci) &&
00330                !cm->anyContents())
00331               error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
00332               
00333             ci->first.e->nOccurrences++;
00334             validate(xpp,ci->first.e->getType(),
00335                      ipTc->getChildContainer(ci->first.e->getName(), true));
00336             //ipTc->getChildContainer(xpp->getName(), true));
00337           }
00338         }
00339       while (true);
00340 
00341       /*
00342         check for occurrence constraints
00343       */
00344       for (ci=cit_b;ci!=cit_e;ci++){
00345         if(ci->second==ContentModel::Particle && 
00346            (ci->first.e->nOccurrences<ci->first.e->getMin()||
00347             ci->first.e->nOccurrences>ci->first.e->getMax()))
00348           error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
00349       }
00350       break;
00351     }      
00352   case Schema::Choice:
00353     {
00354 
00355       if (!nested)
00356         xpp->nextTag();
00357         
00358         
00359       if(findElement(ci, cit_e, xpp->getName(), ci)) {
00360           
00361         //see if one of the choices is a particle and it occurs in the instance
00362         ci->first.e->nOccurrences++;
00363         validate(xpp, ci->first.e->getType(),
00364                  ipTc->getChildContainer(ci->first.e->getName(), true));
00365           
00366         break;
00367       } 
00368       else {
00369         //its a choice which has a content model
00370         ci++;
00371       }
00372       if (ci->second == ContentModel::Container){
00373         
00374         try {
00375           validateContentModel(xpp,ci->first.c,
00376                                ipTc->getChildContainer(ci->first.c,true),
00377                                elemName,true);
00378         }
00379         catch (SchemaParserException spe){
00380 
00381           ci++;
00382           //try the other content model
00383           validateContentModel(xpp,ci->first.c,
00384                                ipTc->getChildContainer(ci->first.c,true),
00385                                elemName,true);
00386         }
00387       }
00388       else{
00389         
00390         error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
00391       }
00392          
00393       /*
00394        * Only one of the choices is allowed
00395        */
00396         
00397       /*
00398        * check for occurrence constraints
00399        */
00400       if(ci->second==ContentModel::Particle && 
00401          (ci->first.e->nOccurrences<ci->first.e->getMin()||
00402           ci->first.e->nOccurrences>ci->first.e->getMax()))
00403         error(ci->first.e->getName()+"did not meet occurrence constraints",xpp);
00404       
00405       break;
00406     }
00407   }
00408   /*
00409    * reset occurence ocunters
00410    */
00411   for (ci=cit_b;ci!=cit_e;ci++){
00412     
00413     if(ci->second==ContentModel::Particle)
00414       ci->first.e->nOccurrences=0;
00415   }
00416   return ipTc;
00417 }
00418   
00419 
00420 
00421 /*
00422  *  This method validates all supported simple types
00423  *  Both native atomic types and schema defined 
00424  */
00425 
00426 TypeContainer * 
00427 SchemaValidator::validate(void* value ,
00428                           int typeId,
00429                           TypeContainer * ipTc,
00430                           XmlPullParser * xpp)
00431 {
00432   
00433   int basetype = sParser->getBasicContentType(typeId);
00434   
00435   const XSDType * pType = sParser->getType(typeId);
00436   if (pType && !pType->isSimple()){
00437     
00438     return 0;
00439   }
00440   const SimpleType  *st = static_cast<const SimpleType*>(pType);
00441   
00442   //check for the validity of the value
00443   //if available also check against restrictions in the schema
00444 
00445   if (!ipTc)
00446     ipTc = new TypeContainer(typeId, sParser);
00447 
00448   if (st && (st->isList() || st->isUnion())){
00449             
00450     std::string val = *((std::string*)value);
00451     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
00452     return ipTc;
00453   }
00454   switch (basetype)
00455     {
00456     case Schema::XSD_INTEGER:
00457     case Schema::XSD_INT:
00458       {
00459         int x= *((int*)value);
00460         if (!st) {
00461           ipTc->setValue(x);
00462         }
00463         else{
00464 
00465           ipTc->setValue(x,st->isValidInt(x));
00466         }
00467         break;
00468       }
00469     case Schema::XSD_BYTE:
00470       {
00471         char c= *((char*)value);
00472         ipTc->setValue(c);
00473       }
00474       break;
00475     case Schema::XSD_FLOAT:
00476       {
00477         float f = *((float*)value);
00478         if (!st) {
00479           
00480           ipTc->setValue(f);
00481           
00482         }else{
00483           
00484           ipTc->setValue(f,st->isValidFloat(f));
00485         }
00486         break;
00487       }
00488     case Schema::XSD_DOUBLE:
00489     case Schema::XSD_DECIMAL:
00490       {
00491         double db = *((double*)value);
00492         ipTc->setValue(db);
00493       }
00494       break;
00495     case Schema::XSD_LONG:
00496       {
00497         long l = *((long*)value);
00498         ipTc->setValue(l);
00499       }
00500       break;
00501     case Schema::XSD_POSINT:
00502     case Schema::XSD_ULONG:
00503       {
00504         unsigned long long ul= *((unsigned long long*)value);
00505         ipTc->setValue(ul);
00506       }
00507       break;
00508     case Schema::XSD_BOOLEAN:
00509       {
00510         bool b  = *((bool*)value);
00511         ipTc->setValue(b);
00512         break;
00513       }
00514     case Schema::XSD_QNAME:
00515       {
00516         Qname q  = *((Qname* )value);
00517         ipTc->setValue(q);
00518       }
00519       break;
00520     case Schema::XSD_STRING:
00521     default: 
00522       {
00523         std::string val = *((std::string* )value);
00524         if (!st) {
00525           
00526           ipTc->setValue(val);
00527         }
00528         else{
00529           
00530           ipTc->setValue(val,st->isValidString(val));
00531         }
00532       }
00533       break;
00534     }
00535 
00536   return  ipTc;
00537 }
00538 
00539 /*
00540  *  This method validates all supported simple types
00541  *  Both native atomic types and schema defined 
00542  */
00543 
00544 TypeContainer *
00545 SchemaValidator::validate(const string & val,
00546                           int typeId,
00547                           TypeContainer *ipTc,
00548                           XmlPullParser * xpp)
00549 {
00550 
00551   int basetype = sParser->getBasicContentType(typeId);
00552   if (basetype == Schema::XSD_INVALID) {
00553     
00554     return 0;
00555   }
00556   
00557   const XSDType * pType = sParser->getType(typeId);
00558   if (pType && 
00559       !pType->isSimple() && 
00560       pType->getContentModel() != Schema::Simple){
00561     
00562     return 0;
00563   }
00564 
00565   if (pType && !pType->isSimple() && 
00566       pType->getContentModel() ==Schema::Simple) {
00567     //this is a complex type but has a simple content model
00568     
00569     const ComplexType * ct = static_cast<const ComplexType*>(pType);
00570     int contentType = ct->getContentType();
00571     return validate(val,contentType,ipTc,xpp);
00572 
00573   }
00574   const SimpleType  *st = static_cast<const SimpleType*>(pType);
00575   
00576   //check for the validity of the value
00577   //if available also check against restrictions in the schema
00578 
00579   if (!ipTc)
00580     ipTc = new TypeContainer(typeId, sParser);
00581   ipTc->setValAsString(val);
00582 
00583   while(ipTc->isValueValid()){
00584     
00585     extractSimpleType(val, basetype, ipTc, st, xpp);
00586 
00587     
00588     if(!st || (st && (st->isList() || st->isUnion()))){
00589       
00590       break;
00591       //if we validated an atomic type we are done
00592       //if we just validated a list or union,there is no need 
00593       //to continue checking base types
00594     }
00595 
00596     if (!sParser->isBasicType(st->getBaseTypeId())){
00597       
00598       st=static_cast<const SimpleType*>(sParser->getType(st->getBaseTypeId()));
00599     }
00600     else{
00601       st = 0;
00602     }
00603   }
00604   return ipTc;
00605 }
00606 
00607 
00608 void 
00609 SchemaValidator::extractSimpleType(const std::string & val,
00610                                    int basetype,
00611                                    TypeContainer * ipTc,
00612                                    const SimpleType * st,
00613                                    XmlPullParser * xpp)
00614 {
00615 
00616   if (st && (st->isList() || st->isUnion())){
00617             
00618     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
00619     return;
00620   }
00621   
00622   istringstream istr(val);
00623   int x;
00624   double db;
00625   long l;
00626   char c;
00627   unsigned long long ul;
00628   float f;
00629 #ifdef LOGGING
00630   std::cout<<val<<std::endl;
00631 #endif
00632   switch (basetype)
00633     {
00634     case Schema::XSD_INTEGER:
00635     case Schema::XSD_INT:
00636       {
00637         istr >> x;
00638         if (!st) {
00639           ipTc->setValue(x,!istr.fail());
00640         }
00641         else{
00642 
00643           ipTc->setValue(x,!istr.fail() && st->isValidInt(x));
00644         }
00645         break;
00646       }
00647     case Schema::XSD_BYTE:
00648       istr >> c;
00649       ipTc->setValue(c,!istr.fail());
00650       break;
00651     case Schema::XSD_FLOAT:
00652       {
00653         istr >> f;
00654         if (!st) {
00655           ipTc->setValue(f,!istr.fail());
00656         }else{
00657           ipTc->setValue(f,!istr.fail() && st->isValidFloat(f));
00658         }
00659         break;
00660       }
00661     case Schema::XSD_DOUBLE:
00662     case Schema::XSD_DECIMAL:
00663       istr >> db;
00664       ipTc->setValue(db,!istr.fail());
00665       break;
00666     case Schema::XSD_LONG:
00667       istr >> l;
00668       ipTc->setValue(l,!istr.fail());
00669       break;
00670     case Schema::XSD_POSINT:
00671     case Schema::XSD_ULONG:
00672       istr >> ul;
00673       ipTc->setValue(ul,!istr.fail());
00674       break;
00675     case Schema::XSD_BOOLEAN:
00676       {
00677 
00678         if(val=="true" ||
00679            val=="yes" ||
00680            val=="1")
00681         
00682           ipTc->setValue(true);
00683         else
00684           ipTc->setValue(false);
00685         break;
00686       }
00687     case Schema::XSD_QNAME:
00688       {
00689         Qname q(val);
00690         if (xpp)
00691           q.setNamespace(xpp->getNamespace(q.getPrefix()));
00692         ipTc->setValue(q);
00693         break;
00694       }
00695     case Schema::XSD_STRING:
00696     default: 
00697       {
00698         if (!st) {
00699             
00700           ipTc->setValue(val);
00701         }
00702         else{
00703           if (basetype == Schema::XSD_STRING)
00704             ipTc->setValue(val,st->isValidString(val));
00705           else
00706             ipTc->setValue(val);//other types such as date for which no validation is done
00707         }
00708       }
00709       break;
00710     }
00711 }
00712 
00713 /*
00714  * This function validates a string as a list or union 
00715  * for the simple type 
00716  */
00717 
00718 bool
00719 SchemaValidator::validateListOrUnion(const SimpleType* st,
00720                                      const std::string &val,
00721                                      XmlPullParser * xpp)
00722 {
00723   if (st->isList()){
00724    
00725     size_t s = 0;
00726 
00727     while(s < val.length()){
00728       while(val[s]==' ')s++;
00729       std::string t = val.substr(s,val.find(' ',s)-s);
00730       TypeContainer * tc = validate(t,st->getBaseTypeId(),0,xpp);
00731       if (!(tc && tc->isValueValid()))
00732         return false;
00733       s+=t.length()+1;
00734     }
00735     return true ;
00736   
00737   }else if (st->isUnion()){
00738     
00739     std::list<int>::const_iterator it= st->unionTypes()->begin();
00740     while (it!=st->unionTypes()->end()){
00741       TypeContainer * tc = validate(val,*it,0,xpp);
00742       if (tc && tc->isValueValid())
00743         return true;
00744     }
00745     return false;
00746   }
00747   else{
00748     return false;
00749   }
00750 }
00751 /*
00752  * This function searches for a child element in a complex type 
00753  * The iterator pElem is set to point to the found element
00754  * rewind controls whether a search is to be done by resetting pElem 
00755  * to the begining of the list 
00756  * Returns true if element is found else false 
00757  */
00758 
00759 bool
00760 SchemaValidator::findElement(ContentModel::ContentsIterator start, 
00761                              ContentModel::ContentsIterator end, 
00762                              std::string name,
00763                              ContentModel::ContentsIterator & found)
00764 {
00765   for (ContentModel::ContentsIterator ci=start;
00766        ci!=end;
00767        ci++){
00768     
00769     if(ci->second==ContentModel::Particle){
00770       if(ci->first.e->getName()==name ||
00771          ci->first.e->getName() == "*")
00772         {
00773           found=ci;
00774           return true;
00775         }
00776     }
00777   }
00778   return false;
00779 }
00780 
00781 void SchemaValidator::error(const std::string& mesg,XmlPullParser* xpp)
00782 {
00783     
00784   SchemaParserException spe(mesg + "\nError validating schema instance\n");
00785   if(xpp){
00786     
00787     spe.line=xpp->getLineNumber();
00788     spe.col=xpp->getColumnNumber();
00789   }
00790   throw spe;
00791 }
00792 
00793 
00794 bool
00795 SchemaValidator::checkAttributeOccurence(const ComplexType* ct ,
00796                                          XmlPullParser* xpp)
00797 {
00798 
00799   if (ct->getNumAttributes() > 0)
00800     {
00801       for (int i = 0; i < ct->getNumAttributes(); i++)
00802         {
00803           const Attribute*at = ct->getAttribute(i);
00804               
00805           /*
00806             Check for the correctness of each attribute
00807           */
00808           string attVal = xpp->getAttributeValue("", at->getName());
00809           if (attVal.empty())
00810             {
00811               if (at->isRequired())
00812                 error("Required attribute \"" + at->getName() +
00813                       "\" missing or empty",xpp);
00814 
00815               else
00816                 continue;
00817             }
00818         }
00819     }
00820   return true;
00821 }
00822 }
00823 //TODO validation of <any>
00824 //TODO validation of base64binary,hexBinary
00825 //TODO validation of types derived by extension/restriction of complex types

Generated on Sun Nov 26 03:04:42 2006 for wsdlpull by  doxygen 1.4.6