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