00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <sstream>
00022 #include "schemaparser/SchemaValidator.h"
00023 using namespace std;
00024
00025 namespace Schema {
00026
00027
00028
00029
00030
00031 SchemaValidator::SchemaValidator(const SchemaParser * sp)
00032 {
00033 sParser = sp;
00034 }
00035
00036 SchemaValidator::~SchemaValidator()
00037 {
00038 }
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
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
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
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
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
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
00123
00124
00125
00126
00127
00128
00129
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
00174 checkAttributeOccurence(ct,xpp);
00175 if (bt)
00176 checkAttributeOccurence(bt,xpp);
00177
00178
00179 if (ct->getContentModel() == Schema::Simple)
00180 {
00181
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
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
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
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
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
00269 }
00270 while (true);
00271
00272
00273
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
00298
00299
00300
00301
00302 }else {
00303
00304 if (xpp->getName() == elemName)
00305 break;
00306 if(ci==cit_e)
00307 break;
00308
00309
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
00337 }
00338 }
00339 while (true);
00340
00341
00342
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
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
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
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
00395
00396
00397
00398
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
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
00423
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
00443
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
00541
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
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
00577
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
00592
00593
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);
00707 }
00708 }
00709 break;
00710 }
00711 }
00712
00713
00714
00715
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
00753
00754
00755
00756
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
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
00824
00825