wsdlpull 1.23
|
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