1 /*
2  * wsdlpull - A C++ parser  for WSDL  (Web services description language)
3  * Copyright (C) 2005-2007 Vivek Krishna
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *
20  */
21 #include <sstream>
22 #include "schemaparser/SchemaValidator.h"
23 using namespace std;
24 
25 namespace Schema {
26 /*
27   This class validates an incoming Xml instance against a given type
28   whose schema has been processed by a given SchemaParser instance
29 
30 */
SchemaValidator(const SchemaParser * sp,std::ostream & os)31 SchemaValidator::SchemaValidator(const SchemaParser * sp,
32 				 std::ostream& os)
33   :ostr_(os),
34    sParser_(sp)
35 {
36 
37 
38 }
39 
~SchemaValidator()40 SchemaValidator::~SchemaValidator()
41 {
42 }
43 
44 
45 /*
46   Main entry method for validation
47   Inputs
48   1. XmlStream ,xpp.getName() muct return the name of the  type
49   which must be validated
50   2. typeId of the type against which this stream must be
51   validated against
52   3.An Input type container  (default  0)
53 */
54 TypeContainer *
validate(XmlPullParser * xpp,int typeId,TypeContainer * ipTc)55 SchemaValidator::validate(XmlPullParser * xpp,
56 			  int typeId,
57 			  TypeContainer * ipTc)
58 {
59   TypeContainer *t=0;
60 
61   try{
62     string elemName = xpp->getName();
63     const SchemaParser * s1Parser = sParser_;
64     int typeId1= typeId;
65 
66     if (!ipTc)
67       t = new TypeContainer(typeId, sParser_);
68     else
69       t = ipTc;
70 
71 
72 
73     if (t->getTypeId() != typeId)
74       error("Fatal error ,container's type is not same as the validated type",xpp);
75 
76     // a schema definition inside an instance
77     if (typeId == Schema::XSD_SCHEMA){
78 
79       SchemaParser * ssParser_ = new SchemaParser(xpp);
80       if (!ssParser_->parseSchemaTag()){
81 
82 	delete ssParser_;
83 	return 0;
84       }
85       delete ssParser_;
86       return t;
87     }
88 
89     //ignore ANY
90     if (typeId == Schema::XSD_ANY){
91 
92       xpp->skipSubTree();
93       return t;
94     }
95 
96     // check if this type belongs to the current schema, if not we need to switch contexts
97     if (!sParser_->isBasicType(typeId)){
98 
99       const XSDType * pType = sParser_->getType(typeId);
100 
101       if (sParser_->isImported(pType->getNamespace())) {
102 
103 	sParser_ = sParser_->getImportedSchemaParser(pType->getNamespace());
104 	typeId = const_cast<SchemaParser*>(sParser_)->getTypeId(pType->getQname());
105 
106 	t->sParser_ = sParser_;
107 	t->typeId_ = (Schema::Type)typeId;
108 
109       }
110     }
111 
112 
113     if (sParser_->getType(typeId) == 0
114 	|| sParser_->getType(typeId)->isSimple()) {
115 
116       //simple type validation
117       string val;
118       xpp->nextToken();
119       if (xpp->getEventType() == XmlPullParser::TEXT ||
120 	  xpp->getEventType() == XmlPullParser::ENTITY_REF){
121 
122 	val = xpp->getText();
123 
124 	xpp->nextToken();
125 	while (xpp->getEventType() == XmlPullParser::ENTITY_REF ||
126 	       xpp->getEventType() == XmlPullParser::TEXT){
127 
128 	  val += xpp->getText();
129 	  xpp->nextToken();
130 
131 	}
132 	validate(val, typeId, t,xpp);
133       }
134       else{
135 	//text was probably empty,nevertheless create  a type container
136 	validate(val, typeId, t, xpp);
137       }
138       if (xpp->getEventType() == XmlPullParser::END_TAG)
139 	{
140 	  if (xpp->getName() != elemName)
141 	    error("Syntax error "+elemName,xpp);
142 	}
143       else
144 	error("Expected a closing tag for " + elemName,xpp);
145     }
146     else {
147 
148       /*
149 	Perform Validation of Complex types
150 	Check for
151 	1.Is the tag name correct (this has to be right !!)
152 	2.Attributes ,if any should be valid
153 	3.Are there any mandatory (#required) attributes
154 	4. Validate its content model
155 	6.Return the type container which has the
156 	correctly filled in values
157 
158       */
159       const ComplexType *ct =
160 	static_cast<const ComplexType *>(sParser_->getType(typeId));
161 
162       const ComplexType * bt = 0;
163       TypeContainer * btCnt = 0;
164       if (ct->getBaseTypeId()!=Schema::XSD_ANYTYPE) {
165 
166 	bt = static_cast<const ComplexType*>
167 	  (sParser_->getType(ct->getBaseTypeId()));
168 	btCnt = t->getBaseTypeContainer(true);
169       }
170 
171       int attcnt = xpp->getAttributeCount();
172 
173       for (int i = 0; i < attcnt; i++) {
174 
175 	std::string attName = xpp->getAttributeName(i);
176 	std::string attVal = xpp->getAttributeValue("", attName);
177 	std::string attNsp = xpp->getAttributeNamespace(i);
178 	if (!attNsp.empty() && attNsp != sParser_->getNamespace())
179 	  continue;
180 
181 	const Attribute*at = 0;
182 	TypeContainer *atCnt = 0;
183 	at = ct->getAttribute(attName);
184 
185 	if (!at && bt){
186 	  at  = bt->getAttribute(attName);
187 	  if (at)
188 	    atCnt = btCnt->getAttributeContainer(attName, true);
189 	}
190 	else{
191 	  atCnt = t->getAttributeContainer(attName, true);
192 	}
193 
194 	if (!at)
195 	  error("Unknown attribute \"" + attName +  "\"",xpp);
196 
197 	validate(attVal, at->getType(), atCnt, xpp);
198       }
199 
200       //see if some required attributes are missing
201       checkAttributeOccurence(ct,xpp);
202       if (bt)
203 	checkAttributeOccurence(bt,xpp);
204 
205 
206       if (ct->getContentModel() == Schema::Simple)
207 	{
208 	  //complex types with a simple content model
209 
210 	  string val;
211 	  xpp->nextToken();
212 	  if (xpp->getEventType() == xpp->TEXT){
213 	    val = xpp->getText();
214 	    validate(val, ct->getContentType(), t, xpp);
215 	    xpp->nextTag();
216 	  }
217 	  else{
218 	    //text was probably empty,nevertheless create  a type container
219 	    validate(val, ct->getContentType(), t, xpp);
220 	  }
221 
222 	  if (xpp->getEventType() == XmlPullParser::END_TAG)
223 	    {
224 	      if (xpp->getName() != elemName)
225 		error("Syntax error",xpp);
226 	    }
227 	  else
228 	    error("Expected a closing tag for " + elemName,xpp);
229 	}
230       else if (ct->getContentModel() == Schema::Complex){
231 	//a complex type with complex content model
232 	ContentModel* cm=ct->getContents();
233 	ContentModel * bCm = 0;
234 	if (bt)
235 	  bCm = bt->getContents();
236 	if(cm)
237 	  validateContentModel(xpp,
238 			       cm,
239 			       t->getChildContainer(cm,true),
240 			       elemName,
241                                false,
242 			       btCnt);
243 	else if (bCm)
244 	  validateContentModel(xpp,
245 			       bCm,
246 			       btCnt->getChildContainer(bCm,true),
247                                elemName);
248 	else
249 	  xpp->nextTag();
250       }
251       else{
252 	// a complex type with mixed content model.no support yet
253       }
254     }
255     typeId = typeId1;
256     sParser_ = s1Parser;
257     return t;
258 
259   }catch (SchemaParserException spe){
260 
261     if (!ipTc && t) delete t;
262 
263     if(xpp){
264 
265       spe.line=xpp->getLineNumber();
266       spe.col=xpp->getColumnNumber();
267       throw spe;
268     }
269   }
270   return 0;
271 }
272 
273 TypeContainer*
validateContentModel(XmlPullParser * xpp,ContentModel * cm,TypeContainer * ipTc,const string & elemName,bool nested,TypeContainer * btCnt)274 SchemaValidator::validateContentModel(XmlPullParser * xpp,
275                                       ContentModel* cm,
276                                       TypeContainer * ipTc,
277                                       const string & elemName,
278 				      bool nested,
279 				      TypeContainer * btCnt)
280 {
281   ContentModel::ContentsIterator cit_b=cm->begin();
282   ContentModel::ContentsIterator cit_e=cm->end();
283   ContentModel::ContentsIterator ci=cit_e;
284 
285   ContentModel::ContentsIterator bci;//base content model iterator
286   ContentModel * bCm=0;
287 
288 
289   for (ci=cit_b;ci!=cit_e;ci++){
290     if(ci->second==ContentModel::Particle)
291       ci->first.e->nOccurrences=0;
292   }
293   ci=cit_b;
294 
295   if (btCnt) {
296     int t = btCnt->getTypeId();
297     const ComplexType* ct = static_cast<const ComplexType*>(btCnt->schemaParser()->getType(t));
298     bCm = ct->getContents();
299     if (bCm)
300       bci =bCm->begin();
301   }
302 
303   switch (cm->getCompositor()) {
304 
305   case Schema::All:
306     {
307       do
308 	{
309 	  if (!nested)
310 	    xpp->nextTag();
311 	  if (xpp->getEventType() == XmlPullParser::END_TAG)
312 	    {
313 	      if (xpp->getName() == elemName)
314 		break;
315 	      while (xpp->getEventType() != XmlPullParser::START_TAG)
316 		xpp->nextTag();
317 	    }
318 	  //All cannot have another content model inside like group/choice etc
319 
320 	  if(!findElement(cit_b,cit_e,xpp->getName(),ci))
321 	    error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
322 	  ci->first.e->nOccurrences++;
323 
324 	  validate(xpp, ci->first.e->getType(),
325 		   ipTc->getChildContainer(ci->first.e->getName(), true));
326 	  //ipTc->getChildContainer(xpp->getName(), true));
327 	}
328       while (true);
329 
330       /*
331 	check for occurrence constraints
332       */
333       for (ci=cit_b;ci!=cit_e;ci++){
334 	if(ci->second==ContentModel::Particle &&
335            (ci->first.e->nOccurrences<ci->first.e->getMin()||
336             ci->first.e->nOccurrences>ci->first.e->getMax()))
337 	  error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
338       }
339 
340       break;
341     }
342   case Schema::Sequence:
343     {
344       do
345 	{
346 	  if (!nested)
347 	    xpp->nextTag();
348 
349 	  if(xpp->getEventType() == XmlPullParser::END_TAG){
350 
351 	    if (xpp->getName() == elemName)
352 	      break;
353 	    if(ci==cit_e)
354 	      break;
355 
356 	    //position the xml parser to the next element
357 	    while ((xpp->getEventType() != XmlPullParser::START_TAG)&&
358 		   ((xpp->getEventType() != XmlPullParser::END_TAG)||
359 		    (xpp->getName() != elemName)))
360 	      xpp->nextTag();
361 	  }
362 	  //loop through all the contents inside
363 	  //the child elements in the content model must be in the same
364 	  //order as defined in the <sequence> tag of the schema
365 
366 	  if(ci->second==ContentModel::Container){
367 
368 	    if ((xpp->getEventType() == xpp->END_TAG)&&
369 		(xpp->getName() == elemName))
370 	      break;
371 	    //nested content model
372 	    validateContentModel(xpp,ci->first.c,
373 				 ipTc->getChildContainer(ci->first.c,true),
374 				 elemName,true,btCnt);
375 	    ci++;
376 	  }
377 	  else{
378 
379 
380 	    if(cm->anyContents() ||
381 	       findElement(ci,cit_e,xpp->getName(), ci)){
382 
383 	      ci->first.e->nOccurrences++;
384 	      validate(xpp,ci->first.e->getType(),
385 		       ipTc->getChildContainer(ci->first.e->getName(), true));
386 
387 	    }else if (bCm && (bCm->anyContents() ||
388 		      findElement(bCm->begin(),bCm->end(),xpp->getName(), bci))){
389 
390 	      TypeContainer * t = btCnt->getChildContainer(bCm,true);
391 	      validate(xpp,bci->first.e->getType(),t->getChildContainer(bci->first.e->getName(),true));
392 
393 	    } else {
394 
395 	      error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
396 	    }
397 
398 	  }
399 	}
400       while (true);
401 
402       /*
403 	check for occurrence constraints
404       */
405       for (ci=cit_b;ci!=cit_e;ci++){
406 	if(ci->second==ContentModel::Particle &&
407            (ci->first.e->nOccurrences<ci->first.e->getMin()||
408             ci->first.e->nOccurrences>ci->first.e->getMax()))
409 	  error(ci->first.e->getName()+" did not meet occurrence constraints",xpp);
410       }
411       break;
412     }
413   case Schema::Choice:
414     {
415 
416       if (!nested)
417 	xpp->nextTag();
418 
419 
420       if(findElement(ci,cit_e,xpp->getName(), ci)) {
421 
422 	std::string choiceElem = xpp->getName();
423 	do {
424 	//see if one of the choices is a particle and it occurs in the instance
425 	ci->first.e->nOccurrences++;
426 	validate(xpp, ci->first.e->getType(),
427 		 ipTc->getChildContainer(ci->first.e->getName(), true));
428 	xpp->nextTag();
429 	}while(xpp->getName() == choiceElem);
430 	xpp->prevTag();
431 	break;
432       }
433       else {
434 	//its a choice which has a content model
435 	ci++;
436       }
437       if (ci->second == ContentModel::Container){
438 
439 	try {
440 	  validateContentModel(xpp,ci->first.c,
441 			       ipTc->getChildContainer(ci->first.c,true),
442 			       elemName,true,btCnt);
443 	}
444 	catch (SchemaParserException spe){
445 
446 	  ci++;
447 	  //try the other content model
448 	  validateContentModel(xpp,ci->first.c,
449 			       ipTc->getChildContainer(ci->first.c,true),
450 			       elemName,true,btCnt);
451 	}
452       }
453       else{
454 
455 	error("Could not find element " +xpp->getName()+" in "+elemName,xpp);
456       }
457 
458       /*
459        * Only one of the choices is allowed
460        */
461 
462       /*
463        * check for occurrence constraints
464        */
465       if(ci->second==ContentModel::Particle &&
466          (ci->first.e->nOccurrences<ci->first.e->getMin()||
467           ci->first.e->nOccurrences>ci->first.e->getMax()))
468 	error(ci->first.e->getName()+"did not meet occurrence constraints",xpp);
469 
470       break;
471     }
472   }
473   /*
474    * reset occurence ocunters
475    */
476   for (ci=cit_b;ci!=cit_e;ci++){
477 
478     if(ci->second==ContentModel::Particle)
479       ci->first.e->nOccurrences=0;
480   }
481   return ipTc;
482 }
483 
484 
485 
486 /*
487  *  This method validates all supported simple types
488  *  Both native atomic types and schema defined
489  */
490 
491 TypeContainer *
validate(void * value,int typeId,TypeContainer * ipTc,XmlPullParser * xpp)492 SchemaValidator::validate(void* value ,
493                           int typeId,
494                           TypeContainer * ipTc,
495                           XmlPullParser * xpp)
496 {
497 
498   int basetype = sParser_->getBasicContentType(typeId);
499 
500   const XSDType * pType = sParser_->getType(typeId);
501   if (pType && !pType->isSimple()){
502 
503     return 0;
504   }
505   const SimpleType  *st = static_cast<const SimpleType*>(pType);
506 
507   //check for the validity of the value
508   //if available also check against restrictions in the schema
509 
510   if (!ipTc)
511     ipTc = new TypeContainer(typeId, sParser_);
512 
513   if (st && (st->isList() || st->isUnion())){
514 
515     std::string val = *((std::string*)value);
516     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
517     return ipTc;
518   }
519   switch (basetype)
520     {
521     case Schema::XSD_INTEGER:
522     case Schema::XSD_INT:
523       {
524 	int x= *((int*)value);
525 	if (!st) {
526 	  ipTc->setValue(x);
527 	}
528 	else{
529 
530 	  ipTc->setValue(x,st->isValidInt(x));
531 	}
532 	break;
533       }
534     case Schema::XSD_BYTE:
535       {
536 	char c= *((char*)value);
537 	ipTc->setValue(c);
538       }
539       break;
540     case Schema::XSD_FLOAT:
541       {
542 	float f = *((float*)value);
543 	if (!st) {
544 
545 	  ipTc->setValue(f);
546 
547 	}else{
548 
549 	  ipTc->setValue(f,st->isValidFloat(f));
550 	}
551 	break;
552       }
553     case Schema::XSD_DOUBLE:
554     case Schema::XSD_DECIMAL:
555       {
556 	double db = *((double*)value);
557 	ipTc->setValue(db);
558       }
559       break;
560     case Schema::XSD_LONG:
561       {
562 	long l = *((long*)value);
563 	ipTc->setValue(l);
564       }
565       break;
566     case Schema::XSD_POSINT:
567     case Schema::XSD_ULONG:
568       {
569 	unsigned long  ul= *((unsigned  long*)value);
570 	ipTc->setValue(ul);
571       }
572       break;
573     case Schema::XSD_BOOLEAN:
574       {
575 	bool b  = *((bool*)value);
576 	ipTc->setValue(b);
577 	break;
578       }
579     case Schema::XSD_QNAME:
580       {
581 	Qname q  = *((Qname* )value);
582 	ipTc->setValue(q);
583       }
584       break;
585     case Schema::XSD_STRING:
586     default:
587       {
588 	std::string val = *((std::string* )value);
589 	if (!st) {
590 
591 	  ipTc->setValue(val);
592 	}
593 	else{
594 
595 	  ipTc->setValue(val,st->isValidString(val));
596 	}
597       }
598       break;
599     }
600 
601   return  ipTc;
602 }
603 
604 /*
605  *  This method validates all supported simple types
606  *  Both native atomic types and schema defined
607  */
608 
609 TypeContainer *
validate(const string & val,int typeId,TypeContainer * ipTc,XmlPullParser * xpp)610 SchemaValidator::validate(const string & val,
611 			  int typeId,
612                           TypeContainer *ipTc,
613                           XmlPullParser * xpp)
614 {
615 
616   int basetype = sParser_->getBasicContentType(typeId);
617   if (basetype == Schema::XSD_INVALID) {
618 
619     return 0;
620   }
621 
622   const XSDType * pType = sParser_->getType(typeId);
623   if (pType &&
624       !pType->isSimple() &&
625       pType->getContentModel() != Schema::Simple){
626 
627     return 0;
628   }
629 
630   if (pType && !pType->isSimple() &&
631       pType->getContentModel() ==Schema::Simple) {
632     //this is a complex type but has a simple content model
633 
634     const ComplexType * ct = static_cast<const ComplexType*>(pType);
635     int contentType = ct->getContentType();
636     return validate(val,contentType,ipTc,xpp);
637 
638   }
639   const SimpleType  *st = static_cast<const SimpleType*>(pType);
640 
641   //check for the validity of the value
642   //if available also check against restrictions in the schema
643 
644   if (!ipTc)
645     ipTc = new TypeContainer(typeId, sParser_);
646   ipTc->setValAsString(val);
647 
648   while(ipTc->isValueValid()){
649 
650     extractSimpleType(val, basetype, ipTc, st, xpp);
651 
652 
653     if(!st || (st && (st->isList() || st->isUnion()))){
654 
655       break;
656       //if we validated an atomic type we are done
657       //if we just validated a list or union,there is no need
658       //to continue checking base types
659     }
660 
661     if (!sParser_->isBasicType(st->getBaseTypeId())){
662 
663       st=static_cast<const SimpleType*>(sParser_->getType(st->getBaseTypeId()));
664     }
665     else{
666       st = 0;
667     }
668   }
669   return ipTc;
670 }
671 
672 
673 void
extractSimpleType(const std::string & val,int basetype,TypeContainer * ipTc,const SimpleType * st,XmlPullParser * xpp)674 SchemaValidator::extractSimpleType(const std::string & val,
675 				   int basetype,
676 				   TypeContainer * ipTc,
677                                    const SimpleType * st,
678                                    XmlPullParser * xpp)
679 {
680 
681   if (st && (st->isList() || st->isUnion())){
682 
683     ipTc->setValue(val,validateListOrUnion(st,val,xpp));
684     return;
685   }
686 
687   istringstream istr(val);
688   int x;
689   double db;
690   long l;
691   char c;
692   unsigned long  ul;
693   float f;
694 
695   switch (basetype)
696     {
697     case Schema::XSD_INTEGER:
698     case Schema::XSD_INT:
699       {
700 	istr >> x;
701 	if (!st) {
702 	  ipTc->setValue(x,!istr.fail());
703 	}
704 	else{
705 
706 	  ipTc->setValue(x,!istr.fail() && st->isValidInt(x));
707 	}
708 	break;
709       }
710     case Schema::XSD_BYTE:
711       istr >> c;
712       ipTc->setValue(c,!istr.fail());
713       break;
714     case Schema::XSD_FLOAT:
715       {
716 	istr >> f;
717 	if (!st) {
718 	  ipTc->setValue(f,!istr.fail());
719 	}else{
720 	  ipTc->setValue(f,!istr.fail() && st->isValidFloat(f));
721 	}
722 	break;
723       }
724     case Schema::XSD_DOUBLE:
725     case Schema::XSD_DECIMAL:
726       istr >> db;
727       ipTc->setValue(db,!istr.fail());
728       break;
729     case Schema::XSD_LONG:
730       istr >> l;
731       ipTc->setValue(l,!istr.fail());
732       break;
733     case Schema::XSD_POSINT:
734     case Schema::XSD_ULONG:
735       istr >> ul;
736       ipTc->setValue(ul,!istr.fail());
737       break;
738     case Schema::XSD_BOOLEAN:
739       {
740 
741 	if(val=="true" ||
742 	   val=="yes" ||
743 	   val=="1")
744 
745 	  ipTc->setValue(true);
746 	else
747 	  ipTc->setValue(false);
748 	break;
749       }
750     case Schema::XSD_QNAME:
751       {
752 	Qname q(val);
753 	if (xpp)
754 	  q.setNamespace(xpp->getNamespace(q.getPrefix()));
755 	ipTc->setValue(q);
756 	break;
757       }
758     case Schema::XSD_STRING:
759     default:
760       {
761 	if (!st) {
762 
763 	  ipTc->setValue(val);
764 	}
765 	else{
766           if (basetype == Schema::XSD_STRING)
767 	    ipTc->setValue(val,st->isValidString(val));
768 	  else
769 	    ipTc->setValue(val);//other types such as date for which no validation is done
770 	}
771       }
772       break;
773     }
774 }
775 
776 /*
777  * This function validates a string as a list or union
778  * for the simple type
779  */
780 
781 bool
validateListOrUnion(const SimpleType * st,const std::string & val,XmlPullParser * xpp)782 SchemaValidator::validateListOrUnion(const SimpleType* st,
783                                      const std::string &val,
784                                      XmlPullParser * xpp)
785 {
786   if (st->isList()){
787 
788     size_t s = 0;
789 
790     while(s < val.length()){
791       while(val[s]==' ')s++;
792       std::string t = val.substr(s,val.find(' ',s)-s);
793       TypeContainer * tc = validate(t,st->getBaseTypeId(),0,xpp);
794       if (!(tc && tc->isValueValid()))
795 	return false;
796       s+=t.length()+1;
797     }
798     return true ;
799 
800   }else if (st->isUnion()){
801 
802     std::list<int>::const_iterator it= st->unionTypes()->begin();
803     while (it!=st->unionTypes()->end()){
804 
805       TypeContainer * tc = validate(val,*it,0,xpp);
806 
807       if (tc && tc->isValueValid())
808 	return true;
809       it++;
810     }
811     return false;
812   }
813   else{
814     return false;
815   }
816 }
817 /*
818  * This function searches for a child element in a complex type
819  * The iterator pElem is set to point to the found element
820  * rewind controls whether a search is to be done by resetting pElem
821  * to the begining of the list
822  * Returns true if element is found else false
823  */
824 
825 bool
findElement(ContentModel::ContentsIterator start,ContentModel::ContentsIterator end,std::string name,ContentModel::ContentsIterator & found)826 SchemaValidator::findElement(ContentModel::ContentsIterator start,
827 			     ContentModel::ContentsIterator end,
828 			     std::string name,
829 			     ContentModel::ContentsIterator & found)
830 {
831   for (ContentModel::ContentsIterator ci=start;
832        ci!=end;
833        ci++){
834 
835     if(ci->second==ContentModel::Particle){
836 #ifdef LOGGING
837       std::cout<<"Looking for "<< name<<" found "<<ci->first.e->getName()<<std::endl;
838 #endif
839       if(ci->first.e->getName()==name ||
840 	 ci->first.e->getName() == "*")//* is  a hack for soap arrays
841         {
842           found=ci;
843           return true;
844         }
845     }
846   }
847   return false;
848 }
849 
error(const std::string & mesg,XmlPullParser * xpp)850 void SchemaValidator::error(const std::string& mesg,XmlPullParser* xpp)
851 {
852 
853   SchemaParserException spe(mesg + "\nError validating schema instance\n");
854   if(xpp){
855 
856     spe.line=xpp->getLineNumber();
857     spe.col=xpp->getColumnNumber();
858   }
859   throw spe;
860 }
861 
862 
863 bool
checkAttributeOccurence(const ComplexType * ct,XmlPullParser * xpp)864 SchemaValidator::checkAttributeOccurence(const ComplexType* ct ,
865 					 XmlPullParser* xpp)
866 {
867 
868   if (ct->getNumAttributes() > 0)
869     {
870       for (int i = 0; i < ct->getNumAttributes(); i++)
871 	{
872 	  const Attribute*at = ct->getAttribute(i);
873 
874 	  /*
875 	    Check for the correctness of each attribute
876 	  */
877 	  string attVal = xpp->getAttributeValue("", at->getName());
878 	  if (attVal.empty())
879 	    {
880 	      if (at->isRequired())
881 		error("Required attribute \"" + at->getName() +
882 		      "\" missing or empty",xpp);
883 
884 	      else
885 		continue;
886 	    }
887 	}
888     }
889   return true;
890 }
891 
892 
893 
894 bool
instance(const std::string & tag,Schema::Type type_id)895 SchemaValidator::instance(const std::string& tag,
896 			  Schema::Type type_id)
897 
898 {
899 
900   //generate an instance of the given type
901   std::string nsp = sParser_->getNamespace();
902   xmlStream_ = new XmlSerializer(ostr_); //xml serializer
903 
904   if (!nsp.empty())
905     xmlStream_->setPrefix("s",nsp);
906 
907   xmlStream_->setPrefix("xsi",Schema::SchemaInstaceUri);
908   xmlStream_->startDocument("UTF-8",false);
909 
910   return instance1(tag,type_id);
911 }
912 
913 bool
instance1(const std::string & tag,Schema::Type type_id)914 SchemaValidator::instance1(const std::string &tag,
915 			   Schema::Type type_id)
916 {
917 
918   std::string nsp = sParser_->getNamespace();
919   static bool first = false;
920   xmlStream_->startTag(nsp,tag);
921   if (!first){
922     xmlStream_->attribute("",
923 			  "xmlns",
924 			  nsp);
925     first = true;
926   }
927 
928 
929   //  xmlStream_->attribute(Schema::SchemaInstaceUri,
930   //		"type",
931   //		"s:"+sParser_->getTypeName(type_id));
932   const XSDType * pType = sParser_->getType(type_id);
933 
934   if ( pType== 0 ||
935        pType->isSimple()){
936 
937     xmlStream_->text(""); //simple content types
938 
939   }
940   else {
941 
942     const ComplexType * ct =
943       static_cast<const ComplexType*>(pType);
944 
945     //print attributes if any
946     if (ct->getNumAttributes() > 0) {
947 
948       for (int i = 0; i < ct->getNumAttributes(); i++) {
949 
950 	const Attribute*at = ct->getAttribute(i);
951 	xmlStream_->attribute(sParser_->getNamespace(),at->getName(),"");
952       }
953     }
954 
955 
956     if (ct->getContentModel() == Schema::Simple) {
957 
958       xmlStream_->text("");
959     }
960     else{
961 
962       ContentModel* cm=ct->getContents();
963       instanceCM(cm);
964 
965     }
966   }
967   xmlStream_->endTag(nsp,tag);
968   return  true;
969 }
970 
971 
972 
973 
974 void
instanceCM(ContentModel * cm)975 SchemaValidator::instanceCM(ContentModel *cm)
976 
977 {
978 
979   ContentModel::ContentsIterator cit_b=cm->begin();
980   ContentModel::ContentsIterator cit_e=cm->end();
981   ContentModel::ContentsIterator ci=cit_b;
982 
983   switch (cm->getCompositor())
984     {
985     case Schema::All:
986     case Schema::Sequence:
987     case Schema::Choice:
988       {
989 	// a simple logic to start with
990 	// not taking care of all,choice ,sequence as of now
991 
992 	for (ci=cit_b;ci!=cit_e;ci++){
993 
994 	  if(ci->second==ContentModel::Particle &&
995              ci->first.e->getMax() > 0){
996 
997 	    const SchemaParser* s1Parser = sParser_;
998 	    Schema::Type t=(Schema::Type)ci->first.e->getType();
999 
1000 	    if (!ci->first.e->getTypeNamespace().empty() &&
1001 		sParser_->isImported(ci->first.e->getTypeNamespace()) &&
1002                 sParser_->getNamespace() != ci->first.e->getTypeNamespace()) {
1003 
1004 	      //here the type of the element is defined in another imported schemaparser
1005 	      //so try to get the pointer.
1006 	      t = (Schema::Type)sParser_->getType(t)->getTypeId();
1007 	      sParser_ = sParser_->getImportedSchemaParser(ci->first.e->getTypeNamespace());
1008 	    }
1009 
1010 	    instance1(ci->first.e->getName(),t);
1011 	    sParser_ = s1Parser;
1012 	  }
1013 	  else if (ci->second==ContentModel::Container) {
1014 
1015 	    //nested xsd:sequence inside choice..nested content models
1016 	    instanceCM(ci->first.c);
1017 
1018 	  }
1019 	  else if (ci->second==ContentModel::ParticleGroup){
1020 
1021 	    //xsd:group inside
1022 	    instanceCM(ci->first.g->getContents());
1023 
1024 	  }
1025 	}
1026 	break;
1027       }
1028     }
1029 }
1030 
1031 }
1032 //TODO validation of <any>
1033 //TODO validation of base64binary,hexBinary
1034 //TODO validation of types derived by extension/restriction of complex types
1035