blob: 19260637852ae2397ee8d16d23d4487ad90c4d40 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemas.c : implementation of the XML Schema handling and
3 * schema validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20
21#include <libxml/xmlschemas.h>
22#include <libxml/schemasInternals.h>
23#include <libxml/xmlschemastypes.h>
24#include <libxml/xmlautomata.h>
25#include <libxml/xmlregexp.h>
26
Daniel Veillard8651f532002-04-17 09:06:27 +000027#define DEBUG 1 /* very verbose output */
28#define DEBUG_CONTENT 1
29#define DEBUG_TYPE 1
Daniel Veillard4255d502002-04-16 15:50:10 +000030/* #define DEBUG_AUTOMATA 1 */
31
32#define UNBOUNDED (1 << 30)
33#define TODO \
34 xmlGenericError(xmlGenericErrorContext, \
35 "Unimplemented block at %s:%d\n", \
36 __FILE__, __LINE__);
37
38/*
39 * The XML Schemas namespaces
40 */
41static const xmlChar *xmlSchemaNs = (const xmlChar *)
42 "http://www.w3.org/2001/XMLSchema";
43
44static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
45 "http://www.w3.org/2001/XMLSchema-instance";
46
47#define IS_SCHEMA(node, type) \
48 ((node != NULL) && (node->ns != NULL) && \
49 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
50 (xmlStrEqual(node->ns->href, xmlSchemaNs)))
51
52#define XML_SCHEMAS_PARSE_ERROR 1
53
54struct _xmlSchemaParserCtxt {
55 void *userData; /* user specific data block */
56 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
57 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
58
59 xmlSchemaPtr schema; /* The schema in use */
60 xmlChar *container; /* the current element, group, ... */
61 int counter;
62
63 xmlChar *URL;
64 xmlDocPtr doc;
65
66 /*
67 * Used to build complex element content models
68 */
69 xmlAutomataPtr am;
70 xmlAutomataStatePtr start;
71 xmlAutomataStatePtr end;
72 xmlAutomataStatePtr state;
73};
74
75
76#define XML_SCHEMAS_ATTR_UNKNOWN 1
77#define XML_SCHEMAS_ATTR_CHECKED 2
78
79typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
80typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
81struct _xmlSchemaAttrState {
82 xmlAttrPtr attr;
83 int state;
84};
85
86/**
87 * xmlSchemaValidCtxt:
88 *
89 * A Schemas validation context
90 */
91
92struct _xmlSchemaValidCtxt {
93 void *userData; /* user specific data block */
94 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
95 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
96
97 xmlSchemaPtr schema; /* The schema in use */
98 xmlDocPtr doc;
99 xmlParserInputBufferPtr input;
100 xmlCharEncoding enc;
101 xmlSAXHandlerPtr sax;
102 void *user_data;
103
104 xmlDocPtr myDoc;
105 int err;
106
107 xmlNodePtr node;
108 xmlSchemaTypePtr type;
109
110 xmlRegExecCtxtPtr regexp;
111 xmlSchemaValPtr value;
112
113 int attrNr;
114 int attrBase;
115 int attrMax;
116 xmlSchemaAttrStatePtr attr;
117};
118
119
120/************************************************************************
121 * *
122 * Some predeclarations *
123 * *
124 ************************************************************************/
125static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
126 xmlSchemaTypePtr type,
127 xmlChar *value);
128
129/************************************************************************
130 * *
131 * Allocation functions *
132 * *
133 ************************************************************************/
134
135/**
136 * xmlSchemaNewSchema:
137 * @ctxt: a schema validation context (optional)
138 *
139 * Allocate a new Schema structure.
140 *
141 * Returns the newly allocated structure or NULL in case or error
142 */
143static xmlSchemaPtr
144xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
145{
146 xmlSchemaPtr ret;
147
148 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
149 if (ret == NULL) {
150 if ((ctxt != NULL) && (ctxt->error != NULL))
151 ctxt->error(ctxt->userData, "Out of memory\n");
152 return (NULL);
153 }
154 memset(ret, 0, sizeof(xmlSchema));
155
156 return (ret);
157}
158
159/**
160 * xmlSchemaNewFacet:
161 * @ctxt: a schema validation context (optional)
162 *
163 * Allocate a new Facet structure.
164 *
165 * Returns the newly allocated structure or NULL in case or error
166 */
167static xmlSchemaFacetPtr
168xmlSchemaNewFacet(xmlSchemaParserCtxtPtr ctxt)
169{
170 xmlSchemaFacetPtr ret;
171
172 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
173 if (ret == NULL) {
174 if ((ctxt != NULL) && (ctxt->error != NULL))
175 ctxt->error(ctxt->userData, "Out of memory\n");
176 return (NULL);
177 }
178 memset(ret, 0, sizeof(xmlSchemaFacet));
179
180 return (ret);
181}
182
183/**
184 * xmlSchemaNewAnnot:
185 * @ctxt: a schema validation context (optional)
186 * @node: a node
187 *
188 * Allocate a new annotation structure.
189 *
190 * Returns the newly allocated structure or NULL in case or error
191 */
192static xmlSchemaAnnotPtr
193xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
194{
195 xmlSchemaAnnotPtr ret;
196
197 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
198 if (ret == NULL) {
199 if ((ctxt != NULL) && (ctxt->error != NULL))
200 ctxt->error(ctxt->userData, "Out of memory\n");
201 return (NULL);
202 }
203 memset(ret, 0, sizeof(xmlSchemaAnnot));
204 ret->content = node;
205 return (ret);
206}
207
208/**
209 * xmlSchemaFreeNotation:
210 * @schema: a schema notation structure
211 *
212 * Deallocate a Schema Notation structure.
213 */
214static void
215xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
216{
217 if (nota == NULL)
218 return;
219 if (nota->name != NULL)
220 xmlFree((xmlChar *) nota->name);
221 xmlFree(nota);
222}
223
224/**
225 * xmlSchemaFreeAttribute:
226 * @schema: a schema attribute structure
227 *
228 * Deallocate a Schema Attribute structure.
229 */
230static void
231xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
232{
233 if (attr == NULL)
234 return;
235 if (attr->name != NULL)
236 xmlFree((xmlChar *) attr->name);
237 if (attr->ref != NULL)
238 xmlFree((xmlChar *) attr->ref);
239 if (attr->refNs != NULL)
240 xmlFree((xmlChar *) attr->refNs);
241 if (attr->typeName != NULL)
242 xmlFree((xmlChar *) attr->typeName);
243 if (attr->typeNs != NULL)
244 xmlFree((xmlChar *) attr->typeNs);
245 xmlFree(attr);
246}
247
248/**
249 * xmlSchemaFreeAttributeGroup:
250 * @schema: a schema attribute group structure
251 *
252 * Deallocate a Schema Attribute Group structure.
253 */
254static void
255xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
256{
257 if (attr == NULL)
258 return;
259 if (attr->name != NULL)
260 xmlFree((xmlChar *) attr->name);
261 xmlFree(attr);
262}
263
264/**
265 * xmlSchemaFreeElement:
266 * @schema: a schema element structure
267 *
268 * Deallocate a Schema Element structure.
269 */
270static void
271xmlSchemaFreeElement(xmlSchemaElementPtr elem)
272{
273 if (elem == NULL)
274 return;
275 if (elem->name != NULL)
276 xmlFree((xmlChar *) elem->name);
277 if (elem->namedType != NULL)
278 xmlFree((xmlChar *) elem->namedType);
279 if (elem->namedTypeNs != NULL)
280 xmlFree((xmlChar *) elem->namedTypeNs);
281 if (elem->ref != NULL)
282 xmlFree((xmlChar *) elem->ref);
283 if (elem->refNs != NULL)
284 xmlFree((xmlChar *) elem->refNs);
285 if (elem->contModel != NULL)
286 xmlRegFreeRegexp(elem->contModel);
287 xmlFree(elem);
288}
289
290/**
291 * xmlSchemaFreeFacet:
292 * @facet: a schema facet structure
293 *
294 * Deallocate a Schema Facet structure.
295 */
296static void
297xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
298{
299 if (facet == NULL)
300 return;
301 if (facet->value != NULL)
302 xmlFree((xmlChar *) facet->value);
303 if (facet->id != NULL)
304 xmlFree((xmlChar *) facet->id);
305 if (facet->val != NULL)
306 xmlSchemaFreeValue(facet->val);
307 if (facet->regexp != NULL)
308 xmlRegFreeRegexp(facet->regexp);
309 xmlFree(facet);
310}
311
312/**
313 * xmlSchemaFreeType:
314 * @type: a schema type structure
315 *
316 * Deallocate a Schema Type structure.
317 */
318void
319xmlSchemaFreeType(xmlSchemaTypePtr type)
320{
321 if (type == NULL)
322 return;
323 if (type->name != NULL)
324 xmlFree((xmlChar *) type->name);
325 if (type->base != NULL)
326 xmlFree((xmlChar *) type->base);
327 if (type->baseNs != NULL)
328 xmlFree((xmlChar *) type->baseNs);
329 if (type->annot != NULL)
330 xmlFree((xmlChar *) type->annot);
331 if (type->facets != NULL) {
332 xmlSchemaFacetPtr facet, next;
333
334 facet = type->facets;
335 while (facet != NULL) {
336 next = facet->next;
337 xmlSchemaFreeFacet(facet);
338 facet = next;
339 }
340 }
341 xmlFree(type);
342}
343
344/**
345 * xmlSchemaFreeAnnot:
346 * @annot: a schema type structure
347 *
348 * Deallocate a annotation structure
349 */
350static void
351xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
352{
353 if (annot == NULL)
354 return;
355 xmlFree(annot);
356}
357
358/**
359 * xmlSchemaFree:
360 * @schema: a schema structure
361 *
362 * Deallocate a Schema structure.
363 */
364void
365xmlSchemaFree(xmlSchemaPtr schema)
366{
367 if (schema == NULL)
368 return;
369
370 if (schema->name != NULL)
371 xmlFree((xmlChar *) schema->name);
372 if (schema->notaDecl != NULL)
373 xmlHashFree(schema->notaDecl,
374 (xmlHashDeallocator) xmlSchemaFreeNotation);
375 if (schema->attrDecl != NULL)
376 xmlHashFree(schema->attrDecl,
377 (xmlHashDeallocator) xmlSchemaFreeAttribute);
378 if (schema->attrgrpDecl != NULL)
379 xmlHashFree(schema->attrgrpDecl,
380 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup);
381 if (schema->elemDecl != NULL)
382 xmlHashFree(schema->elemDecl,
383 (xmlHashDeallocator) xmlSchemaFreeElement);
384 if (schema->typeDecl != NULL)
385 xmlHashFree(schema->typeDecl,
386 (xmlHashDeallocator) xmlSchemaFreeType);
387 if (schema->annot != NULL)
388 xmlSchemaFreeAnnot(schema->annot);
389 if (schema->doc != NULL)
390 xmlFreeDoc(schema->doc);
391
392 xmlFree(schema);
393}
394
395/************************************************************************
396 * *
397 * Error functions *
398 * *
399 ************************************************************************/
400
401/**
402 * xmlSchemaErrorContext:
403 * @ctxt: the parsing context
404 * @schema: the schema being built
405 * @node: the node being processed
406 * @child: the child being processed
407 *
408 * Dump a SchemaType structure
409 */
410static void
411xmlSchemaErrorContext(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
412 xmlNodePtr node, xmlNodePtr child)
413{
414 int line = 0;
415 const xmlChar *file = NULL;
416 const xmlChar *name = NULL;
417 const char *type = "error";
418
419 if ((ctxt == NULL) || (ctxt->error == NULL))
420 return;
421
422 if (child != NULL)
423 node = child;
424
425 if (node != NULL) {
426 if ((node->type == XML_DOCUMENT_NODE) ||
427 (node->type == XML_HTML_DOCUMENT_NODE)) {
428 xmlDocPtr doc = (xmlDocPtr) node;
429
430 file = doc->URL;
431 } else {
432 /*
433 * Try to find contextual informations to report
434 */
435 if (node->type == XML_ELEMENT_NODE) {
436 line = (int) node->content;
437 } else if ((node->prev != NULL) &&
438 (node->prev->type == XML_ELEMENT_NODE)) {
439 line = (int) node->prev->content;
440 } else if ((node->parent != NULL) &&
441 (node->parent->type == XML_ELEMENT_NODE)) {
442 line = (int) node->parent->content;
443 }
444 if ((node->doc != NULL) && (node->doc->URL != NULL))
445 file = node->doc->URL;
446 if (node->name != NULL)
447 name = node->name;
448 }
449 }
450
451 if (ctxt != NULL)
452 type = "compilation error";
453 else if (schema != NULL)
454 type = "runtime error";
455
456 if ((file != NULL) && (line != 0) && (name != NULL))
457 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
458 type, file, line, name);
459 else if ((file != NULL) && (name != NULL))
460 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
461 type, file, name);
462 else if ((file != NULL) && (line != 0))
463 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
464 else if (file != NULL)
465 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
466 else if (name != NULL)
467 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
468 else
469 ctxt->error(ctxt->userData, "%s\n", type);
470}
471
472/************************************************************************
473 * *
474 * Debug functions *
475 * *
476 ************************************************************************/
477
478/**
479 * xmlSchemaElementDump:
480 * @elem: an element
481 * @output: the file output
482 *
483 * Dump the element
484 */
485static void
486xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
487 ATTRIBUTE_UNUSED const xmlChar *name,
488 ATTRIBUTE_UNUSED const xmlChar *context,
489 ATTRIBUTE_UNUSED const xmlChar *namespace)
490{
491 if (elem == NULL)
492 return;
493
494 fprintf(output, "Element ");
495 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
496 fprintf(output, "toplevel ");
497 fprintf(output, ": %s ", elem->name);
498 if (namespace != NULL)
499 fprintf(output, "namespace '%s' ", namespace);
500
501 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
502 fprintf(output, "nillable ");
503 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
504 fprintf(output, "global ");
505 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
506 fprintf(output, "default ");
507 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
508 fprintf(output, "fixed ");
509 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
510 fprintf(output, "abstract ");
511 if (elem->flags & XML_SCHEMAS_ELEM_REF)
512 fprintf(output, "ref '%s' ", elem->ref);
513 if (elem->id != NULL)
514 fprintf(output, "id '%s' ", elem->id);
515 fprintf(output, "\n");
516 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
517 fprintf(output, " ");
518 if (elem->minOccurs != 1)
519 fprintf(output, "min: %d ", elem->minOccurs);
520 if (elem->maxOccurs >= UNBOUNDED)
521 fprintf(output, "max: unbounded\n");
522 else if (elem->maxOccurs != 1)
523 fprintf(output, "max: %d\n", elem->maxOccurs);
524 else
525 fprintf(output, "\n");
526 }
527 if (elem->namedType != NULL) {
528 fprintf(output, " type: %s", elem->namedType);
529 if (elem->namedTypeNs != NULL)
530 fprintf(output, " ns %s\n", elem->namedTypeNs);
531 else
532 fprintf(output, "\n");
533 }
534 if (elem->substGroup != NULL) {
535 fprintf(output, " substitutionGroup: %s", elem->substGroup);
536 if (elem->substGroupNs != NULL)
537 fprintf(output, " ns %s\n", elem->substGroupNs);
538 else
539 fprintf(output, "\n");
540 }
541 if (elem->value != NULL)
542 fprintf(output, " default: %s", elem->value);
543}
544
545/**
546 * xmlSchemaAnnotDump:
547 * @output: the file output
548 * @annot: a annotation
549 *
550 * Dump the annotation
551 */
552static void
553xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
554{
555 xmlChar *content;
556
557 if (annot == NULL)
558 return;
559
560 content = xmlNodeGetContent(annot->content);
561 if (content != NULL) {
562 fprintf(output, " Annot: %s\n", content);
563 xmlFree(content);
564 } else
565 fprintf(output, " Annot: empty\n");
566}
567
568/**
569 * xmlSchemaTypeDump:
570 * @output: the file output
571 * @type: a type structure
572 *
573 * Dump a SchemaType structure
574 */
575static void
576xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
577{
578 if (type == NULL) {
579 fprintf(output, "Type: NULL\n");
580 return;
581 }
582 fprintf(output, "Type: ");
583 if (type->name != NULL)
584 fprintf(output, "%s, ", type->name);
585 else
586 fprintf(output, "no name");
587 switch (type->type) {
588 case XML_SCHEMA_TYPE_BASIC:
589 fprintf(output, "basic ");
590 break;
591 case XML_SCHEMA_TYPE_SIMPLE:
592 fprintf(output, "simple ");
593 break;
594 case XML_SCHEMA_TYPE_COMPLEX:
595 fprintf(output, "complex ");
596 break;
597 case XML_SCHEMA_TYPE_SEQUENCE:
598 fprintf(output, "sequence ");
599 break;
600 case XML_SCHEMA_TYPE_CHOICE:
601 fprintf(output, "choice ");
602 break;
603 case XML_SCHEMA_TYPE_ALL:
604 fprintf(output, "all ");
605 break;
606 case XML_SCHEMA_TYPE_UR:
607 fprintf(output, "ur ");
608 break;
609 case XML_SCHEMA_TYPE_RESTRICTION:
610 fprintf(output, "restriction ");
611 break;
612 case XML_SCHEMA_TYPE_EXTENSION:
613 fprintf(output, "extension ");
614 break;
615 default:
616 fprintf(output, "unknowntype%d ", type->type);
617 break;
618 }
619 if (type->base != NULL) {
620 fprintf(output, "base %s, ", type->base);
621 }
622 switch (type->contentType) {
623 case XML_SCHEMA_CONTENT_UNKNOWN:
624 fprintf(output, "unknown ");
625 break;
626 case XML_SCHEMA_CONTENT_EMPTY:
627 fprintf(output, "empty ");
628 break;
629 case XML_SCHEMA_CONTENT_ELEMENTS:
630 fprintf(output, "element ");
631 break;
632 case XML_SCHEMA_CONTENT_MIXED:
633 fprintf(output, "mixed ");
634 break;
635 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
636 fprintf(output, "mixed_or_elems ");
637 break;
638 case XML_SCHEMA_CONTENT_BASIC:
639 fprintf(output, "basic ");
640 break;
641 case XML_SCHEMA_CONTENT_SIMPLE:
642 fprintf(output, "simple ");
643 break;
644 }
645 fprintf(output, "\n");
646 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
647 fprintf(output, " ");
648 if (type->minOccurs != 1)
649 fprintf(output, "min: %d ", type->minOccurs);
650 if (type->maxOccurs >= UNBOUNDED)
651 fprintf(output, "max: unbounded\n");
652 else if (type->maxOccurs != 1)
653 fprintf(output, "max: %d\n", type->maxOccurs);
654 else
655 fprintf(output, "\n");
656 }
657 if (type->annot != NULL)
658 xmlSchemaAnnotDump(output, type->annot);
659 if (type->subtypes != NULL) {
660 xmlSchemaTypePtr sub = type->subtypes;
661
662 fprintf(output, " subtypes: ");
663 while (sub != NULL) {
664 fprintf(output, "%s ", sub->name);
665 sub = sub->next;
666 }
667 fprintf(output, "\n");
668 }
669
670}
671
672/**
673 * xmlSchemaDump:
674 * @output: the file output
675 * @schema: a schema structure
676 *
677 * Dump a Schema structure.
678 */
679void
680xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
681{
682 if (schema == NULL) {
683 fprintf(output, "Schemas: NULL\n");
684 return;
685 }
686 fprintf(output, "Schemas: ");
687 if (schema->name != NULL)
688 fprintf(output, "%s, ", schema->name);
689 else
690 fprintf(output, "no name, ");
691 if (schema->targetNamespace != NULL)
692 fprintf(output, "%s", schema->targetNamespace);
693 else
694 fprintf(output, "no target namespace");
695 fprintf(output, "\n");
696 if (schema->annot != NULL)
697 xmlSchemaAnnotDump(output, schema->annot);
698
699 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
700 output);
701 xmlHashScanFull(schema->elemDecl,
702 (xmlHashScannerFull) xmlSchemaElementDump, output);
703}
704
705/************************************************************************
706 * *
707 * Parsing functions *
708 * *
709 ************************************************************************/
710
711/**
712 * xmlSchemaGetType:
713 * @schema: the schemas context
714 * @name: the type name
715 * @ns: the type namespace
716 *
717 * Lookup a type in the schemas or the predefined types
718 *
719 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
720 */
721static xmlSchemaTypePtr
722xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
723 const xmlChar * namespace) {
724 xmlSchemaTypePtr ret;
725
726 if (name == NULL)
727 return(NULL);
728 if (schema != NULL) {
729 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
730 if (ret != NULL)
731 return(ret);
732 }
733 ret = xmlSchemaGetPredefinedType(name, namespace);
734#ifdef DEBUG
735 if (ret == NULL) {
736 if (namespace == NULL)
737 fprintf(stderr, "Unable to lookup type %s", name);
738 else
739 fprintf(stderr, "Unable to lookup type %s:%s", name, namespace);
740 }
741#endif
742 return(ret);
743}
744
745/************************************************************************
746 * *
747 * Parsing functions *
748 * *
749 ************************************************************************/
750
751#define IS_BLANK_NODE(n) \
752 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
753
754/**
755 * xmlSchemaIsBlank:
756 * @str: a string
757 *
758 * Check if a string is ignorable
759 *
760 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
761 */
762static int
763xmlSchemaIsBlank(xmlChar *str) {
764 if (str == NULL)
765 return(1);
766 while (*str != 0) {
767 if (!(IS_BLANK(*str))) return(0);
768 str++;
769 }
770 return(1);
771}
772
773/**
774 * xmlSchemaAddNotation:
775 * @ctxt: a schema validation context
776 * @schema: the schema being built
777 * @name: the item name
778 *
779 * Add an XML schema Attrribute declaration
780 * *WARNING* this interface is highly subject to change
781 *
782 * Returns the new struture or NULL in case of error
783 */
784static xmlSchemaNotationPtr
785xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
786 const xmlChar * name)
787{
788 xmlSchemaNotationPtr ret = NULL;
789 int val;
790
791 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
792 return (NULL);
793
794 if (schema->notaDecl == NULL)
795 schema->notaDecl = xmlHashCreate(10);
796 if (schema->notaDecl == NULL)
797 return (NULL);
798
799 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
800 if (ret == NULL) {
801 if ((ctxt != NULL) && (ctxt->error != NULL))
802 ctxt->error(ctxt->userData, "Out of memory\n");
803 return (NULL);
804 }
805 memset(ret, 0, sizeof(xmlSchemaNotation));
806 ret->name = xmlStrdup(name);
807 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
808 ret);
809 if (val != 0) {
810 if ((ctxt != NULL) && (ctxt->error != NULL))
811 ctxt->error(ctxt->userData, "Could not add notation %s\n",
812 name);
813 xmlFree((char *) ret->name);
814 xmlFree(ret);
815 return (NULL);
816 }
817 return (ret);
818}
819
820
821/**
822 * xmlSchemaAddAttribute:
823 * @ctxt: a schema validation context
824 * @schema: the schema being built
825 * @name: the item name
826 * @container: the container's name
827 *
828 * Add an XML schema Attrribute declaration
829 * *WARNING* this interface is highly subject to change
830 *
831 * Returns the new struture or NULL in case of error
832 */
833static xmlSchemaAttributePtr
834xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
835 const xmlChar * name)
836{
837 xmlSchemaAttributePtr ret = NULL;
838 int val;
839
840 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
841 return (NULL);
842
843 if (schema->attrDecl == NULL)
844 schema->attrDecl = xmlHashCreate(10);
845 if (schema->attrDecl == NULL)
846 return (NULL);
847
848 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
849 if (ret == NULL) {
850 if ((ctxt != NULL) && (ctxt->error != NULL))
851 ctxt->error(ctxt->userData, "Out of memory\n");
852 return (NULL);
853 }
854 memset(ret, 0, sizeof(xmlSchemaAttribute));
855 ret->name = xmlStrdup(name);
856 val = xmlHashAddEntry3(schema->attrDecl, name,
857 schema->targetNamespace, ctxt->container, ret);
858 if (val != 0) {
859 if ((ctxt != NULL) && (ctxt->error != NULL))
860 ctxt->error(ctxt->userData, "Could not add attribute %s\n",
861 name);
862 xmlFree((char *) ret->name);
863 xmlFree(ret);
864 return (NULL);
865 }
866 return (ret);
867}
868
869/**
870 * xmlSchemaAddAttributeGroup:
871 * @ctxt: a schema validation context
872 * @schema: the schema being built
873 * @name: the item name
874 *
875 * Add an XML schema Attrribute Group declaration
876 *
877 * Returns the new struture or NULL in case of error
878 */
879static xmlSchemaAttributeGroupPtr
880xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
881 const xmlChar * name)
882{
883 xmlSchemaAttributeGroupPtr ret = NULL;
884 int val;
885
886 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
887 return (NULL);
888
889 if (schema->attrgrpDecl == NULL)
890 schema->attrgrpDecl = xmlHashCreate(10);
891 if (schema->attrgrpDecl == NULL)
892 return (NULL);
893
894 ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup));
895 if (ret == NULL) {
896 if ((ctxt != NULL) && (ctxt->error != NULL))
897 ctxt->error(ctxt->userData, "Out of memory\n");
898 return (NULL);
899 }
900 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
901 ret->name = xmlStrdup(name);
902 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
903 schema->targetNamespace, ctxt->container, ret);
904 if (val != 0) {
905 if ((ctxt != NULL) && (ctxt->error != NULL))
906 ctxt->error(ctxt->userData, "Could not add attribute group %s\n",
907 name);
908 xmlFree((char *) ret->name);
909 xmlFree(ret);
910 return (NULL);
911 }
912 return (ret);
913}
914
915/**
916 * xmlSchemaAddElement:
917 * @ctxt: a schema validation context
918 * @schema: the schema being built
919 * @name: the type name
920 * @namespace: the type namespace
921 *
922 * Add an XML schema Element declaration
923 * *WARNING* this interface is highly subject to change
924 *
925 * Returns the new struture or NULL in case of error
926 */
927static xmlSchemaElementPtr
928xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
929 const xmlChar * name, const xmlChar * namespace)
930{
931 xmlSchemaElementPtr ret = NULL;
932 int val;
933
934 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
935 return (NULL);
936
937 if (schema->elemDecl == NULL)
938 schema->elemDecl = xmlHashCreate(10);
939 if (schema->elemDecl == NULL)
940 return (NULL);
941
942 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
943 if (ret == NULL) {
944 if ((ctxt != NULL) && (ctxt->error != NULL))
945 ctxt->error(ctxt->userData, "Out of memory\n");
946 return (NULL);
947 }
948 memset(ret, 0, sizeof(xmlSchemaElement));
949 ret->name = xmlStrdup(name);
950 val = xmlHashAddEntry3(schema->elemDecl, name,
951 namespace, ctxt->container, ret);
952 if (val != 0) {
953 char buf[100];
954
955 snprintf(buf, 99, "privatieelem%d", ctxt->counter++ + 1);
956 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
957 namespace, ret);
958 if (val != 0) {
959 if ((ctxt != NULL) && (ctxt->error != NULL))
960 ctxt->error(ctxt->userData, "Could not add element %s\n",
961 name);
962 xmlFree((char *) ret->name);
963 xmlFree(ret);
964 return (NULL);
965 }
966 }
967 return (ret);
968}
969
970/**
971 * xmlSchemaAddType:
972 * @ctxt: a schema validation context
973 * @schema: the schema being built
974 * @name: the item name
975 *
976 * Add an XML schema Simple Type definition
977 * *WARNING* this interface is highly subject to change
978 *
979 * Returns the new struture or NULL in case of error
980 */
981static xmlSchemaTypePtr
982xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
983 const xmlChar * name)
984{
985 xmlSchemaTypePtr ret = NULL;
986 int val;
987
988 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
989 return (NULL);
990
991 if (schema->typeDecl == NULL)
992 schema->typeDecl = xmlHashCreate(10);
993 if (schema->typeDecl == NULL)
994 return (NULL);
995
996 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
997 if (ret == NULL) {
998 if ((ctxt != NULL) && (ctxt->error != NULL))
999 ctxt->error(ctxt->userData, "Out of memory\n");
1000 return (NULL);
1001 }
1002 memset(ret, 0, sizeof(xmlSchemaType));
1003 ret->name = xmlStrdup(name);
1004 val = xmlHashAddEntry2(schema->typeDecl, name, schema->targetNamespace,
1005 ret);
1006 if (val != 0) {
1007 if ((ctxt != NULL) && (ctxt->error != NULL))
1008 ctxt->error(ctxt->userData, "Could not add type %s\n", name);
1009 xmlFree((char *) ret->name);
1010 xmlFree(ret);
1011 return (NULL);
1012 }
1013 ret->minOccurs = 1;
1014 ret->maxOccurs = 1;
1015
1016 return (ret);
1017}
1018
1019/************************************************************************
1020 * *
1021 * Utilities for parsing *
1022 * *
1023 ************************************************************************/
1024
1025/**
1026 * xmlGetQNameProp:
1027 * @ctxt: a schema validation context
1028 * @node: a subtree containing XML Schema informations
1029 * @name: the attribute name
1030 * @namespace: the result namespace if any
1031 *
1032 * Extract a QName Attribute value
1033 *
1034 * Returns the NCName or NULL if not found, and also update @namespace
1035 * with the namespace URI
1036 */
1037static xmlChar *
1038xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1039 const char *name,
1040 xmlChar **namespace) {
1041 xmlChar *val, *ret, *prefix;
1042 xmlNsPtr ns;
1043
1044
1045 if (namespace != NULL)
1046 *namespace = NULL;
1047 val = xmlGetProp(node, (const xmlChar *) name);
1048 if (val == NULL)
1049 return(NULL);
1050
1051 ret = xmlSplitQName2(val, &prefix);
1052 if (ret == NULL)
1053 return(val);
1054 xmlFree(val);
1055
1056 ns = xmlSearchNs(node->doc, node, prefix);
1057 if (ns == NULL) {
1058 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1059 if ((ctxt != NULL) && (ctxt->error != NULL))
1060 ctxt->error(ctxt->userData,
1061 "Attribute %s: the QName prefix %s is undefined\n",
1062 name, prefix);
1063 } else {
1064 *namespace = xmlStrdup(ns->href);
1065 }
1066 xmlFree(prefix);
1067 return(ret);
1068}
1069
1070/**
1071 * xmlGetMaxOccurs:
1072 * @ctxt: a schema validation context
1073 * @node: a subtree containing XML Schema informations
1074 *
1075 * Get the maxOccurs property
1076 *
1077 * Returns the default if not found, or the value
1078 */
1079static int
1080xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1081 xmlChar *val, *cur;
1082 int ret = 0;
1083
1084 val = xmlGetProp(node, (const xmlChar *) "maxOccurs");
1085 if (val == NULL)
1086 return(1);
1087
1088 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
1089 xmlFree(val);
1090 return(UNBOUNDED); /* encoding it with -1 might be another option */
1091 }
1092
1093 cur = val;
1094 while (IS_BLANK(*cur)) cur++;
1095 while ((*cur >= '0') && (*cur <= '9')) {
1096 ret = ret * 10 + (*cur - '0');
1097 cur++;
1098 }
1099 while (IS_BLANK(*cur)) cur++;
1100 if (*cur != 0) {
1101 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1102 if ((ctxt != NULL) && (ctxt->error != NULL))
1103 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1104 val);
1105 xmlFree(val);
1106 return(1);
1107 }
1108 xmlFree(val);
1109 return(ret);
1110}
1111
1112/**
1113 * xmlGetMinOccurs:
1114 * @ctxt: a schema validation context
1115 * @node: a subtree containing XML Schema informations
1116 *
1117 * Get the minOccurs property
1118 *
1119 * Returns the default if not found, or the value
1120 */
1121static int
1122xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1123 xmlChar *val, *cur;
1124 int ret = 0;
1125
1126 val = xmlGetProp(node, (const xmlChar *) "minOccurs");
1127 if (val == NULL)
1128 return(1);
1129
1130 cur = val;
1131 while (IS_BLANK(*cur)) cur++;
1132 while ((*cur >= '0') && (*cur <= '9')) {
1133 ret = ret * 10 + (*cur - '0');
1134 cur++;
1135 }
1136 while (IS_BLANK(*cur)) cur++;
1137 if (*cur != 0) {
1138 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1139 if ((ctxt != NULL) && (ctxt->error != NULL))
1140 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1141 val);
1142 xmlFree(val);
1143 return(1);
1144 }
1145 xmlFree(val);
1146 return(ret);
1147}
1148
1149/**
1150 * xmlGetBooleanProp:
1151 * @ctxt: a schema validation context
1152 * @node: a subtree containing XML Schema informations
1153 * @name: the attribute name
1154 * @def: the default value
1155 *
1156 * Get is a bolean property is set
1157 *
1158 * Returns the default if not found, 0 if found to be false,
1159 * 1 if found to be true
1160 */
1161static int
1162xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1163 const char *name, int def) {
1164 xmlChar *val;
1165
1166 val = xmlGetProp(node, (const xmlChar *) name);
1167 if (val == NULL)
1168 return(def);
1169
1170 if (xmlStrEqual(val, BAD_CAST"true"))
1171 def = 1;
1172 else if (xmlStrEqual(val, BAD_CAST"false"))
1173 def = 0;
1174 else {
1175 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1176 if ((ctxt != NULL) && (ctxt->error != NULL))
1177 ctxt->error(ctxt->userData,
1178 "Attribute %s: the value %s is not boolean\n",
1179 name, val);
1180 }
1181 xmlFree(val);
1182 return(def);
1183}
1184
1185/************************************************************************
1186 * *
1187 * Shema extraction from an Infoset *
1188 * *
1189 ************************************************************************/
1190static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1191 ctxt, xmlSchemaPtr schema,
1192 xmlNodePtr node);
1193static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt,
1194 xmlSchemaPtr schema,
1195 xmlNodePtr node);
1196static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt,
1197 xmlSchemaPtr schema,
1198 xmlNodePtr node,
1199 int simple);
1200static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1201 xmlSchemaPtr schema,
1202 xmlNodePtr node);
1203static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1204 xmlSchemaPtr schema,
1205 xmlNodePtr node);
1206static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1207 ctxt,
1208 xmlSchemaPtr schema,
1209 xmlNodePtr node);
1210static xmlSchemaAttributeGroupPtr
1211xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1212 xmlSchemaPtr schema, xmlNodePtr node);
1213static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1214 xmlSchemaPtr schema,
1215 xmlNodePtr node);
1216static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1217 xmlSchemaPtr schema,
1218 xmlNodePtr node);
1219static xmlSchemaAttributePtr
1220xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1221 xmlNodePtr node);
1222
1223/**
1224 * xmlSchemaParseAttrDecls:
1225 * @ctxt: a schema validation context
1226 * @schema: the schema being built
1227 * @node: a subtree containing XML Schema informations
1228 * @type: the hosting type
1229 *
1230 * parse a XML schema attrDecls declaration corresponding to
1231 * <!ENTITY % attrDecls
1232 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1233 */
1234static xmlNodePtr
1235xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1236 xmlNodePtr child, xmlSchemaTypePtr type)
1237{
1238 xmlSchemaAttributePtr lastattr, attr;
1239
1240 lastattr = NULL;
1241 while ((IS_SCHEMA(child, "attribute")) ||
1242 (IS_SCHEMA(child, "attributeGroup"))) {
1243 attr = NULL;
1244 if (IS_SCHEMA(child, "attribute")) {
1245 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1246 } else if (IS_SCHEMA(child, "attributeGroup")) {
1247 attr = (xmlSchemaAttributePtr)
1248 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1249 }
1250 if (attr != NULL) {
1251 if (lastattr == NULL) {
1252 type->attributes = attr;
1253 lastattr = attr
1254 ;
1255 } else {
1256 lastattr->next = attr;
1257 lastattr = attr;
1258 }
1259 }
1260 child = child->next;
1261 }
1262 if (IS_SCHEMA(child, "anyAttribute")) {
1263 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1264 if (attr != NULL) {
1265 if (lastattr == NULL) {
1266 type->attributes = attr;
1267 lastattr = attr
1268 ;
1269 } else {
1270 lastattr->next = attr;
1271 lastattr = attr;
1272 }
1273 }
1274 child = child->next;
1275 }
1276 return(child);
1277}
1278
1279/**
1280 * xmlSchemaParseAnnotation:
1281 * @ctxt: a schema validation context
1282 * @schema: the schema being built
1283 * @node: a subtree containing XML Schema informations
1284 *
1285 * parse a XML schema Attrribute declaration
1286 * *WARNING* this interface is highly subject to change
1287 *
1288 * Returns -1 in case of error, 0 if the declaration is inproper and
1289 * 1 in case of success.
1290 */
1291static xmlSchemaAnnotPtr
1292xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1293 xmlNodePtr node)
1294{
1295 xmlSchemaAnnotPtr ret;
1296
1297 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1298 return (NULL);
1299 ret = xmlSchemaNewAnnot(ctxt, node);
1300
1301 return (ret);
1302}
1303
1304/**
1305 * xmlSchemaParseFacet:
1306 * @ctxt: a schema validation context
1307 * @schema: the schema being built
1308 * @node: a subtree containing XML Schema informations
1309 *
1310 * parse a XML schema Facet declaration
1311 * *WARNING* this interface is highly subject to change
1312 *
1313 * Returns the new type structure or NULL in case of error
1314 */
1315static xmlSchemaFacetPtr
1316xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1317 xmlNodePtr node)
1318{
1319 xmlSchemaFacetPtr facet;
1320 xmlNodePtr child = NULL;
1321 xmlChar *value;
1322
1323 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1324 return (NULL);
1325
1326 facet = xmlSchemaNewFacet(ctxt);
1327 if (facet == NULL)
1328 return (NULL);
1329 facet->node = node;
1330 value = xmlGetProp(node, (const xmlChar *) "value");
1331 if (value == NULL) {
1332 xmlSchemaErrorContext(ctxt, schema, node, child);
1333 if ((ctxt != NULL) && (ctxt->error != NULL))
1334 ctxt->error(ctxt->userData, "Facet %s has no value\n", node->name);
1335 xmlSchemaFreeFacet(facet);
1336 return (NULL);
1337 }
1338 if (IS_SCHEMA(node, "minInclusive")) {
1339 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1340 } else if (IS_SCHEMA(node, "minExclusive")) {
1341 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1342 } else if (IS_SCHEMA(node, "maxInclusive")) {
1343 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1344 } else if (IS_SCHEMA(node, "maxExclusive")) {
1345 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1346 } else if (IS_SCHEMA(node, "totalDigits")) {
1347 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1348 } else if (IS_SCHEMA(node, "fractionDigits")) {
1349 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1350 } else if (IS_SCHEMA(node, "pattern")) {
1351 facet->type = XML_SCHEMA_FACET_PATTERN;
1352 } else if (IS_SCHEMA(node, "enumeration")) {
1353 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1354 } else if (IS_SCHEMA(node, "whiteSpace")) {
1355 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1356 } else if (IS_SCHEMA(node, "length")) {
1357 facet->type = XML_SCHEMA_FACET_LENGTH;
1358 } else if (IS_SCHEMA(node, "maxLength")) {
1359 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1360 } else if (IS_SCHEMA(node, "minLength")) {
1361 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1362 } else {
1363 xmlSchemaErrorContext(ctxt, schema, node, child);
1364 if ((ctxt != NULL) && (ctxt->error != NULL))
1365 ctxt->error(ctxt->userData, "Unknown facet type %s\n", node->name);
1366 xmlSchemaFreeFacet(facet);
1367 return(NULL);
1368 }
1369 facet->id = xmlGetProp(node, (const xmlChar *) "id");
1370 facet->value = value;
1371 child = node->children;
1372
1373 if (IS_SCHEMA(child, "annotation")) {
1374 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1375 child = child->next;
1376 }
1377 if (child != NULL) {
1378 xmlSchemaErrorContext(ctxt, schema, node, child);
1379 if ((ctxt != NULL) && (ctxt->error != NULL))
1380 ctxt->error(ctxt->userData,
1381 "Facet %s has unexpected child content\n",
1382 node->name);
1383 }
1384 return (facet);
1385}
1386
1387/**
1388 * xmlSchemaParseAny:
1389 * @ctxt: a schema validation context
1390 * @schema: the schema being built
1391 * @node: a subtree containing XML Schema informations
1392 *
1393 * parse a XML schema Any declaration
1394 * *WARNING* this interface is highly subject to change
1395 *
1396 * Returns the new type structure or NULL in case of error
1397 */
1398static xmlSchemaTypePtr
1399xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1400 xmlNodePtr node)
1401{
1402 xmlSchemaTypePtr type;
1403 xmlNodePtr child = NULL;
1404 xmlChar name[30];
1405
1406 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1407 return (NULL);
1408 snprintf((char *)name, 30, "any %d", ctxt->counter++ + 1);
1409 type = xmlSchemaAddType(ctxt, schema, name);
1410 if (type == NULL)
1411 return (NULL);
1412 type->node = node;
1413 type->type = XML_SCHEMA_TYPE_ANY;
1414 child = node->children;
1415 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1416 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1417
1418 if (IS_SCHEMA(child, "annotation")) {
1419 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1420 child = child->next;
1421 }
1422 if (child != NULL) {
1423 xmlSchemaErrorContext(ctxt, schema, node, child);
1424 if ((ctxt != NULL) && (ctxt->error != NULL))
1425 ctxt->error(ctxt->userData,
1426 "Sequence %s has unexpected content\n",
1427 type->name);
1428 }
1429
1430 return (type);
1431}
1432
1433/**
1434 * xmlSchemaParseNotation:
1435 * @ctxt: a schema validation context
1436 * @schema: the schema being built
1437 * @node: a subtree containing XML Schema informations
1438 *
1439 * parse a XML schema Notation declaration
1440 *
1441 * Returns the new structure or NULL in case of error
1442 */
1443static xmlSchemaNotationPtr
1444xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1445 xmlNodePtr node)
1446{
1447 xmlChar *name;
1448 xmlSchemaNotationPtr ret;
1449 xmlNodePtr child = NULL;
1450
1451 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1452 return (NULL);
1453 name = xmlGetProp(node, (const xmlChar *) "name");
1454 if (name == NULL) {
1455 xmlSchemaErrorContext(ctxt, schema, node, child);
1456 if ((ctxt != NULL) && (ctxt->error != NULL))
1457 ctxt->error(ctxt->userData, "Notation has no name\n");
1458 return (NULL);
1459 }
1460 ret = xmlSchemaAddNotation(ctxt, schema, name);
1461 if (ret == NULL) {
1462 xmlFree(name);
1463 return (NULL);
1464 }
1465 child = node->children;
1466 if (IS_SCHEMA(child, "annotation")) {
1467 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1468 child = child->next;
1469 }
1470 if (child != NULL) {
1471 xmlSchemaErrorContext(ctxt, schema, node, child);
1472 if ((ctxt != NULL) && (ctxt->error != NULL))
1473 ctxt->error(ctxt->userData,
1474 "notation %s has unexpected content\n",
1475 name);
1476 }
1477
1478 return (ret);
1479}
1480
1481/**
1482 * xmlSchemaParseAnyAttribute:
1483 * @ctxt: a schema validation context
1484 * @schema: the schema being built
1485 * @node: a subtree containing XML Schema informations
1486 *
1487 * parse a XML schema AnyAttrribute declaration
1488 * *WARNING* this interface is highly subject to change
1489 *
1490 * Returns an attribute def structure or NULL
1491 */
1492static xmlSchemaAttributePtr
1493xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1494 xmlNodePtr node)
1495{
1496 xmlChar *processContents;
1497 xmlSchemaAttributePtr ret;
1498 xmlNodePtr child = NULL;
1499 char name[100];
1500
1501 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1502 return (NULL);
1503
1504 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
1505 ret = xmlSchemaAddAttribute(ctxt, schema, (xmlChar *)name);
1506 if (ret == NULL) {
1507 return (NULL);
1508 }
1509 ret->id = xmlGetProp(node, (const xmlChar *) "id");
1510 processContents = xmlGetProp(node, (const xmlChar *) "processContents");
1511 if ((processContents == NULL) ||
1512 (xmlStrEqual(processContents, (const xmlChar *)"strict"))) {
1513 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1514 } else if (xmlStrEqual(processContents, (const xmlChar *)"skip")) {
1515 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1516 } else if (xmlStrEqual(processContents, (const xmlChar *)"lax")) {
1517 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
1518 } else {
1519 xmlSchemaErrorContext(ctxt, schema, node, child);
1520 if ((ctxt != NULL) && (ctxt->error != NULL))
1521 ctxt->error(ctxt->userData,
1522 "anyAttribute has unexpected content for processContents: %s\n",
1523 processContents);
1524 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1525 }
1526 if (processContents != NULL)
1527 xmlFree(processContents);
1528
1529 child = node->children;
1530 if (IS_SCHEMA(child, "annotation")) {
1531 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1532 child = child->next;
1533 }
1534 if (child != NULL) {
1535 xmlSchemaErrorContext(ctxt, schema, node, child);
1536 if ((ctxt != NULL) && (ctxt->error != NULL))
1537 ctxt->error(ctxt->userData,
1538 "anyAttribute %s has unexpected content\n",
1539 name);
1540 }
1541
1542 return (ret);
1543}
1544
1545
1546/**
1547 * xmlSchemaParseAttribute:
1548 * @ctxt: a schema validation context
1549 * @schema: the schema being built
1550 * @node: a subtree containing XML Schema informations
1551 *
1552 * parse a XML schema Attrribute declaration
1553 * *WARNING* this interface is highly subject to change
1554 *
1555 * Returns -1 in case of error, 0 if the declaration is inproper and
1556 * 1 in case of success.
1557 */
1558static xmlSchemaAttributePtr
1559xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1560 xmlNodePtr node)
1561{
1562 xmlChar *name, *refNs = NULL, *ref = NULL;
1563 xmlSchemaAttributePtr ret;
1564 xmlNodePtr child = NULL;
1565
1566 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1567 return (NULL);
1568 name = xmlGetProp(node, (const xmlChar *) "name");
1569 if (name == NULL) {
1570 char buf[100];
1571
1572 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1573 if (ref == NULL) {
1574 xmlSchemaErrorContext(ctxt, schema, node, child);
1575 if ((ctxt != NULL) && (ctxt->error != NULL))
1576 ctxt->error(ctxt->userData, "Attribute has no name nor ref\n");
1577 return (NULL);
1578 }
1579 snprintf(buf, 99, "anonattr%d", ctxt->counter++ + 1);
1580 name = xmlStrdup((xmlChar *) buf);
1581 }
1582 ret = xmlSchemaAddAttribute(ctxt, schema, name);
1583 if (ret == NULL) {
1584 xmlFree(name);
1585 if (ref != NULL)
1586 xmlFree(ref);
1587 return (NULL);
1588 }
1589 xmlFree(name);
1590 ret->ref = ref;
1591 ret->refNs = refNs;
1592 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
1593 child = node->children;
1594 if (IS_SCHEMA(child, "annotation")) {
1595 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1596 child = child->next;
1597 }
1598 if (IS_SCHEMA(child, "simpleType")) {
1599 ret->base = xmlSchemaParseSimpleType(ctxt, schema, child);
1600 child = child->next;
1601 }
1602 if (child != NULL) {
1603 xmlSchemaErrorContext(ctxt, schema, node, child);
1604 if ((ctxt != NULL) && (ctxt->error != NULL))
1605 ctxt->error(ctxt->userData,
1606 "attribute %s has unexpected content\n",
1607 name);
1608 }
1609
1610 return (ret);
1611}
1612
1613/**
1614 * xmlSchemaParseAttributeGroup:
1615 * @ctxt: a schema validation context
1616 * @schema: the schema being built
1617 * @node: a subtree containing XML Schema informations
1618 *
1619 * parse a XML schema Attribute Group declaration
1620 * *WARNING* this interface is highly subject to change
1621 *
1622 * Returns the attribute group or NULL in case of error.
1623 */
1624static xmlSchemaAttributeGroupPtr
1625xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1626 xmlNodePtr node)
1627{
1628 xmlChar *name, *refNs = NULL, *ref = NULL;
1629 xmlSchemaAttributeGroupPtr ret;
1630 xmlSchemaAttributePtr last = NULL, attr;
1631 xmlNodePtr child = NULL;
1632 xmlChar *oldcontainer;
1633
1634 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1635 return (NULL);
1636 oldcontainer = ctxt->container;
1637 name = xmlGetProp(node, (const xmlChar *) "name");
1638 if (name == NULL) {
1639 char buf[100];
1640
1641 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1642 if (ref == NULL) {
1643 xmlSchemaErrorContext(ctxt, schema, node, child);
1644 if ((ctxt != NULL) && (ctxt->error != NULL))
1645 ctxt->error(ctxt->userData,
1646 "AttributeGroup has no name nor ref\n");
1647 return (NULL);
1648 }
1649 snprintf(buf, 99, "anonattrgroup%d", ctxt->counter++ + 1);
1650 name = xmlStrdup((xmlChar *) buf);
1651 }
1652 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
1653 if (ret == NULL) {
1654 xmlFree(name);
1655 if (ref != NULL)
1656 xmlFree(ref);
1657 return (NULL);
1658 }
1659 ret->ref = ref;
1660 ret->refNs = refNs;
1661 child = node->children;
1662 ctxt->container = name;
1663 if (IS_SCHEMA(child, "annotation")) {
1664 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1665 child = child->next;
1666 }
1667 while ((IS_SCHEMA(child, "attribute")) ||
1668 (IS_SCHEMA(child, "attributeGroup"))) {
1669 attr = NULL;
1670 if (IS_SCHEMA(child, "attribute")) {
1671 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1672 } else if (IS_SCHEMA(child, "attributeGroup")) {
1673 attr = (xmlSchemaAttributePtr)
1674 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1675 }
1676 if (attr != NULL) {
1677 if (last == NULL) {
1678 ret->attributes = attr;
1679 last = attr;
1680 } else {
1681 last->next = attr;
1682 last = attr;
1683 }
1684 }
1685 child = child->next;
1686 }
1687 if (IS_SCHEMA(child, "anyAttribute")) {
1688 TODO
1689 child = child->next;
1690 }
1691 if (child != NULL) {
1692 xmlSchemaErrorContext(ctxt, schema, node, child);
1693 if ((ctxt != NULL) && (ctxt->error != NULL))
1694 ctxt->error(ctxt->userData,
1695 "attribute group %s has unexpected content\n",
1696 name);
1697 }
1698
1699 ctxt->container = oldcontainer;
1700 return (ret);
1701}
1702
1703/**
1704 * xmlSchemaParseElement:
1705 * @ctxt: a schema validation context
1706 * @schema: the schema being built
1707 * @node: a subtree containing XML Schema informations
1708 *
1709 * parse a XML schema Element declaration
1710 * *WARNING* this interface is highly subject to change
1711 *
1712 * Returns -1 in case of error, 0 if the declaration is inproper and
1713 * 1 in case of success.
1714 */
1715static xmlSchemaElementPtr
1716xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1717 xmlNodePtr node, int toplevel)
1718{
1719 xmlChar *name, *refNs = NULL, *ref = NULL, *namespace, *fixed;
1720 xmlSchemaElementPtr ret;
1721 xmlNodePtr child = NULL;
1722 xmlChar *oldcontainer;
1723
1724 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1725 return (NULL);
1726 oldcontainer = ctxt->container;
1727 name = xmlGetProp(node, (const xmlChar *) "name");
1728 if (name == NULL) {
1729 char buf[100];
1730
1731 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1732 if (ref == NULL) {
1733 xmlSchemaErrorContext(ctxt, schema, node, child);
1734 if ((ctxt != NULL) && (ctxt->error != NULL))
1735 ctxt->error(ctxt->userData, "Element has no name nor ref\n");
1736 return (NULL);
1737 }
1738 snprintf(buf, 99, "anonelem%d", ctxt->counter++ + 1);
1739 name = xmlStrdup((xmlChar *) buf);
1740 }
1741 namespace = xmlGetProp(node, (const xmlChar *) "targetNamespace");
1742 if (namespace == NULL)
1743 ret =
1744 xmlSchemaAddElement(ctxt, schema, name,
1745 schema->targetNamespace);
1746 else
1747 ret = xmlSchemaAddElement(ctxt, schema, name, namespace);
1748 if (namespace != NULL)
1749 xmlFree(namespace);
1750 if (ret == NULL) {
1751 xmlFree(name);
1752 if (ref != NULL)
1753 xmlFree(ref);
1754 return (NULL);
1755 }
1756 ret->type = XML_SCHEMA_TYPE_ELEMENT;
1757 ret->ref = ref;
1758 ret->refNs = refNs;
1759 if (ref != NULL)
1760 ret->flags |= XML_SCHEMAS_ELEM_REF;
1761 if (toplevel)
1762 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
1763 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
1764 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1765 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
1766 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1767 ctxt->container = name;
1768
1769 ret->id = xmlGetProp(node, BAD_CAST "id");
1770 ret->namedType = xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
1771 ret->substGroup = xmlGetQNameProp(ctxt, node, "substitutionGroup",
1772 &(ret->substGroupNs));
1773 fixed = xmlGetProp(node, BAD_CAST "fixed");
1774 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
1775 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1776
1777 ret->value = xmlGetProp(node, BAD_CAST "default");
1778 if ((ret->value != NULL) && (fixed != NULL)) {
1779 xmlSchemaErrorContext(ctxt, schema, node, child);
1780 ctxt->error(ctxt->userData,
1781 "Element %s has both default and fixed\n",
1782 ret->name);
1783 xmlFree(fixed);
1784 } else if (fixed != NULL) {
1785 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
1786 ret->value = fixed;
1787 }
1788
1789 child = node->children;
1790 if (IS_SCHEMA(child, "annotation")) {
1791 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1792 child = child->next;
1793 }
1794 if (IS_SCHEMA(child, "complexType")) {
1795 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
1796 child = child->next;
1797 } else if (IS_SCHEMA(child, "simpleType")) {
1798 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
1799 child = child->next;
1800 }
1801 while ((IS_SCHEMA(child, "unique")) ||
1802 (IS_SCHEMA(child, "key")) ||
1803 (IS_SCHEMA(child, "keyref"))) {
1804 TODO
1805 child = child->next;
1806 }
1807 if (child != NULL) {
1808 xmlSchemaErrorContext(ctxt, schema, node, child);
1809 if ((ctxt != NULL) && (ctxt->error != NULL))
1810 ctxt->error(ctxt->userData,
1811 "element %s has unexpected content\n",
1812 name);
1813 }
1814
1815 ctxt->container = oldcontainer;
1816 xmlFree(name);
1817 return (ret);
1818}
1819
1820/**
1821 * xmlSchemaParseUnion:
1822 * @ctxt: a schema validation context
1823 * @schema: the schema being built
1824 * @node: a subtree containing XML Schema informations
1825 *
1826 * parse a XML schema Union definition
1827 * *WARNING* this interface is highly subject to change
1828 *
1829 * Returns -1 in case of error, 0 if the declaration is inproper and
1830 * 1 in case of success.
1831 */
1832static xmlSchemaTypePtr
1833xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1834 xmlNodePtr node)
1835{
1836 xmlSchemaTypePtr type, subtype, last = NULL;
1837 xmlNodePtr child = NULL;
1838 xmlChar name[30];
1839
1840 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1841 return (NULL);
1842
1843
1844 snprintf((char *)name, 30, "union %d", ctxt->counter++ + 1);
1845 type = xmlSchemaAddType(ctxt, schema, name);
1846 if (type == NULL)
1847 return (NULL);
1848 type->node = node;
1849 type->type = XML_SCHEMA_TYPE_LIST;
1850 type->id = xmlGetProp(node, BAD_CAST "id");
1851 type->ref = xmlGetProp(node, BAD_CAST "memberTypes");
1852
1853 child = node->children;
1854 if (IS_SCHEMA(child, "annotation")) {
1855 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1856 child = child->next;
1857 }
1858 while (IS_SCHEMA(child, "simpleType")) {
1859 subtype = (xmlSchemaTypePtr)
1860 xmlSchemaParseSimpleType(ctxt, schema, child);
1861 if (subtype != NULL) {
1862 if (last == NULL) {
1863 type->subtypes = subtype;
1864 last = subtype;
1865 } else {
1866 last->next = subtype;
1867 last = subtype;
1868 }
1869 last->next = NULL;
1870 }
1871 child = child->next;
1872 }
1873 if (child != NULL) {
1874 xmlSchemaErrorContext(ctxt, schema, node, child);
1875 if ((ctxt != NULL) && (ctxt->error != NULL))
1876 ctxt->error(ctxt->userData,
1877 "Union %s has unexpected content\n",
1878 type->name);
1879 }
1880 return (type);
1881}
1882
1883/**
1884 * xmlSchemaParseList:
1885 * @ctxt: a schema validation context
1886 * @schema: the schema being built
1887 * @node: a subtree containing XML Schema informations
1888 *
1889 * parse a XML schema List definition
1890 * *WARNING* this interface is highly subject to change
1891 *
1892 * Returns -1 in case of error, 0 if the declaration is inproper and
1893 * 1 in case of success.
1894 */
1895static xmlSchemaTypePtr
1896xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1897 xmlNodePtr node)
1898{
1899 xmlSchemaTypePtr type, subtype;
1900 xmlNodePtr child = NULL;
1901 xmlChar name[30];
1902
1903 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1904 return (NULL);
1905
1906 snprintf((char *)name, 30, "list %d", ctxt->counter++ + 1);
1907 type = xmlSchemaAddType(ctxt, schema, name);
1908 if (type == NULL)
1909 return (NULL);
1910 type->node = node;
1911 type->type = XML_SCHEMA_TYPE_LIST;
1912 type->id = xmlGetProp(node, BAD_CAST "id");
1913 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
1914
1915 child = node->children;
1916 if (IS_SCHEMA(child, "annotation")) {
1917 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1918 child = child->next;
1919 }
1920 subtype = NULL;
1921 if (IS_SCHEMA(child, "simpleType")) {
1922 subtype = (xmlSchemaTypePtr)
1923 xmlSchemaParseSimpleType(ctxt, schema, child);
1924 child = child->next;
1925 type->subtypes = subtype;
1926 }
1927 if (child != NULL) {
1928 xmlSchemaErrorContext(ctxt, schema, node, child);
1929 if ((ctxt != NULL) && (ctxt->error != NULL))
1930 ctxt->error(ctxt->userData,
1931 "List %s has unexpected content\n",
1932 type->name);
1933 }
1934 return (type);
1935}
1936/**
1937 * xmlSchemaParseSimpleType:
1938 * @ctxt: a schema validation context
1939 * @schema: the schema being built
1940 * @node: a subtree containing XML Schema informations
1941 *
1942 * parse a XML schema Simple Type definition
1943 * *WARNING* this interface is highly subject to change
1944 *
1945 * Returns -1 in case of error, 0 if the declaration is inproper and
1946 * 1 in case of success.
1947 */
1948static xmlSchemaTypePtr
1949xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1950 xmlNodePtr node)
1951{
1952 xmlSchemaTypePtr type, subtype;
1953 xmlNodePtr child = NULL;
1954 xmlChar *name;
1955
1956 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1957 return (NULL);
1958
1959
1960 name = xmlGetProp(node, (const xmlChar *) "name");
1961 if (name == NULL) {
1962 char buf[100];
1963
1964 snprintf(buf, 99, "simpletype%d", ctxt->counter++ + 1);
1965 name = xmlStrdup((xmlChar *) buf);
1966 }
1967 if (name == NULL) {
1968 xmlSchemaErrorContext(ctxt, schema, node, child);
1969 if ((ctxt != NULL) && (ctxt->error != NULL))
1970 ctxt->error(ctxt->userData, "simpleType has no name\n");
1971 return (NULL);
1972 }
1973 type = xmlSchemaAddType(ctxt, schema, name);
1974 xmlFree(name);
1975 if (type == NULL)
1976 return (NULL);
1977 type->node = node;
1978 type->type = XML_SCHEMA_TYPE_SIMPLE;
1979 type->id = xmlGetProp(node, BAD_CAST "id");
1980
1981 child = node->children;
1982 if (IS_SCHEMA(child, "annotation")) {
1983 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1984 child = child->next;
1985 }
1986 subtype = NULL;
1987 if (IS_SCHEMA(child, "restriction")) {
1988 subtype = (xmlSchemaTypePtr)
1989 xmlSchemaParseRestriction(ctxt, schema, child, 1);
1990 child = child->next;
1991 } else if (IS_SCHEMA(child, "list")) {
1992 subtype = (xmlSchemaTypePtr)
1993 xmlSchemaParseList(ctxt, schema, child);
1994 child = child->next;
1995 } else if (IS_SCHEMA(child, "union")) {
1996 subtype = (xmlSchemaTypePtr)
1997 xmlSchemaParseUnion(ctxt, schema, child);
1998 child = child->next;
1999 }
2000 type->subtypes = subtype;
2001 if (child != NULL) {
2002 xmlSchemaErrorContext(ctxt, schema, node, child);
2003 if ((ctxt != NULL) && (ctxt->error != NULL))
2004 ctxt->error(ctxt->userData,
2005 "SimpleType %s has unexpected content\n",
2006 type->name);
2007 }
2008
2009 return (type);
2010}
2011
2012
2013/**
2014 * xmlSchemaParseGroup:
2015 * @ctxt: a schema validation context
2016 * @schema: the schema being built
2017 * @node: a subtree containing XML Schema informations
2018 *
2019 * parse a XML schema Group definition
2020 * *WARNING* this interface is highly subject to change
2021 *
2022 * Returns -1 in case of error, 0 if the declaration is inproper and
2023 * 1 in case of success.
2024 */
2025static xmlSchemaTypePtr
2026xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2027 xmlNodePtr node)
2028{
2029 xmlSchemaTypePtr type, subtype;
2030 xmlNodePtr child = NULL;
2031 xmlChar *name, *ref = NULL, *refNs = NULL;
2032
2033 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2034 return (NULL);
2035
2036
2037 name = xmlGetProp(node, (const xmlChar *) "name");
2038 if (name == NULL) {
2039 char buf[100];
2040
2041 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2042 if (ref == NULL) {
2043 xmlSchemaErrorContext(ctxt, schema, node, child);
2044 if ((ctxt != NULL) && (ctxt->error != NULL))
2045 ctxt->error(ctxt->userData, "Group has no name nor ref\n");
2046 return (NULL);
2047 }
2048 snprintf(buf, 99, "anongroup%d", ctxt->counter++ + 1);
2049 name = xmlStrdup((xmlChar *) buf);
2050 }
2051 type = xmlSchemaAddType(ctxt, schema, name);
2052 if (type == NULL)
2053 return (NULL);
2054 type->node = node;
2055 type->type = XML_SCHEMA_TYPE_GROUP;
2056 type->id = xmlGetProp(node, BAD_CAST "id");
2057 type->ref = ref;
2058 type->refNs = refNs;
2059 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2060 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2061
2062 child = node->children;
2063 if (IS_SCHEMA(child, "annotation")) {
2064 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2065 child = child->next;
2066 }
2067 subtype = NULL;
2068 if (IS_SCHEMA(child, "all")) {
2069 subtype = (xmlSchemaTypePtr)
2070 xmlSchemaParseAll(ctxt, schema, child);
2071 child = child->next;
2072 } else if (IS_SCHEMA(child, "choice")) {
2073 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2074 child = child->next;
2075 } else if (IS_SCHEMA(child, "sequence")) {
2076 subtype = (xmlSchemaTypePtr)
2077 xmlSchemaParseSequence(ctxt, schema, child);
2078 child = child->next;
2079 }
2080 if (subtype != NULL)
2081 type->subtypes = subtype;
2082 if (child != NULL) {
2083 xmlSchemaErrorContext(ctxt, schema, node, child);
2084 if ((ctxt != NULL) && (ctxt->error != NULL))
2085 ctxt->error(ctxt->userData,
2086 "Group %s has unexpected content\n",
2087 type->name);
2088 }
2089
2090 return (type);
2091}
2092
2093/**
2094 * xmlSchemaParseAll:
2095 * @ctxt: a schema validation context
2096 * @schema: the schema being built
2097 * @node: a subtree containing XML Schema informations
2098 *
2099 * parse a XML schema All definition
2100 * *WARNING* this interface is highly subject to change
2101 *
2102 * Returns -1 in case of error, 0 if the declaration is inproper and
2103 * 1 in case of success.
2104 */
2105static xmlSchemaTypePtr
2106xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2107 xmlNodePtr node)
2108{
2109 xmlSchemaTypePtr type, subtype, last = NULL;
2110 xmlNodePtr child = NULL;
2111 xmlChar name[30];
2112
2113 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2114 return (NULL);
2115
2116
2117 snprintf((char *)name, 30, "all%d", ctxt->counter++ + 1);
2118 type = xmlSchemaAddType(ctxt, schema, name);
2119 if (type == NULL)
2120 return (NULL);
2121 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002122 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002123 type->id = xmlGetProp(node, BAD_CAST "id");
2124 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2125 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2126
2127 child = node->children;
2128 if (IS_SCHEMA(child, "annotation")) {
2129 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2130 child = child->next;
2131 }
2132 while (IS_SCHEMA(child, "element")) {
2133 subtype = (xmlSchemaTypePtr)
2134 xmlSchemaParseElement(ctxt, schema, child, 0);
2135 if (subtype != NULL) {
2136 if (last == NULL) {
2137 type->subtypes = subtype;
2138 last = subtype;
2139 } else {
2140 last->next = subtype;
2141 last = subtype;
2142 }
2143 last->next = NULL;
2144 }
2145 child = child->next;
2146 }
2147 if (child != NULL) {
2148 xmlSchemaErrorContext(ctxt, schema, node, child);
2149 if ((ctxt != NULL) && (ctxt->error != NULL))
2150 ctxt->error(ctxt->userData,
2151 "All %s has unexpected content\n",
2152 type->name);
2153 }
2154
2155 return (type);
2156}
2157
2158/**
2159 * xmlSchemaParseChoice:
2160 * @ctxt: a schema validation context
2161 * @schema: the schema being built
2162 * @node: a subtree containing XML Schema informations
2163 *
2164 * parse a XML schema Choice definition
2165 * *WARNING* this interface is highly subject to change
2166 *
2167 * Returns -1 in case of error, 0 if the declaration is inproper and
2168 * 1 in case of success.
2169 */
2170static xmlSchemaTypePtr
2171xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2172 xmlNodePtr node)
2173{
2174 xmlSchemaTypePtr type, subtype, last = NULL;
2175 xmlNodePtr child = NULL;
2176 xmlChar name[30];
2177
2178 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2179 return (NULL);
2180
2181
2182 snprintf((char *)name, 30, "choice %d", ctxt->counter++ + 1);
2183 type = xmlSchemaAddType(ctxt, schema, name);
2184 if (type == NULL)
2185 return (NULL);
2186 type->node = node;
2187 type->type = XML_SCHEMA_TYPE_CHOICE;
2188 type->id = xmlGetProp(node, BAD_CAST "id");
2189 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2190 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2191
2192 child = node->children;
2193 if (IS_SCHEMA(child, "annotation")) {
2194 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2195 child = child->next;
2196 }
2197 while ((IS_SCHEMA(child, "element")) ||
2198 (IS_SCHEMA(child, "group")) ||
2199 (IS_SCHEMA(child, "any")) ||
2200 (IS_SCHEMA(child, "choice")) ||
2201 (IS_SCHEMA(child, "sequence"))) {
2202 subtype = NULL;
2203 if (IS_SCHEMA(child, "element")) {
2204 subtype = (xmlSchemaTypePtr)
2205 xmlSchemaParseElement(ctxt, schema, child, 0);
2206 } else if (IS_SCHEMA(child, "group")) {
2207 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2208 } else if (IS_SCHEMA(child, "any")) {
2209 subtype = xmlSchemaParseAny(ctxt, schema, child);
2210 } else if (IS_SCHEMA(child, "sequence")) {
2211 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2212 } else if (IS_SCHEMA(child, "choice")) {
2213 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2214 }
2215 if (subtype != NULL) {
2216 if (last == NULL) {
2217 type->subtypes = subtype;
2218 last = subtype;
2219 } else {
2220 last->next = subtype;
2221 last = subtype;
2222 }
2223 last->next = NULL;
2224 }
2225 child = child->next;
2226 }
2227 if (child != NULL) {
2228 xmlSchemaErrorContext(ctxt, schema, node, child);
2229 if ((ctxt != NULL) && (ctxt->error != NULL))
2230 ctxt->error(ctxt->userData,
2231 "Choice %s has unexpected content\n",
2232 type->name);
2233 }
2234
2235 return (type);
2236}
2237
2238/**
2239 * xmlSchemaParseSequence:
2240 * @ctxt: a schema validation context
2241 * @schema: the schema being built
2242 * @node: a subtree containing XML Schema informations
2243 *
2244 * parse a XML schema Sequence definition
2245 * *WARNING* this interface is highly subject to change
2246 *
2247 * Returns -1 in case of error, 0 if the declaration is inproper and
2248 * 1 in case of success.
2249 */
2250static xmlSchemaTypePtr
2251xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2252 xmlNodePtr node)
2253{
2254 xmlSchemaTypePtr type, subtype, last = NULL;
2255 xmlNodePtr child = NULL;
2256 xmlChar name[30];
2257
2258 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2259 return (NULL);
2260
2261
2262 snprintf((char *)name, 30, "sequence %d", ctxt->counter++ + 1);
2263 type = xmlSchemaAddType(ctxt, schema, name);
2264 if (type == NULL)
2265 return (NULL);
2266 type->node = node;
2267 type->type = XML_SCHEMA_TYPE_SEQUENCE;
2268 type->id = xmlGetProp(node, BAD_CAST "id");
2269 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2270 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2271
2272 child = node->children;
2273 if (IS_SCHEMA(child, "annotation")) {
2274 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2275 child = child->next;
2276 }
2277 while ((IS_SCHEMA(child, "element")) ||
2278 (IS_SCHEMA(child, "group")) ||
2279 (IS_SCHEMA(child, "any")) ||
2280 (IS_SCHEMA(child, "choice")) ||
2281 (IS_SCHEMA(child, "sequence"))) {
2282 subtype = NULL;
2283 if (IS_SCHEMA(child, "element")) {
2284 subtype = (xmlSchemaTypePtr)
2285 xmlSchemaParseElement(ctxt, schema, child, 0);
2286 } else if (IS_SCHEMA(child, "group")) {
2287 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2288 } else if (IS_SCHEMA(child, "any")) {
2289 subtype = xmlSchemaParseAny(ctxt, schema, child);
2290 } else if (IS_SCHEMA(child, "choice")) {
2291 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2292 } else if (IS_SCHEMA(child, "sequence")) {
2293 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2294 }
2295 if (subtype != NULL) {
2296 if (last == NULL) {
2297 type->subtypes = subtype;
2298 last = subtype;
2299 } else {
2300 last->next = subtype;
2301 last = subtype;
2302 }
2303 last->next = NULL;
2304 }
2305 child = child->next;
2306 }
2307 if (child != NULL) {
2308 xmlSchemaErrorContext(ctxt, schema, node, child);
2309 if ((ctxt != NULL) && (ctxt->error != NULL))
2310 ctxt->error(ctxt->userData,
2311 "Sequence %s has unexpected content\n",
2312 type->name);
2313 }
2314
2315 return (type);
2316}
2317
2318/**
2319 * xmlSchemaParseRestriction:
2320 * @ctxt: a schema validation context
2321 * @schema: the schema being built
2322 * @node: a subtree containing XML Schema informations
2323 * @simple: is that part of a simple type.
2324 *
2325 * parse a XML schema Restriction definition
2326 * *WARNING* this interface is highly subject to change
2327 *
2328 * Returns the type definition or NULL in case of error
2329 */
2330static xmlSchemaTypePtr
2331xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2332 xmlNodePtr node, int simple)
2333{
2334 xmlSchemaTypePtr type, subtype;
2335 xmlSchemaFacetPtr facet, lastfacet = NULL;
2336 xmlNodePtr child = NULL;
2337 xmlChar name[30];
2338 xmlChar *oldcontainer;
2339
2340 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2341 return (NULL);
2342
2343 oldcontainer = ctxt->container;
2344
2345 snprintf((char *)name, 30, "restriction %d", ctxt->counter++ + 1);
2346 type = xmlSchemaAddType(ctxt, schema, name);
2347 if (type == NULL)
2348 return (NULL);
2349 type->node = node;
2350 type->type = XML_SCHEMA_TYPE_RESTRICTION;
2351 type->id = xmlGetProp(node, BAD_CAST "id");
2352 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2353 if ((!simple) && (type->base == NULL)) {
2354 xmlSchemaErrorContext(ctxt, schema, node, child);
2355 if ((ctxt != NULL) && (ctxt->error != NULL))
2356 ctxt->error(ctxt->userData,
2357 "Restriction %s has no base\n",
2358 type->name);
2359 }
2360 ctxt->container = name;
2361
2362 child = node->children;
2363 if (IS_SCHEMA(child, "annotation")) {
2364 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2365 child = child->next;
2366 }
2367 subtype = NULL;
2368
2369 if (IS_SCHEMA(child, "all")) {
2370 subtype = (xmlSchemaTypePtr)
2371 xmlSchemaParseAll(ctxt, schema, child);
2372 child = child->next;
2373 type->subtypes = subtype;
2374 } else if (IS_SCHEMA(child, "choice")) {
2375 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2376 child = child->next;
2377 type->subtypes = subtype;
2378 } else if (IS_SCHEMA(child, "sequence")) {
2379 subtype = (xmlSchemaTypePtr)
2380 xmlSchemaParseSequence(ctxt, schema, child);
2381 child = child->next;
2382 type->subtypes = subtype;
2383 } else if (IS_SCHEMA(child, "group")) {
2384 subtype = (xmlSchemaTypePtr)
2385 xmlSchemaParseGroup(ctxt, schema, child);
2386 child = child->next;
2387 type->subtypes = subtype;
2388 } else {
2389 if (IS_SCHEMA(child, "simpleType")) {
2390 subtype = (xmlSchemaTypePtr)
2391 xmlSchemaParseSimpleType(ctxt, schema, child);
2392 child = child->next;
2393 type->baseType = subtype;
2394 }
2395 /*
2396 * Facets
2397 */
2398 while ((IS_SCHEMA(child, "minInclusive")) ||
2399 (IS_SCHEMA(child, "minExclusive")) ||
2400 (IS_SCHEMA(child, "maxInclusive")) ||
2401 (IS_SCHEMA(child, "maxExclusive")) ||
2402 (IS_SCHEMA(child, "totalDigits")) ||
2403 (IS_SCHEMA(child, "fractionDigits")) ||
2404 (IS_SCHEMA(child, "pattern")) ||
2405 (IS_SCHEMA(child, "enumeration")) ||
2406 (IS_SCHEMA(child, "whiteSpace")) ||
2407 (IS_SCHEMA(child, "length")) ||
2408 (IS_SCHEMA(child, "maxLength")) ||
2409 (IS_SCHEMA(child, "minLength"))) {
2410 facet = xmlSchemaParseFacet(ctxt, schema, child);
2411 if (facet != NULL) {
2412 if (lastfacet == NULL) {
2413 type->facets = facet;
2414 lastfacet = facet;
2415 } else {
2416 lastfacet->next = facet;
2417 lastfacet = facet;
2418 }
2419 lastfacet->next = NULL;
2420 }
2421 child = child->next;
2422 }
2423 }
2424 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2425 if (child != NULL) {
2426 xmlSchemaErrorContext(ctxt, schema, node, child);
2427 if ((ctxt != NULL) && (ctxt->error != NULL))
2428 ctxt->error(ctxt->userData,
2429 "Restriction %s has unexpected content\n",
2430 type->name);
2431 }
2432 ctxt->container = oldcontainer;
2433 return (type);
2434}
2435
2436/**
2437 * xmlSchemaParseExtension:
2438 * @ctxt: a schema validation context
2439 * @schema: the schema being built
2440 * @node: a subtree containing XML Schema informations
2441 *
2442 * parse a XML schema Extension definition
2443 * *WARNING* this interface is highly subject to change
2444 *
2445 * Returns the type definition or NULL in case of error
2446 */
2447static xmlSchemaTypePtr
2448xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2449 xmlNodePtr node)
2450{
2451 xmlSchemaTypePtr type, subtype;
2452 xmlNodePtr child = NULL;
2453 xmlChar name[30];
2454 xmlChar *oldcontainer;
2455
2456 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2457 return (NULL);
2458
2459 oldcontainer = ctxt->container;
2460
2461 snprintf((char *)name, 30, "extension %d", ctxt->counter++ + 1);
2462 type = xmlSchemaAddType(ctxt, schema, name);
2463 if (type == NULL)
2464 return (NULL);
2465 type->node = node;
2466 type->type = XML_SCHEMA_TYPE_EXTENSION;
2467 type->id = xmlGetProp(node, BAD_CAST "id");
2468 ctxt->container = name;
2469
2470 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2471 if (type->base == NULL) {
2472 xmlSchemaErrorContext(ctxt, schema, node, child);
2473 if ((ctxt != NULL) && (ctxt->error != NULL))
2474 ctxt->error(ctxt->userData,
2475 "Extension %s has no base\n",
2476 type->name);
2477 }
2478 child = node->children;
2479 if (IS_SCHEMA(child, "annotation")) {
2480 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2481 child = child->next;
2482 }
2483 subtype = NULL;
2484
2485 if (IS_SCHEMA(child, "all")) {
2486 subtype = xmlSchemaParseAll(ctxt, schema, child);
2487 child = child->next;
2488 } else if (IS_SCHEMA(child, "choice")) {
2489 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2490 child = child->next;
2491 } else if (IS_SCHEMA(child, "sequence")) {
2492 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2493 child = child->next;
2494 } else if (IS_SCHEMA(child, "group")) {
2495 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2496 child = child->next;
2497 }
2498 if (subtype != NULL)
2499 type->subtypes = subtype;
2500 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2501 if (child != NULL) {
2502 xmlSchemaErrorContext(ctxt, schema, node, child);
2503 if ((ctxt != NULL) && (ctxt->error != NULL))
2504 ctxt->error(ctxt->userData,
2505 "Extension %s has unexpected content\n",
2506 type->name);
2507 }
2508 ctxt->container = oldcontainer;
2509 return (type);
2510}
2511
2512/**
2513 * xmlSchemaParseSimpleContent:
2514 * @ctxt: a schema validation context
2515 * @schema: the schema being built
2516 * @node: a subtree containing XML Schema informations
2517 *
2518 * parse a XML schema SimpleContent definition
2519 * *WARNING* this interface is highly subject to change
2520 *
2521 * Returns the type definition or NULL in case of error
2522 */
2523static xmlSchemaTypePtr
2524xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2525 xmlNodePtr node)
2526{
2527 xmlSchemaTypePtr type, subtype;
2528 xmlNodePtr child = NULL;
2529 xmlChar name[30];
2530
2531 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2532 return (NULL);
2533
2534
2535 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2536 type = xmlSchemaAddType(ctxt, schema, name);
2537 if (type == NULL)
2538 return (NULL);
2539 type->node = node;
2540 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
2541 type->id = xmlGetProp(node, BAD_CAST "id");
2542
2543 child = node->children;
2544 if (IS_SCHEMA(child, "annotation")) {
2545 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2546 child = child->next;
2547 }
2548 subtype = NULL;
2549 if (IS_SCHEMA(child, "restriction")) {
2550 subtype = (xmlSchemaTypePtr)
2551 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2552 child = child->next;
2553 } else if (IS_SCHEMA(child, "extension")) {
2554 subtype = (xmlSchemaTypePtr)
2555 xmlSchemaParseExtension(ctxt, schema, child);
2556 child = child->next;
2557 }
2558 type->subtypes = subtype;
2559 if (child != NULL) {
2560 xmlSchemaErrorContext(ctxt, schema, node, child);
2561 if ((ctxt != NULL) && (ctxt->error != NULL))
2562 ctxt->error(ctxt->userData,
2563 "SimpleContent %s has unexpected content\n",
2564 type->name);
2565 }
2566 return (type);
2567}
2568
2569/**
2570 * xmlSchemaParseComplexContent:
2571 * @ctxt: a schema validation context
2572 * @schema: the schema being built
2573 * @node: a subtree containing XML Schema informations
2574 *
2575 * parse a XML schema ComplexContent definition
2576 * *WARNING* this interface is highly subject to change
2577 *
2578 * Returns the type definition or NULL in case of error
2579 */
2580static xmlSchemaTypePtr
2581xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2582 xmlNodePtr node)
2583{
2584 xmlSchemaTypePtr type, subtype;
2585 xmlNodePtr child = NULL;
2586 xmlChar name[30];
2587
2588 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2589 return (NULL);
2590
2591
2592 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2593 type = xmlSchemaAddType(ctxt, schema, name);
2594 if (type == NULL)
2595 return (NULL);
2596 type->node = node;
2597 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
2598 type->id = xmlGetProp(node, BAD_CAST "id");
2599
2600 child = node->children;
2601 if (IS_SCHEMA(child, "annotation")) {
2602 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2603 child = child->next;
2604 }
2605 subtype = NULL;
2606 if (IS_SCHEMA(child, "restriction")) {
2607 subtype = (xmlSchemaTypePtr)
2608 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2609 child = child->next;
2610 } else if (IS_SCHEMA(child, "extension")) {
2611 subtype = (xmlSchemaTypePtr)
2612 xmlSchemaParseExtension(ctxt, schema, child);
2613 child = child->next;
2614 }
2615 type->subtypes = subtype;
2616 if (child != NULL) {
2617 xmlSchemaErrorContext(ctxt, schema, node, child);
2618 if ((ctxt != NULL) && (ctxt->error != NULL))
2619 ctxt->error(ctxt->userData,
2620 "ComplexContent %s has unexpected content\n",
2621 type->name);
2622 }
2623 return (type);
2624}
2625
2626/**
2627 * xmlSchemaParseComplexType:
2628 * @ctxt: a schema validation context
2629 * @schema: the schema being built
2630 * @node: a subtree containing XML Schema informations
2631 *
2632 * parse a XML schema Complex Type definition
2633 * *WARNING* this interface is highly subject to change
2634 *
2635 * Returns the type definition or NULL in case of error
2636 */
2637static xmlSchemaTypePtr
2638xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2639 xmlNodePtr node)
2640{
2641 xmlSchemaTypePtr type, subtype;
2642 xmlNodePtr child = NULL;
2643 xmlChar *name;
2644 xmlChar *oldcontainer;
2645
2646 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2647 return (NULL);
2648
2649 oldcontainer = ctxt->container;
2650 name = xmlGetProp(node, (const xmlChar *) "name");
2651 if (name == NULL) {
2652 char buf[100];
2653
2654 snprintf(buf, 99, "anontype%d", ctxt->counter++ + 1);
2655 name = xmlStrdup((xmlChar *) buf);
2656 }
2657 if (name == NULL) {
2658 xmlSchemaErrorContext(ctxt, schema, node, child);
2659 if ((ctxt != NULL) && (ctxt->error != NULL))
2660 ctxt->error(ctxt->userData, "complexType has no name\n");
2661 return (NULL);
2662 }
2663 type = xmlSchemaAddType(ctxt, schema, name);
2664 if (type == NULL) {
2665 xmlFree(name);
2666 return (NULL);
2667 }
2668 type->node = node;
2669 type->type = XML_SCHEMA_TYPE_COMPLEX;
2670 type->id = xmlGetProp(node, BAD_CAST "id");
2671 ctxt->container = name;
2672
2673 child = node->children;
2674 if (IS_SCHEMA(child, "annotation")) {
2675 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2676 child = child->next;
2677 }
2678 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillarddecd64d2002-04-18 14:41:51 +00002679 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002680 child = child->next;
2681 } else if (IS_SCHEMA(child, "complexContent")) {
2682 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
2683 child = child->next;
2684 } else {
2685 subtype = NULL;
2686
2687 if (IS_SCHEMA(child, "all")) {
2688 subtype = xmlSchemaParseAll(ctxt, schema, child);
2689 child = child->next;
2690 } else if (IS_SCHEMA(child, "choice")) {
2691 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2692 child = child->next;
2693 } else if (IS_SCHEMA(child, "sequence")) {
2694 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2695 child = child->next;
2696 } else if (IS_SCHEMA(child, "group")) {
2697 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2698 child = child->next;
2699 }
2700 if (subtype != NULL)
2701 type->subtypes = subtype;
2702 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2703 }
2704 if (child != NULL) {
2705 xmlSchemaErrorContext(ctxt, schema, node, child);
2706 if ((ctxt != NULL) && (ctxt->error != NULL))
2707 ctxt->error(ctxt->userData,
2708 "ComplexType %s has unexpected content\n",
2709 type->name);
2710 }
2711 ctxt->container = oldcontainer;
2712 xmlFree(name);
2713 return (type);
2714}
2715
2716
2717/**
2718 * xmlSchemaParseSchema:
2719 * @ctxt: a schema validation context
2720 * @node: a subtree containing XML Schema informations
2721 *
2722 * parse a XML schema definition from a node set
2723 * *WARNING* this interface is highly subject to change
2724 *
2725 * Returns the internal XML Schema structure built from the resource or
2726 * NULL in case of error
2727 */
2728static xmlSchemaPtr
2729xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
2730{
2731 xmlSchemaPtr schema = NULL;
2732 xmlSchemaAnnotPtr annot;
2733 xmlNodePtr child = NULL;
2734 xmlChar *val;
2735
2736 if ((ctxt == NULL) || (node == NULL))
2737 return (NULL);
2738
2739 if (IS_SCHEMA(node, "schema")) {
2740 schema = xmlSchemaNewSchema(ctxt);
2741 if (schema == NULL)
2742 return(NULL);
2743 schema->targetNamespace = xmlGetProp(node, BAD_CAST "targetNamespace");
2744 schema->id = xmlGetProp(node, BAD_CAST "id");
2745 schema->version = xmlGetProp(node, BAD_CAST "version");
2746 val = xmlGetProp(node, BAD_CAST "elementFormDefault");
2747 if (val != NULL) {
2748 if (xmlStrEqual(val, BAD_CAST "qualified"))
2749 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
2750 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
2751 xmlSchemaErrorContext(ctxt, schema, node, child);
2752 if ((ctxt != NULL) && (ctxt->error != NULL)) {
2753 ctxt->error(ctxt->userData,
2754 "Invalid value %s for elementFormDefault\n",
2755 val);
2756 }
2757 }
2758 xmlFree(val);
2759 }
2760 val = xmlGetProp(node, BAD_CAST "attributeFormDefault");
2761 if (val != NULL) {
2762 if (xmlStrEqual(val, BAD_CAST "qualified"))
2763 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
2764 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
2765 xmlSchemaErrorContext(ctxt, schema, node, child);
2766 if ((ctxt != NULL) && (ctxt->error != NULL)) {
2767 ctxt->error(ctxt->userData,
2768 "Invalid value %s for elementFormDefault\n",
2769 val);
2770 }
2771 }
2772 xmlFree(val);
2773 }
2774
2775 child = node->children;
2776 while ((IS_SCHEMA(child, "include")) ||
2777 (IS_SCHEMA(child, "import")) ||
2778 (IS_SCHEMA(child, "redefine")) ||
2779 (IS_SCHEMA(child, "annotation"))) {
2780 if (IS_SCHEMA(child, "annotation")) {
2781 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2782 if (schema->annot == NULL)
2783 schema->annot = annot;
2784 else
2785 xmlSchemaFreeAnnot(annot);
2786 } else if (IS_SCHEMA(child, "include")) {
2787 TODO
2788 } else if (IS_SCHEMA(child, "import")) {
2789 TODO
2790 } else if (IS_SCHEMA(child, "redefine")) {
2791 TODO
2792 }
2793 child = child->next;
2794 }
2795 while (child != NULL) {
2796 if (IS_SCHEMA(child, "complexType")) {
2797 xmlSchemaParseComplexType(ctxt, schema, child);
2798 child = child->next;
2799 } else if (IS_SCHEMA(child, "simpleType")) {
2800 xmlSchemaParseSimpleType(ctxt, schema, child);
2801 child = child->next;
2802 } else if (IS_SCHEMA(child, "element")) {
2803 xmlSchemaParseElement(ctxt, schema, child, 1);
2804 child = child->next;
2805 } else if (IS_SCHEMA(child, "attribute")) {
2806 xmlSchemaParseAttribute(ctxt, schema, child);
2807 child = child->next;
2808 } else if (IS_SCHEMA(child, "attributeGroup")) {
2809 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2810 child = child->next;
2811 } else if (IS_SCHEMA(child, "group")) {
2812 xmlSchemaParseGroup(ctxt, schema, child);
2813 child = child->next;
2814 } else if (IS_SCHEMA(child, "notation")) {
2815 xmlSchemaParseNotation(ctxt, schema, child);
2816 child = child->next;
2817 } else {
2818 xmlSchemaErrorContext(ctxt, schema, node, child);
2819 if ((ctxt != NULL) && (ctxt->error != NULL))
2820 ctxt->error(ctxt->userData,
2821 "Schemas: unexpected element %s here \n",
2822 child->name);
2823 child = child->next;
2824 }
2825 while (IS_SCHEMA(child, "annotation")) {
2826 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2827 if (schema->annot == NULL)
2828 schema->annot = annot;
2829 else
2830 xmlSchemaFreeAnnot(annot);
2831 child = child->next;
2832 }
2833 }
2834 }
2835#ifdef DEBUG
2836 if (schema == NULL)
2837 xmlGenericError(xmlGenericErrorContext,
2838 "xmlSchemaParse() failed\n");
2839#endif
2840
2841 return (schema);
2842}
2843
2844/************************************************************************
2845 * *
2846 * Validating using Schemas *
2847 * *
2848 ************************************************************************/
2849
2850/************************************************************************
2851 * *
2852 * Reading/Writing Schemas *
2853 * *
2854 ************************************************************************/
2855
2856/**
2857 * xmlSchemaNewParserCtxt:
2858 * @URL: the location of the schema
2859 *
2860 * Create an XML Schemas parse context for that file/resource expected
2861 * to contain an XML Schemas file.
2862 *
2863 * Returns the parser context or NULL in case of error
2864 */
2865xmlSchemaParserCtxtPtr
2866xmlSchemaNewParserCtxt(const char *URL) {
2867 xmlSchemaParserCtxtPtr ret;
2868
2869 if (URL == NULL)
2870 return(NULL);
2871
2872 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
2873 if (ret == NULL) {
2874 xmlGenericError(xmlGenericErrorContext,
2875 "Failed to allocate new schama parser context for %s\n", URL);
2876 return (NULL);
2877 }
2878 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
2879 ret->URL = xmlStrdup((const xmlChar *)URL);
2880 return (ret);
2881}
2882
2883/**
2884 * xmlSchemaFreeParserCtxt:
2885 * @ctxt: the schema parser context
2886 *
2887 * Free the resources associated to the schema parser context
2888 */
2889void
2890xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) {
2891 if (ctxt == NULL)
2892 return;
2893 if (ctxt->URL != NULL)
2894 xmlFree(ctxt->URL);
2895 xmlFree(ctxt);
2896}
2897
2898/************************************************************************
2899 * *
2900 * Building the content models *
2901 * *
2902 ************************************************************************/
2903/**
2904 * xmlSchemaBuildAContentModel:
2905 * @type: the schema type definition
2906 * @ctxt: the schema parser context
2907 * @name: the element name whose content is being built
2908 *
2909 * Generate the automata sequence needed for that type
2910 */
2911static void
2912xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
2913 xmlSchemaParserCtxtPtr ctxt,
2914 const xmlChar *name) {
2915 if (type == NULL) {
2916 xmlGenericError(xmlGenericErrorContext,
2917 "Found unexpected type = NULL in %s content model\n",
2918 name);
2919 return;
2920 }
2921 switch (type->type) {
2922 case XML_SCHEMA_TYPE_ANY:
2923 /* TODO : handle the namespace too */
2924 /* TODO : make that a specific transition type */
2925 TODO
2926 ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state,
2927 NULL, BAD_CAST "*", NULL);
2928 break;
2929 case XML_SCHEMA_TYPE_ELEMENT: {
2930 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
2931 /* TODO : handle the namespace too */
2932 xmlAutomataStatePtr oldstate = ctxt->state;
2933 if (elem->maxOccurs >= UNBOUNDED) {
2934 if (elem->refDecl != NULL) {
2935 xmlSchemaBuildAContentModel(
2936 (xmlSchemaTypePtr) elem->refDecl,
2937 ctxt, elem->refDecl->name);
2938 } else {
2939 ctxt->state = xmlAutomataNewTransition(ctxt->am,
2940 ctxt->state, NULL, elem->name, type);
2941 }
2942 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2943 if (elem->minOccurs == 0) {
2944 /* basically an elem* */
2945 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2946 }
2947 } else if (elem->maxOccurs > 1) {
2948 if (elem->refDecl != NULL) {
2949 TODO
2950 xmlSchemaBuildAContentModel(
2951 (xmlSchemaTypePtr) elem->refDecl,
2952 ctxt, elem->refDecl->name);
2953 } else {
2954 ctxt->state = xmlAutomataNewCountTrans(ctxt->am,
2955 ctxt->state, NULL, elem->name,
2956 elem->minOccurs, elem->maxOccurs, type);
2957 }
2958 } else {
2959 if (elem->refDecl != NULL) {
2960 xmlSchemaBuildAContentModel(
2961 (xmlSchemaTypePtr) elem->refDecl,
2962 ctxt, elem->refDecl->name);
2963 } else {
2964 ctxt->state = xmlAutomataNewTransition(ctxt->am,
2965 ctxt->state, NULL, elem->name, type);
2966 }
2967 if (elem->minOccurs == 0) {
2968 /* basically an elem? */
2969 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2970 }
2971 }
2972 break;
2973 }
2974 case XML_SCHEMA_TYPE_SEQUENCE: {
2975 xmlSchemaTypePtr subtypes;
2976
2977 /*
2978 * Simply iterate over the subtypes
2979 */
2980 subtypes = type->subtypes;
2981 while (subtypes != NULL) {
2982 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
2983 subtypes = subtypes->next;
2984 }
2985 break;
2986 }
2987 case XML_SCHEMA_TYPE_CHOICE: {
2988 xmlSchemaTypePtr subtypes;
2989 xmlAutomataStatePtr start, end;
2990
2991 start = ctxt->state;
2992 end = xmlAutomataNewState(ctxt->am);
2993
2994 /*
2995 * iterate over the subtypes and remerge the end with an
2996 * epsilon transition
2997 */
Daniel Veillardb509f152002-04-17 16:28:10 +00002998 if (type->maxOccurs == 1) {
2999 subtypes = type->subtypes;
3000 while (subtypes != NULL) {
3001 ctxt->state = start;
3002 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3003 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3004 subtypes = subtypes->next;
3005 }
3006 } else {
3007 int counter;
3008 xmlAutomataStatePtr hop;
3009
3010 /*
3011 * use a counter to keep track of the number of transtions
3012 * which went through the choice.
3013 */
3014 if (type->minOccurs < 1) {
3015 counter = xmlAutomataNewCounter(ctxt->am, 0,
3016 type->maxOccurs - 1);
3017 } else {
3018 counter = xmlAutomataNewCounter(ctxt->am,
3019 type->minOccurs - 1, type->maxOccurs - 1);
3020 }
3021 hop = xmlAutomataNewState(ctxt->am);
3022
3023 subtypes = type->subtypes;
3024 while (subtypes != NULL) {
3025 ctxt->state = start;
3026 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3027 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3028 subtypes = subtypes->next;
3029 }
3030 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3031 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3032 }
3033 if (type->minOccurs == 0) {
3034 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003035 }
3036 ctxt->state = end;
3037 break;
3038 }
3039 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003040 xmlAutomataStatePtr end;
3041 xmlAutomataStatePtr start;
3042 xmlSchemaTypePtr subtypes;
3043 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
3044
3045 subtypes = type->subtypes;
3046 if (subtypes == NULL)
3047 break;
3048 start = ctxt->state;
3049 while (subtypes != NULL) {
3050 ctxt->state = start;
3051 elem = (xmlSchemaElementPtr) subtypes;
3052
3053 /* TODO : handle the namespace too */
3054 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3055 elem->name, elem->minOccurs, elem->maxOccurs,
3056 subtypes);
3057 subtypes = subtypes->next;
3058 }
3059 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003060 TODO
3061 break;
3062 }
3063 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003064 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003065 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3066 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003067 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003068 if (type->baseType != NULL) {
3069 xmlSchemaTypePtr subtypes;
3070
3071 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3072 subtypes = type->subtypes;
3073 while (subtypes != NULL) {
3074 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3075 subtypes = subtypes->next;
3076 }
3077 } else if (type->subtypes != NULL)
3078 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3079 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003080 case XML_SCHEMA_TYPE_GROUP:
3081 case XML_SCHEMA_TYPE_COMPLEX:
3082 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3083 if (type->subtypes != NULL)
3084 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3085 break;
3086 default:
3087 xmlGenericError(xmlGenericErrorContext,
3088 "Found unexpected type %d in %s content model\n",
3089 type->type, name);
3090 return;
3091 }
3092}
3093/**
3094 * xmlSchemaBuildContentModel:
3095 * @typeDecl: the schema type definition
3096 * @ctxt: the schema parser context
3097 *
3098 * Fixes the content model of the element.
3099 */
3100static void
3101xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3102 xmlSchemaParserCtxtPtr ctxt,
3103 const xmlChar *name) {
3104 xmlAutomataStatePtr start;
3105
Daniel Veillard4255d502002-04-16 15:50:10 +00003106 if (elem->contModel != NULL)
3107 return;
3108 if (elem->subtypes == NULL)
3109 return;
3110 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3111 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003112 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3113 return;
3114
3115#ifdef DEBUG_CONTENT
3116 xmlGenericError(xmlGenericErrorContext,
3117 "Building content model for %s\n", name);
3118#endif
3119
Daniel Veillard4255d502002-04-16 15:50:10 +00003120 ctxt->am = xmlNewAutomata();
3121 if (ctxt->am == NULL) {
3122 xmlGenericError(xmlGenericErrorContext,
3123 "Cannot create automata for elem %s\n", name);
3124 return;
3125 }
3126 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3127 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3128 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3129 elem->contModel = xmlAutomataCompile(ctxt->am);
3130#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00003131 xmlGenericError(xmlGenericErrorContext,
3132 "Content model of %s:\n", name);
3133 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003134#endif
3135 ctxt->state = NULL;
3136 xmlFreeAutomata(ctxt->am);
3137 ctxt->am = NULL;
3138}
3139
3140/**
3141 * xmlSchemaRefFixupCallback:
3142 * @elem: the schema element context
3143 * @ctxt: the schema parser context
3144 *
3145 * Free the resources associated to the schema parser context
3146 */
3147static void
3148xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3149 xmlSchemaParserCtxtPtr ctxt,
3150 const xmlChar *name,
3151 ATTRIBUTE_UNUSED const xmlChar *context,
3152 ATTRIBUTE_UNUSED const xmlChar *namespace)
3153{
3154 if ((ctxt == NULL) || (elem == NULL))
3155 return;
3156 if (elem->ref != NULL) {
3157 xmlSchemaElementPtr elemDecl;
3158
3159 if (elem->subtypes != NULL) {
3160 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3161 if ((ctxt != NULL) && (ctxt->error != NULL))
3162 ctxt->error(ctxt->userData,
3163 "Schemas: element %s have both ref and subtype\n",
3164 name);
3165 return;
3166 }
3167 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3168 elem->ref, elem->refNs);
3169
3170 if (elemDecl == NULL) {
3171 if ((ctxt != NULL) && (ctxt->error != NULL))
3172 ctxt->error(ctxt->userData,
3173 "Schemas: element %s ref to %s not found\n",
3174 name, elem->ref);
3175 return;
3176 }
3177 elem->refDecl = elemDecl;
3178 } else if (elem->namedType != NULL) {
3179 xmlSchemaTypePtr typeDecl;
3180
3181 if (elem->subtypes != NULL) {
3182 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3183 if ((ctxt != NULL) && (ctxt->error != NULL))
3184 ctxt->error(ctxt->userData,
3185 "Schemas: element %s have both type and subtype\n",
3186 name);
3187 return;
3188 }
3189 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3190 elem->namedTypeNs);
3191
3192 if (typeDecl == NULL) {
3193 if ((ctxt != NULL) && (ctxt->error != NULL))
3194 ctxt->error(ctxt->userData,
3195 "Schemas: element %s type %s not found\n",
3196 name, elem->namedType);
3197 return;
3198 }
3199 elem->subtypes = typeDecl;
3200 }
3201}
3202
3203/**
3204 * xmlSchemaTypeFixup:
3205 * @typeDecl: the schema type definition
3206 * @ctxt: the schema parser context
3207 *
3208 * Fixes the content model of the type.
3209 */
3210static void
3211xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3212 xmlSchemaParserCtxtPtr ctxt,
3213 const xmlChar *name)
3214{
3215 if (name == NULL)
3216 name = typeDecl->name;
3217 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3218 switch (typeDecl->type) {
3219 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3220 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3221 typeDecl->contentType = typeDecl->subtypes->contentType;
3222 break;
3223 }
3224 case XML_SCHEMA_TYPE_RESTRICTION: {
3225 if (typeDecl->subtypes != NULL)
3226 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3227
3228 if (typeDecl->base != NULL) {
3229 xmlSchemaTypePtr baseType;
3230
3231 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3232 typeDecl->baseNs);
3233 if (baseType == NULL) {
3234 if ((ctxt != NULL) && (ctxt->error != NULL))
3235 ctxt->error(ctxt->userData,
3236 "Schemas: type %s base type %s not found\n",
3237 name, typeDecl->base);
3238 }
3239 typeDecl->baseType = baseType;
3240 }
3241 if (typeDecl->subtypes == NULL)
3242 /* 1.1.1 */
3243 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3244 else if ((typeDecl->subtypes->subtypes == NULL) &&
3245 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3246 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3247 /* 1.1.2 */
3248 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3249 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3250 (typeDecl->subtypes->subtypes == NULL))
3251 /* 1.1.3 */
3252 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3253 else {
3254 /* 1.2 and 2.X are applied at the other layer */
3255 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3256 }
3257 break;
3258 }
3259 case XML_SCHEMA_TYPE_EXTENSION: {
3260 xmlSchemaContentType explicitContentType;
3261 xmlSchemaTypePtr base;
3262
3263 if (typeDecl->base != NULL) {
3264 xmlSchemaTypePtr baseType;
3265
3266 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3267 typeDecl->baseNs);
3268 if (baseType == NULL) {
3269 if ((ctxt != NULL) && (ctxt->error != NULL))
3270 ctxt->error(ctxt->userData,
3271 "Schemas: type %s base type %s not found\n",
3272 name, typeDecl->base);
3273 }
3274 typeDecl->baseType = baseType;
3275 }
3276 if (typeDecl->subtypes != NULL)
3277 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3278
Daniel Veillard8651f532002-04-17 09:06:27 +00003279 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003280 if (typeDecl->subtypes == NULL)
3281 /* 1.1.1 */
3282 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3283 else if ((typeDecl->subtypes->subtypes == NULL) &&
3284 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3285 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3286 /* 1.1.2 */
3287 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3288 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3289 (typeDecl->subtypes->subtypes == NULL))
3290 /* 1.1.3 */
3291 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3292
3293 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3294 typeDecl->baseNs);
3295 if (base == NULL) {
3296 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3297 if ((ctxt != NULL) && (ctxt->error != NULL))
3298 ctxt->error(ctxt->userData,
3299 "Schemas: base type %s of type %s not found\n",
3300 typeDecl->base, name);
3301 return;
3302 }
3303 xmlSchemaTypeFixup(base, ctxt, NULL);
3304 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3305 /* 2.1 */
3306 typeDecl->contentType = base->contentType;
3307 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3308 /* 2.2 imbitable ! */
3309 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3310 } else {
3311 /* 2.3 imbitable pareil ! */
3312 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3313 }
3314 break;
3315 }
3316 case XML_SCHEMA_TYPE_COMPLEX: {
3317 if (typeDecl->subtypes == NULL) {
3318 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3319 } else {
3320 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3321 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3322 else {
3323 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3324 typeDecl->contentType = typeDecl->subtypes->contentType;
3325 }
3326 }
3327 break;
3328 }
3329 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3330 if (typeDecl->subtypes == NULL) {
3331 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3332 } else {
3333 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3334 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3335 else {
3336 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3337 typeDecl->contentType = typeDecl->subtypes->contentType;
3338 }
3339 }
3340 break;
3341 }
3342 case XML_SCHEMA_TYPE_SEQUENCE:
3343 case XML_SCHEMA_TYPE_GROUP:
3344 case XML_SCHEMA_TYPE_ALL:
3345 case XML_SCHEMA_TYPE_CHOICE:
3346 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3347 break;
3348 case XML_SCHEMA_TYPE_BASIC:
3349 case XML_SCHEMA_TYPE_ANY:
3350 case XML_SCHEMA_TYPE_FACET:
3351 case XML_SCHEMA_TYPE_SIMPLE:
3352 case XML_SCHEMA_TYPE_UR:
3353 case XML_SCHEMA_TYPE_ELEMENT:
3354 case XML_SCHEMA_TYPE_ATTRIBUTE:
3355 case XML_SCHEMA_TYPE_NOTATION:
3356 case XML_SCHEMA_TYPE_LIST:
3357 case XML_SCHEMA_TYPE_UNION:
3358 case XML_SCHEMA_FACET_MININCLUSIVE:
3359 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3360 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3361 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3362 case XML_SCHEMA_FACET_TOTALDIGITS:
3363 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3364 case XML_SCHEMA_FACET_PATTERN:
3365 case XML_SCHEMA_FACET_ENUMERATION:
3366 case XML_SCHEMA_FACET_WHITESPACE:
3367 case XML_SCHEMA_FACET_LENGTH:
3368 case XML_SCHEMA_FACET_MAXLENGTH:
3369 case XML_SCHEMA_FACET_MINLENGTH:
3370 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3371 break;
3372 }
3373 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003374#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003375 if (typeDecl->node != NULL) {
3376 xmlGenericError(xmlGenericErrorContext,
3377 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3378 xmlGetLineNo(typeDecl->node));
3379 } else {
3380 xmlGenericError(xmlGenericErrorContext,
3381 "Type of %s :", name);
3382 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003383 switch (typeDecl->contentType) {
3384 case XML_SCHEMA_CONTENT_SIMPLE:
3385 xmlGenericError(xmlGenericErrorContext,
3386 "simple\n"); break;
3387 case XML_SCHEMA_CONTENT_ELEMENTS:
3388 xmlGenericError(xmlGenericErrorContext,
3389 "elements\n"); break;
3390 case XML_SCHEMA_CONTENT_UNKNOWN:
3391 xmlGenericError(xmlGenericErrorContext,
3392 "unknown !!!\n"); break;
3393 case XML_SCHEMA_CONTENT_EMPTY:
3394 xmlGenericError(xmlGenericErrorContext,
3395 "empty\n"); break;
3396 case XML_SCHEMA_CONTENT_MIXED:
3397 xmlGenericError(xmlGenericErrorContext,
3398 "mixed\n"); break;
3399 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3400 xmlGenericError(xmlGenericErrorContext,
3401 "mixed or elems\n"); break;
3402 case XML_SCHEMA_CONTENT_BASIC:
3403 xmlGenericError(xmlGenericErrorContext,
3404 "basic\n"); break;
3405 default:
3406 xmlGenericError(xmlGenericErrorContext,
3407 "not registered !!!\n"); break;
3408 }
3409#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003410}
3411
3412/**
3413 * xmlSchemaCheckDefaults:
3414 * @typeDecl: the schema type definition
3415 * @ctxt: the schema parser context
3416 *
3417 * Checks the default values types, especially for facets
3418 */
3419static void
3420xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
3421 xmlSchemaParserCtxtPtr ctxt,
3422 const xmlChar *name)
3423{
3424 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3425 if (name == NULL)
3426 name = typeDecl->name;
3427 if (nonNegativeIntegerType == NULL) {
3428 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3429 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3430 }
3431 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
3432 if (typeDecl->facets != NULL) {
3433 xmlSchemaFacetPtr facet = typeDecl->facets;
3434 while (facet != NULL) {
3435 switch (facet->type) {
3436 case XML_SCHEMA_FACET_MININCLUSIVE:
3437 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3438 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3439 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3440 /*
3441 * Okay we need to validate the value
3442 * at that point.
3443 */
3444 xmlSchemaValidCtxtPtr vctxt;
3445
3446 vctxt = xmlSchemaNewValidCtxt(NULL);
3447 if (vctxt == NULL)
3448 break;
3449 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3450 facet->value);
3451 facet->val = vctxt->value;
3452 vctxt->value = NULL;
3453 if (facet->val == NULL) {
3454 /* error code */
3455 xmlSchemaErrorContext(ctxt, NULL,
3456 facet->node, NULL);
3457 ctxt->error(ctxt->userData,
3458 "Schemas: type %s facet value %s invalid\n",
3459 name, facet->value);
3460 }
3461 xmlSchemaFreeValidCtxt(vctxt);
3462 break;
3463 }
3464 case XML_SCHEMA_FACET_ENUMERATION: {
3465 /*
3466 * Okay we need to validate the value
3467 * at that point.
3468 */
3469 xmlSchemaValidCtxtPtr vctxt;
3470 int ret;
3471
3472 vctxt = xmlSchemaNewValidCtxt(NULL);
3473 if (vctxt == NULL)
3474 break;
3475 ret = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3476 facet->value);
3477 if (ret != 0) {
3478 xmlSchemaErrorContext(ctxt, NULL,
3479 facet->node, NULL);
3480 ctxt->error(ctxt->userData,
3481 "Schemas: type %s enumeration value %s invalid\n",
3482 name, facet->value);
3483 }
3484 xmlSchemaFreeValidCtxt(vctxt);
3485 break;
3486 }
3487 case XML_SCHEMA_FACET_PATTERN:
3488 facet->regexp = xmlRegexpCompile(facet->value);
3489 if (facet->regexp == NULL) {
3490 /* error code */
3491 ctxt->error(ctxt->userData,
3492 "Schemas: type %s facet regexp %s invalid\n",
3493 name, facet->value);
3494 }
3495 break;
3496 case XML_SCHEMA_FACET_TOTALDIGITS:
3497 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3498 case XML_SCHEMA_FACET_LENGTH:
3499 case XML_SCHEMA_FACET_MAXLENGTH:
3500 case XML_SCHEMA_FACET_MINLENGTH: {
3501 int ret;
3502
3503 ret = xmlSchemaValidatePredefinedType(
3504 nonNegativeIntegerType, facet->value,
3505 &facet->val);
3506 if (ret != 0) {
3507 /* error code */
3508 xmlSchemaErrorContext(ctxt, NULL,
3509 facet->node, NULL);
3510 ctxt->error(ctxt->userData,
3511 "Schemas: type %s facet value %s invalid\n",
3512 name, facet->value);
3513 }
3514 break;
3515 }
3516 case XML_SCHEMA_FACET_WHITESPACE: {
3517 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
3518 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
3519 } else if (xmlStrEqual(facet->value,
3520 BAD_CAST"replace")) {
3521 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
3522 } else if (xmlStrEqual(facet->value,
3523 BAD_CAST"collapse")) {
3524 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
3525 } else {
3526 xmlSchemaErrorContext(ctxt, NULL,
3527 facet->node, NULL);
3528 ctxt->error(ctxt->userData,
3529 "Schemas: type %s whiteSpace value %s invalid\n",
3530 name, facet->value);
3531 }
3532 }
3533 default:
3534 break;
3535 }
3536 facet = facet->next;
3537 }
3538 }
3539 }
3540}
3541
3542/**
3543 * xmlSchemaAttrFixup:
3544 * @attrDecl: the schema attribute definition
3545 * @ctxt: the schema parser context
3546 * @name: the attribute name
3547 *
3548 * Fixes finish doing the computations on the attributes definitions
3549 */
3550static void
3551xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
3552 xmlSchemaParserCtxtPtr ctxt,
3553 const xmlChar *name)
3554{
3555 if (name == NULL)
3556 name = attrDecl->name;
3557 if (attrDecl->subtypes != NULL)
3558 return;
3559 if (attrDecl->typeName != NULL) {
3560 xmlSchemaTypePtr type;
3561
3562 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
3563 attrDecl->typeNs);
3564 if (type == NULL) {
3565 if ((ctxt != NULL) && (ctxt->error != NULL))
3566 ctxt->error(ctxt->userData,
3567 "Schemas: attribute %s type %s not found\n",
3568 name, attrDecl->typeName);
3569 }
3570 attrDecl->subtypes = type;
3571 } else if (attrDecl->ref != NULL) {
3572 xmlSchemaAttributePtr ref;
3573
3574 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
3575 attrDecl->refNs);
3576 if (ref == NULL) {
3577 if ((ctxt != NULL) && (ctxt->error != NULL))
3578 ctxt->error(ctxt->userData,
3579 "Schemas: attribute %s reference %s not found\n",
3580 name, attrDecl->ref);
3581 return;
3582 }
3583 xmlSchemaAttrFixup(ref, ctxt, NULL);
3584 attrDecl->subtypes = ref->subtypes;
3585 } else {
3586 if ((ctxt != NULL) && (ctxt->error != NULL))
3587 ctxt->error(ctxt->userData,
3588 "Schemas: attribute %s has no type nor reference\n",
3589 name);
3590 }
3591}
3592
3593/**
3594 * xmlSchemaParse:
3595 * @ctxt: a schema validation context
3596 * @URL: the location of the schema
3597 *
3598 * Load, XML parse a schema definition resource and build an internal
3599 * XML Shema struture which can be used to validate instances.
3600 * *WARNING* this interface is highly subject to change
3601 *
3602 * Returns the internal XML Schema structure built from the resource or
3603 * NULL in case of error
3604 */
3605xmlSchemaPtr
3606xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
3607{
3608 xmlSchemaPtr ret = NULL;
3609 xmlDocPtr doc;
3610 xmlNodePtr root, cur, delete;
3611
3612 xmlSchemaInitTypes();
3613
3614 if ((ctxt == NULL) || (ctxt->URL == NULL))
3615 return (NULL);
3616
3617 ctxt->counter = 0;
3618 ctxt->container = NULL;
3619
3620 /*
3621 * First step is to parse the input document into an DOM/Infoset
3622 */
3623 doc = xmlParseFile((const char *) ctxt->URL);
3624 if (doc == NULL) {
3625 if (ctxt->error != NULL)
3626 ctxt->error(ctxt->userData,
3627 "xmlSchemaParse: could not load %s\n", ctxt->URL);
3628 return (NULL);
3629 }
3630
3631 /*
3632 * Then extract the root and Schema parse it
3633 */
3634 root = xmlDocGetRootElement(doc);
3635 if (root == NULL) {
3636 if (ctxt->error != NULL)
3637 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
3638 ctxt->URL);
3639 return (NULL);
3640 }
3641
3642 /*
3643 * Remove all the blank text nodes
3644 */
3645 delete = NULL;
3646 cur = root;
3647 while (cur != NULL) {
3648 if (delete != NULL) {
3649 xmlUnlinkNode(delete);
3650 xmlFreeNode(delete);
3651 delete = NULL;
3652 }
3653 if (cur->type == XML_TEXT_NODE) {
3654 if (IS_BLANK_NODE(cur)) {
3655 if (xmlNodeGetSpacePreserve(cur) != 1) {
3656 delete = cur;
3657 }
3658 }
3659 } else if ((cur->type != XML_ELEMENT_NODE) &&
3660 (cur->type != XML_CDATA_SECTION_NODE)) {
3661 delete = cur;
3662 goto skip_children;
3663 }
3664
3665 /*
3666 * Skip to next node
3667 */
3668 if (cur->children != NULL) {
3669 if ((cur->children->type != XML_ENTITY_DECL) &&
3670 (cur->children->type != XML_ENTITY_REF_NODE) &&
3671 (cur->children->type != XML_ENTITY_NODE)) {
3672 cur = cur->children;
3673 continue;
3674 }
3675 }
3676skip_children:
3677 if (cur->next != NULL) {
3678 cur = cur->next;
3679 continue;
3680 }
3681
3682 do {
3683 cur = cur->parent;
3684 if (cur == NULL)
3685 break;
3686 if (cur == root) {
3687 cur = NULL;
3688 break;
3689 }
3690 if (cur->next != NULL) {
3691 cur = cur->next;
3692 break;
3693 }
3694 } while (cur != NULL);
3695 }
3696 if (delete != NULL) {
3697 xmlUnlinkNode(delete);
3698 xmlFreeNode(delete);
3699 delete = NULL;
3700 }
3701
3702 /*
3703 * Then do the parsing for good
3704 */
3705 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00003706 if (ret == NULL)
3707 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003708 ret->doc = doc;
3709
3710 /*
3711 * Then fix all the references.
3712 */
3713 ctxt->schema = ret;
3714 xmlHashScanFull(ret->elemDecl,
3715 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
3716
3717 /*
3718 * Then fixup all types properties
3719 */
3720 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
3721
3722 /*
3723 * Then build the content model for all elements
3724 */
3725 xmlHashScan(ret->elemDecl,
3726 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
3727
3728 /*
3729 * Then check the defaults part of the type like facets values
3730 */
3731 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
3732
3733 /*
3734 * Then fixup all attributes declarations
3735 */
3736 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
3737
3738 return (ret);
3739}
3740
3741/**
3742 * xmlSchemaParse:
3743 * @ctxt: a schema validation context
3744 * @URL: the location of the schema
3745 *
3746 * Load, XML parse a schema definition resource and build an internal
3747 * XML Shema struture which can be used to validate instances.
3748 * *WARNING* this interface is highly subject to change
3749 *
3750 * Returns the internal XML Schema structure built from the resource or
3751 * NULL in case of error
3752 */
3753void
3754xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
3755 xmlSchemaValidityErrorFunc err,
3756 xmlSchemaValidityWarningFunc warn, void *ctx) {
3757 if (ctxt == NULL)
3758 return;
3759 ctxt->error = err;
3760 ctxt->warning = warn;
3761 ctxt->userData = ctx;
3762}
3763
3764/************************************************************************
3765 * *
3766 * Simple type validation *
3767 * *
3768 ************************************************************************/
3769
3770/**
3771 * xmlSchemaValidateSimpleValue:
3772 * @ctxt: a schema validation context
3773 * @type: the type declaration
3774 * @value: the value to validate
3775 *
3776 * Validate a value against a simple type
3777 *
3778 * Returns 0 if the value is valid, a positive error code
3779 * number otherwise and -1 in case of internal or API error.
3780 */
3781static int
3782xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
3783 xmlSchemaTypePtr type,
3784 xmlChar *value) {
3785 int ret = 0;
3786 /*
3787 * First normalize the value accordingly to Schema Datatype
3788 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
3789 */
3790 /*
3791 * Then check the normalized value against the lexical space of the
3792 * type.
3793 */
3794 if (type->type == XML_SCHEMA_TYPE_BASIC) {
3795 if (ctxt->value != NULL) {
3796 xmlSchemaFreeValue(ctxt->value);
3797 ctxt->value = NULL;
3798 }
3799 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
3800 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
3801 xmlSchemaTypePtr base;
3802 xmlSchemaFacetPtr facet;
3803 int tmp;
3804
3805 base = type->baseType;
3806 if (base != NULL) {
3807 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
3808 } else if (type->subtypes != NULL) {
3809
3810 }
3811 /*
3812 * Do not validate facets when working on building the Schemas
3813 */
3814 if (ctxt->schema != NULL) {
3815 if (ret == 0) {
3816 facet = type->facets;
3817 while (facet != NULL) {
3818 tmp = xmlSchemaValidateFacet(base, facet, value,
3819 ctxt->value);
3820 if (tmp != 0)
3821 ret = tmp;
3822 facet = facet->next;
3823 }
3824 }
3825 }
3826 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
3827 xmlSchemaTypePtr base;
3828
3829 base = type->subtypes;
3830 if (base != NULL) {
3831 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
3832 } else {
3833 TODO
3834 }
3835 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
3836 xmlSchemaTypePtr base;
3837 xmlChar *cur, *end, tmp;
3838 int ret2;
3839
3840 base = type->subtypes;
3841 if (base == NULL) {
3842 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
3843 if (ctxt->error != NULL) {
3844 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
3845 ctxt->error(ctxt->userData,
3846 "Internal: List type %s has no base type\n",
3847 type->name);
3848 }
3849 return(-1);
3850 }
3851 cur = value;
3852 do {
3853 while (IS_BLANK(*cur)) cur++;
3854 end = cur;
3855 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
3856 if (end == cur)
3857 break;
3858 tmp = *end;
3859 *end = 0;
3860 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
3861 if (ret2 != 0)
3862 ret = 1;
3863 *end = tmp;
3864 cur = end;
3865 } while (*cur != 0);
3866 } else {
3867 TODO
3868 }
3869 return(ret);
3870}
3871
3872/************************************************************************
3873 * *
3874 * DOM Validation code *
3875 * *
3876 ************************************************************************/
3877
3878static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
3879 xmlNodePtr node);
3880static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
3881 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
3882static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
3883 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
3884
3885/**
3886 * xmlSchemaRegisterAttributes:
3887 * @ctxt: a schema validation context
3888 * @attrs: a list of attributes
3889 *
3890 * Register the list of attributes as the set to be validated on that element
3891 *
3892 * Returns -1 in case of error, 0 otherwise
3893 */
3894static int
3895xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
3896 xmlAttrPtr attrs) {
3897 while (attrs != NULL) {
3898 if (ctxt->attrNr >= ctxt->attrMax) {
3899 xmlSchemaAttrStatePtr tmp;
3900
3901 ctxt->attrMax *= 2;
3902 tmp = (xmlSchemaAttrStatePtr)
3903 xmlRealloc(ctxt->attr, ctxt->attrMax *
3904 sizeof(xmlSchemaAttrState));
3905 if (tmp == NULL) {
3906 ctxt->attrMax /= 2;
3907 return(-1);
3908 }
3909 ctxt->attr = tmp;
3910 }
3911 ctxt->attr[ctxt->attrNr].attr = attrs;
3912 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
3913 ctxt->attrNr++;
3914 attrs = attrs->next;
3915 }
3916 return(0);
3917}
3918
3919/**
3920 * xmlSchemaCheckAttributes:
3921 * @ctxt: a schema validation context
3922 * @node: the node carrying it.
3923 *
3924 * Check that the registered set of attributes on the current node
3925 * has been properly validated.
3926 *
3927 * Returns 0 if validity constraints are met, 1 otherwise.
3928 */
3929static int
3930xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
3931 int ret = 0;
3932 int i;
3933
3934 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
3935 if (ctxt->attr[i].attr == NULL)
3936 break;
3937 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
3938 ret = 1;
3939 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
3940 if (ctxt->error != NULL)
3941 ctxt->error(ctxt->userData,
3942 "Attribute %s on %s is unknown\n",
3943 ctxt->attr[i].attr->name,
3944 node->name);
3945 }
3946 }
3947 return(ret);
3948}
3949
3950/**
3951 * xmlSchemaValidateSimpleContent:
3952 * @ctxt: a schema validation context
3953 * @elem: an element
3954 * @type: the type declaration
3955 *
3956 * Validate the content of an element expected to be a simple type
3957 *
3958 * Returns 0 if the element is schemas valid, a positive error code
3959 * number otherwise and -1 in case of internal or API error.
3960 */
3961static int
3962xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
3963 ATTRIBUTE_UNUSED xmlNodePtr node) {
3964 xmlNodePtr child;
3965 xmlSchemaTypePtr type, base;
3966 xmlChar *value;
3967 int ret = 0, tmp;
3968
3969 child = ctxt->node;
3970 type = ctxt->type;
3971
3972 /*
3973 * Validation Rule: Element Locally Valid (Type): 3.1.3
3974 */
3975 value = xmlNodeGetContent(child);
3976 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
3977 switch (type->type) {
3978 case XML_SCHEMA_TYPE_RESTRICTION: {
3979 xmlSchemaFacetPtr facet;
3980
3981 base = type->baseType;
3982 if (base != NULL) {
3983 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
3984 } else {
3985 TODO
3986 }
3987 if (ret == 0) {
3988 facet = type->facets;
3989 while (facet != NULL) {
3990 tmp = xmlSchemaValidateFacet(base, facet, value,
3991 ctxt->value);
3992 if (tmp != 0)
3993 ret = tmp;
3994 facet = facet->next;
3995 }
3996 }
3997 break;
3998 }
3999 default:
4000 TODO
4001 }
4002 if (value != NULL)
4003 xmlFree(value);
4004
4005 return(ret);
4006}
4007
4008/**
4009 * xmlSchemaValidateCheckNodeList
4010 * @nodelist: the list of nodes
4011 *
4012 * Check the node list is only made of text nodes and entities pointing
4013 * to text nodes
4014 *
4015 * Returns 1 if true, 0 if false and -1 in case of error
4016 */
4017static int
4018xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4019 while (nodelist != NULL) {
4020 if (nodelist->type == XML_ENTITY_REF_NODE) {
4021 TODO /* implement recursion in the entity content */
4022 }
4023 if ((nodelist->type != XML_TEXT_NODE) &&
4024 (nodelist->type != XML_COMMENT_NODE) &&
4025 (nodelist->type != XML_PI_NODE) &&
4026 (nodelist->type != XML_PI_NODE)) {
4027 return(0);
4028 }
4029 nodelist = nodelist->next;
4030 }
4031 return(1);
4032}
4033
4034/**
4035 * xmlSchemaSkipIgnored:
4036 * @ctxt: a schema validation context
4037 * @type: the current type context
4038 * @node: the top node.
4039 *
4040 * Skip ignorable nodes in that context
4041 *
4042 * Returns the new sibling
4043 * number otherwise and -1 in case of internal or API error.
4044 */
4045static xmlNodePtr
4046xmlSchemaSkipIgnored(ATTRIBUTE_UNUSED xmlSchemaValidCtxtPtr ctxt,
4047 xmlSchemaTypePtr type,
4048 xmlNodePtr node) {
4049 int mixed = 0;
4050 /*
4051 * TODO complete and handle entities
4052 */
4053 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4054 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4055 while ((node != NULL) &&
4056 ((node->type == XML_COMMENT_NODE) ||
4057 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4058 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4059 (node->type == XML_TEXT_NODE) &&
4060 (IS_BLANK_NODE(node)))))) {
4061 node = node->next;
4062 }
4063 return(node);
4064}
4065
4066/**
4067 * xmlSchemaValidateCallback:
4068 * @ctxt: a schema validation context
4069 * @name: the name of the element detected (might be NULL)
4070 * @type: the type
4071 *
4072 * A transition has been made in the automata associated to an element
4073 * content model
4074 */
4075static void
4076xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
4077 ATTRIBUTE_UNUSED const xmlChar *name,
4078 xmlSchemaTypePtr type,
4079 xmlNodePtr node) {
4080 xmlSchemaTypePtr oldtype = ctxt->type;
4081 xmlNodePtr oldnode = ctxt->node;
4082#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004083 xmlGenericError(xmlGenericErrorContext,
4084 "xmlSchemaValidateCallback: %s, %s, %s\n",
4085 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004086#endif
4087 ctxt->type = type;
4088 ctxt->node = node;
4089 xmlSchemaValidateContent(ctxt, node);
4090 ctxt->type = oldtype;
4091 ctxt->node = oldnode;
4092}
4093
4094
4095#if 0
4096/**
4097 * xmlSchemaValidateSimpleRestrictionType:
4098 * @ctxt: a schema validation context
4099 * @node: the top node.
4100 *
4101 * Validate the content of a restriction type.
4102 *
4103 * Returns 0 if the element is schemas valid, a positive error code
4104 * number otherwise and -1 in case of internal or API error.
4105 */
4106static int
4107xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4108 xmlNodePtr node)
4109{
4110 xmlNodePtr child;
4111 xmlSchemaTypePtr type;
4112 int ret;
4113
4114 child = ctxt->node;
4115 type = ctxt->type;
4116
4117 if ((ctxt == NULL) || (type == NULL)) {
4118 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4119 if (ctxt->error != NULL)
4120 ctxt->error(ctxt->userData,
4121 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4122 node->name);
4123 return (-1);
4124 }
4125 /*
4126 * Only text and text based entities references shall be found there
4127 */
4128 ret = xmlSchemaValidateCheckNodeList(child);
4129 if (ret < 0) {
4130 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4131 if (ctxt->error != NULL)
4132 ctxt->error(ctxt->userData,
4133 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4134 node->name);
4135 return (-1);
4136 } else if (ret == 0) {
4137 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4138 if (ctxt->error != NULL)
4139 ctxt->error(ctxt->userData,
4140 "Element %s content is not a simple type\n",
4141 node->name);
4142 return (-1);
4143 }
4144 ctxt->type = type->subtypes;
4145 xmlSchemaValidateContent(ctxt, node);
4146 ctxt->type = type;
4147 return (ret);
4148}
4149#endif
4150
4151/**
4152 * xmlSchemaValidateSimpleType:
4153 * @ctxt: a schema validation context
4154 * @node: the top node.
4155 *
4156 * Validate the content of an simple type.
4157 *
4158 * Returns 0 if the element is schemas valid, a positive error code
4159 * number otherwise and -1 in case of internal or API error.
4160 */
4161static int
4162xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4163 xmlNodePtr child;
4164 xmlSchemaTypePtr type;
4165 xmlAttrPtr attr;
4166 int ret;
4167
4168 child = ctxt->node;
4169 type = ctxt->type;
4170
4171 if ((ctxt == NULL) || (type == NULL)) {
4172 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4173 if (ctxt->error != NULL)
4174 ctxt->error(ctxt->userData,
4175 "Internal error: xmlSchemaValidateSimpleType %s\n",
4176 node->name);
4177 return(-1);
4178 }
4179 /*
4180 * Only text and text based entities references shall be found there
4181 */
4182 ret = xmlSchemaValidateCheckNodeList(child);
4183 if (ret < 0) {
4184 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4185 if (ctxt->error != NULL)
4186 ctxt->error(ctxt->userData,
4187 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4188 node->name);
4189 return(-1);
4190 } else if (ret == 0) {
4191 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4192 if (ctxt->error != NULL)
4193 ctxt->error(ctxt->userData,
4194 "Element %s content is not a simple type\n",
4195 node->name);
4196 return(-1);
4197 }
4198 /*
4199 * Validation Rule: Element Locally Valid (Type): 3.1.1
4200 */
4201 attr = node->properties;
4202 while (attr != NULL) {
4203 if ((attr->ns == NULL) ||
4204 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4205 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4206 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4207 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4208 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4209 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4210 if (ctxt->error != NULL)
4211 ctxt->error(ctxt->userData,
4212 "Element %s: attribute %s should not be present\n",
4213 child->name, attr->name);
4214 return(ctxt->err);
4215 }
4216 }
4217
4218 ctxt->type = type->subtypes;
4219 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4220 ctxt->type = type;
4221 return(ret);
4222}
4223
4224/**
4225 * xmlSchemaValidateElementType:
4226 * @ctxt: a schema validation context
4227 * @node: the top node.
4228 *
4229 * Validate the content of an element type.
4230 * Validation Rule: Element Locally Valid (Complex Type)
4231 *
4232 * Returns 0 if the element is schemas valid, a positive error code
4233 * number otherwise and -1 in case of internal or API error.
4234 */
4235static int
4236xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4237 xmlNodePtr child;
4238 xmlSchemaTypePtr type;
4239 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4240 xmlSchemaElementPtr decl;
4241 int ret, attrBase;
4242
4243 oldregexp = ctxt->regexp;
4244
4245 child = ctxt->node;
4246 type = ctxt->type;
4247
4248 if ((ctxt == NULL) || (type == NULL)) {
4249 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4250 if (ctxt->error != NULL)
4251 ctxt->error(ctxt->userData,
4252 "Internal error: xmlSchemaValidateElementType\n",
4253 node->name);
4254 return(-1);
4255 }
4256 if (child == NULL) {
4257 if (type->minOccurs > 0) {
4258 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4259 if (ctxt->error != NULL)
4260 ctxt->error(ctxt->userData,
4261 "Element %s: missing child %s\n",
4262 node->name, type->name);
4263 }
4264 return(ctxt->err);
4265 }
4266
4267 /*
4268 * Verify the element matches
4269 */
4270 if (!xmlStrEqual(child->name, type->name)) {
4271 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4272 if (ctxt->error != NULL)
4273 ctxt->error(ctxt->userData,
4274 "Element %s: missing child %s found %s\n",
4275 node->name, type->name, child->name);
4276 return(ctxt->err);
4277 }
4278 /*
4279 * Verify the attributes
4280 */
4281 attrBase = ctxt->attrBase;
4282 ctxt->attrBase = ctxt->attrNr;
4283 xmlSchemaRegisterAttributes(ctxt, child->properties);
4284 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4285 /*
4286 * Verify the element content recursively
4287 */
4288 decl = (xmlSchemaElementPtr) type;
4289 oldregexp = ctxt->regexp;
4290 if (decl->contModel != NULL) {
4291 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4292 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4293 ctxt);
4294#ifdef DEBUG_AUTOMATA
4295 xmlGenericError(xmlGenericErrorContext,
4296 "====> %s\n", node->name);
4297#endif
4298 }
4299 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4300 type->subtypes);
4301
4302 if (decl->contModel != NULL) {
4303 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4304#ifdef DEBUG_AUTOMATA
4305 xmlGenericError(xmlGenericErrorContext,
4306 "====> %s : %d\n", node->name, ret);
4307#endif
4308 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004309 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004310 if (ctxt->error != NULL)
4311 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4312 node->name);
4313 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004314 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004315 if (ctxt->error != NULL)
4316 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4317 node->name);
4318#ifdef DEBUG_CONTENT
4319 } else {
4320 xmlGenericError(xmlGenericErrorContext,
4321 "Element %s content check succeeded\n", node->name);
4322
4323#endif
4324 }
4325 xmlRegFreeExecCtxt(ctxt->regexp);
4326 }
4327 /*
4328 * Verify that all attributes were Schemas-validated
4329 */
4330 xmlSchemaCheckAttributes(ctxt, node);
4331 ctxt->attrNr = ctxt->attrBase;
4332 ctxt->attrBase = attrBase;
4333
4334 ctxt->regexp = oldregexp;
4335
4336 ctxt->node = child;
4337 ctxt->type = type;
4338 return(ctxt->err);
4339}
4340
4341/**
4342 * xmlSchemaValidateBasicType:
4343 * @ctxt: a schema validation context
4344 * @node: the top node.
4345 *
4346 * Validate the content of an element expected to be a basic type type
4347 *
4348 * Returns 0 if the element is schemas valid, a positive error code
4349 * number otherwise and -1 in case of internal or API error.
4350 */
4351static int
4352xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4353 int ret;
4354 xmlNodePtr child, cur;
4355 xmlSchemaTypePtr type;
4356 xmlChar *value; /* lexical representation */
4357
4358 child = ctxt->node;
4359 type = ctxt->type;
4360
4361 if ((ctxt == NULL) || (type == NULL)) {
4362 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4363 if (ctxt->error != NULL)
4364 ctxt->error(ctxt->userData,
4365 "Internal error: xmlSchemaValidateBasicType\n",
4366 node->name);
4367 return(-1);
4368 }
4369 /*
4370 * First check the content model of the node.
4371 */
4372 cur = child;
4373 while (cur != NULL) {
4374 switch (cur->type) {
4375 case XML_TEXT_NODE:
4376 case XML_CDATA_SECTION_NODE:
4377 case XML_PI_NODE:
4378 case XML_COMMENT_NODE:
4379 case XML_XINCLUDE_START:
4380 case XML_XINCLUDE_END:
4381 break;
4382 case XML_ENTITY_REF_NODE:
4383 case XML_ENTITY_NODE:
4384 TODO
4385 break;
4386 case XML_ELEMENT_NODE:
4387 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4388 if (ctxt->error != NULL)
4389 ctxt->error(ctxt->userData,
4390 "Element %s: child %s should not be present\n",
4391 node->name, cur->name);
4392 return(ctxt->err);
4393 case XML_ATTRIBUTE_NODE:
4394 case XML_DOCUMENT_NODE:
4395 case XML_DOCUMENT_TYPE_NODE:
4396 case XML_DOCUMENT_FRAG_NODE:
4397 case XML_NOTATION_NODE:
4398 case XML_HTML_DOCUMENT_NODE:
4399 case XML_DTD_NODE:
4400 case XML_ELEMENT_DECL:
4401 case XML_ATTRIBUTE_DECL:
4402 case XML_ENTITY_DECL:
4403 case XML_NAMESPACE_DECL:
4404#ifdef LIBXML_DOCB_ENABLED
4405 case XML_DOCB_DOCUMENT_NODE:
4406#endif
4407 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4408 if (ctxt->error != NULL)
4409 ctxt->error(ctxt->userData,
4410 "Element %s: node type %d unexpected here\n",
4411 node->name, cur->type);
4412 return(ctxt->err);
4413 }
4414 cur = cur->next;
4415 }
4416 if (child == NULL)
4417 value = NULL;
4418 else
4419 value = xmlNodeGetContent(child->parent);
4420
4421 if (ctxt->value != NULL) {
4422 xmlSchemaFreeValue(ctxt->value);
4423 ctxt->value = NULL;
4424 }
4425 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4426 if (value != NULL)
4427 xmlFree(value);
4428 if (ret != 0) {
4429 ctxt->error(ctxt->userData,
4430 "Element %s: failed to validate basic type %s\n",
4431 node->name, type->name);
4432 }
4433 return(ret);
4434}
4435
4436/**
4437 * xmlSchemaValidateComplexType:
4438 * @ctxt: a schema validation context
4439 * @node: the top node.
4440 *
4441 * Validate the content of an element expected to be a complex type type
4442 * xmlschema-1.html#cvc-complex-type
4443 * Validation Rule: Element Locally Valid (Complex Type)
4444 *
4445 * Returns 0 if the element is schemas valid, a positive error code
4446 * number otherwise and -1 in case of internal or API error.
4447 */
4448static int
4449xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4450 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004451 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004452 int ret;
4453
4454 child = ctxt->node;
4455 type = ctxt->type;
4456
4457 /* 3.4.4 1 was verified on the caller */
4458
4459 switch (type->contentType) {
4460 case XML_SCHEMA_CONTENT_EMPTY:
4461 if (child != NULL) {
4462 if (ctxt->error != NULL)
4463 ctxt->error(ctxt->userData,
4464 "Element %s is supposed to be empty\n",
4465 node->name);
4466 }
4467 break;
4468 case XML_SCHEMA_CONTENT_ELEMENTS:
4469 case XML_SCHEMA_CONTENT_MIXED:
4470 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4471 /*
4472 * Skip ignorable nodes in that context
4473 */
4474 child = xmlSchemaSkipIgnored(ctxt, type, child);
4475 subtype = type->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +00004476 while (child != NULL) {
4477 if (child->type == XML_ELEMENT_NODE) {
4478 ret = xmlRegExecPushString(ctxt->regexp,
4479 child->name, child);
4480#ifdef DEBUG_AUTOMATA
4481 if (ret < 0)
4482 xmlGenericError(xmlGenericErrorContext,
4483 " --> %s Error\n", child->name);
4484 else
4485 xmlGenericError(xmlGenericErrorContext,
4486 " --> %s\n", child->name);
4487#endif
4488 }
4489 child = child->next;
4490 /*
4491 * Skip ignorable nodes in that context
4492 */
4493 child = xmlSchemaSkipIgnored(ctxt, type, child);
4494 }
4495 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004496 case XML_SCHEMA_CONTENT_BASIC: {
4497 if (type->subtypes != NULL) {
4498 ctxt->type = type->subtypes;
4499 xmlSchemaValidateComplexType(ctxt, node);
4500 }
4501 if (type->baseType != NULL) {
4502 ctxt->type = type->baseType;
4503 xmlSchemaValidateBasicType(ctxt, node);
4504 }
4505 if (type->attributes != NULL) {
4506 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4507 }
4508 ctxt->type = type;
4509 break;
4510 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004511 default:
4512 TODO
4513 xmlGenericError(xmlGenericErrorContext,
4514 "unimplemented content type %d\n",
4515 type->contentType);
4516 }
4517 return(ctxt->err);
4518}
4519
4520/**
4521 * xmlSchemaValidateContent:
4522 * @ctxt: a schema validation context
4523 * @elem: an element
4524 * @type: the type declaration
4525 *
4526 * Validate the content of an element against the type.
4527 *
4528 * Returns 0 if the element is schemas valid, a positive error code
4529 * number otherwise and -1 in case of internal or API error.
4530 */
4531static int
4532xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4533 xmlNodePtr child;
4534 xmlSchemaTypePtr type;
4535
4536 child = ctxt->node;
4537 type = ctxt->type;
4538
4539 switch (type->type) {
4540 case XML_SCHEMA_TYPE_ANY:
4541 /* Any type will do it, fine */
4542 TODO /* handle recursivity */
4543 break;
4544 case XML_SCHEMA_TYPE_COMPLEX:
4545 xmlSchemaValidateComplexType(ctxt, node);
4546 break;
4547 case XML_SCHEMA_TYPE_ELEMENT: {
4548 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
4549 /*
4550 * Handle element reference here
4551 */
4552 if (decl->ref != NULL) {
4553 if (decl->refDecl == NULL) {
4554 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4555 if (ctxt->error != NULL)
4556 ctxt->error(ctxt->userData,
4557 "Internal error: element reference %s not resolved\n",
4558 decl->ref);
4559 return(-1);
4560 }
4561 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
4562 decl = decl->refDecl;
4563 }
4564 xmlSchemaValidateElementType(ctxt, node);
4565 ctxt->type = type;
4566 break;
4567 }
4568 case XML_SCHEMA_TYPE_BASIC:
4569 xmlSchemaValidateBasicType(ctxt, node);
4570 break;
4571 case XML_SCHEMA_TYPE_FACET:
4572 TODO
4573 break;
4574 case XML_SCHEMA_TYPE_SIMPLE:
4575 xmlSchemaValidateSimpleType(ctxt, node);
4576 break;
4577 case XML_SCHEMA_TYPE_SEQUENCE:
4578 TODO
4579 break;
4580 case XML_SCHEMA_TYPE_CHOICE:
4581 TODO
4582 break;
4583 case XML_SCHEMA_TYPE_ALL:
4584 TODO
4585 break;
4586 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
4587 TODO
4588 break;
4589 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4590 TODO
4591 break;
4592 case XML_SCHEMA_TYPE_UR:
4593 TODO
4594 break;
4595 case XML_SCHEMA_TYPE_RESTRICTION:
4596 /*xmlSchemaValidateRestrictionType(ctxt, node); */
4597 TODO
4598 break;
4599 case XML_SCHEMA_TYPE_EXTENSION:
4600 TODO
4601 break;
4602 case XML_SCHEMA_TYPE_ATTRIBUTE:
4603 TODO
4604 break;
4605 case XML_SCHEMA_TYPE_GROUP:
4606 TODO
4607 break;
4608 case XML_SCHEMA_TYPE_NOTATION:
4609 TODO
4610 break;
4611 case XML_SCHEMA_TYPE_LIST:
4612 TODO
4613 break;
4614 case XML_SCHEMA_TYPE_UNION:
4615 TODO
4616 break;
4617 case XML_SCHEMA_FACET_MININCLUSIVE:
4618 TODO
4619 break;
4620 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4621 TODO
4622 break;
4623 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4624 TODO
4625 break;
4626 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4627 TODO
4628 break;
4629 case XML_SCHEMA_FACET_TOTALDIGITS:
4630 TODO
4631 break;
4632 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4633 TODO
4634 break;
4635 case XML_SCHEMA_FACET_PATTERN:
4636 TODO
4637 break;
4638 case XML_SCHEMA_FACET_ENUMERATION:
4639 TODO
4640 break;
4641 case XML_SCHEMA_FACET_WHITESPACE:
4642 TODO
4643 break;
4644 case XML_SCHEMA_FACET_LENGTH:
4645 TODO
4646 break;
4647 case XML_SCHEMA_FACET_MAXLENGTH:
4648 TODO
4649 break;
4650 case XML_SCHEMA_FACET_MINLENGTH:
4651 TODO
4652 break;
4653 }
4654 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4655
4656 if (ctxt->node == NULL)
4657 return(ctxt->err);
4658 ctxt->node = ctxt->node->next;
4659 ctxt->type = type->next;
4660 return(ctxt->err);
4661}
4662
4663/**
4664 * xmlSchemaValidateType:
4665 * @ctxt: a schema validation context
4666 * @elem: an element
4667 * @type: the list of type declarations
4668 *
4669 * Validate the content of an element against the types.
4670 *
4671 * Returns 0 if the element is schemas valid, a positive error code
4672 * number otherwise and -1 in case of internal or API error.
4673 */
4674static int
4675xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4676 xmlSchemaElementPtr elemDecl,
4677 xmlSchemaTypePtr type) {
4678 xmlChar *nil;
4679
4680 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
4681 return(0);
4682 /*
4683 * 3.3.4 : 2
4684 */
4685 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
4686 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
4687 if (ctxt->error != NULL)
4688 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
4689 return(ctxt->err);
4690 }
4691 /*
4692 * 3.3.4: 3
4693 */
4694 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
4695 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
4696 /* 3.3.4: 3.2 */
4697 if (xmlStrEqual(nil, BAD_CAST "true")) {
4698 if (elem->children != NULL) {
4699 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
4700 if (ctxt->error != NULL)
4701 ctxt->error(ctxt->userData, "Element %s is not empty\n",
4702 elem->name);
4703 return(ctxt->err);
4704 }
4705 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
4706 (elemDecl->value != NULL)) {
4707 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
4708 if (ctxt->error != NULL)
4709 ctxt->error(ctxt->userData,
4710 "Empty element %s cannot get a fixed value\n",
4711 elem->name);
4712 return(ctxt->err);
4713 }
4714 }
4715 } else {
4716 /* 3.3.4: 3.1 */
4717 if (nil != NULL) {
4718 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
4719 if (ctxt->error != NULL)
4720 ctxt->error(ctxt->userData,
4721 "Element %s with xs:nil but not nillable\n",
4722 elem->name);
4723 xmlFree(nil);
4724 return(ctxt->err);
4725 }
4726 }
4727
4728 /* TODO 3.3.4: 4 if the element carries xs:type*/
4729
4730 ctxt->type = elemDecl->subtypes;
4731 ctxt->node = elem->children;
4732 xmlSchemaValidateContent(ctxt, elem);
4733 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
4734
4735 return(ctxt->err);
4736}
4737
4738
4739/**
4740 * xmlSchemaValidateAttributes:
4741 * @ctxt: a schema validation context
4742 * @elem: an element
4743 * @attributes: the list of attribute declarations
4744 *
4745 * Validate the attributes of an element.
4746 *
4747 * Returns 0 if the element is schemas valid, a positive error code
4748 * number otherwise and -1 in case of internal or API error.
4749 */
4750static int
4751xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4752 xmlSchemaAttributePtr attributes) {
4753 int i, ret;
4754 xmlAttrPtr attr;
4755 xmlChar *value;
4756
4757 if (attributes == NULL)
4758 return(0);
4759 while (attributes != NULL) {
4760 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4761 attr = ctxt->attr[i].attr;
4762 if (attr == NULL)
4763 continue;
4764 if (!xmlStrEqual(attr->name, attributes->name))
4765 continue;
4766 /*
4767 * TODO: handle the mess about namespaces here.
4768 */
4769 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
4770 TODO
4771 }
4772 if (attributes->subtypes == NULL) {
4773 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4774 if (ctxt->error != NULL)
4775 ctxt->error(ctxt->userData,
4776 "Internal error: attribute %s type not resolved\n",
4777 attr->name);
4778 continue;
4779 }
4780 value = xmlNodeListGetString(elem->doc, attr->children, 1);
4781 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
4782 value);
4783 if (ret != 0) {
4784 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
4785 if (ctxt->error != NULL)
4786 ctxt->error(ctxt->userData,
4787 "attribute %s on %s does not match type\n",
4788 attr->name, elem->name);
4789 } else {
4790 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
4791 }
4792 if (value != NULL) {
4793 xmlFree(value);
4794 }
4795 }
4796 attributes = attributes->next;
4797 }
4798 return(ctxt->err);
4799}
4800
4801/**
4802 * xmlSchemaValidateElement:
4803 * @ctxt: a schema validation context
4804 * @elem: an element
4805 *
4806 * Validate an element in a tree
4807 *
4808 * Returns 0 if the element is schemas valid, a positive error code
4809 * number otherwise and -1 in case of internal or API error.
4810 */
4811static int
4812xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
4813 xmlSchemaElementPtr elemDecl;
4814 int ret, attrBase;
4815
4816 if (elem->ns != NULL)
4817 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
4818 elem->name, elem->ns->href, NULL);
4819 else
4820 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
4821 elem->name, NULL, NULL);
4822 /*
4823 * 3.3.4 : 1
4824 */
4825 if (elemDecl == NULL) {
4826 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
4827 if (ctxt->error != NULL)
4828 ctxt->error(ctxt->userData, "Element %s not declared\n",
4829 elem->name);
4830 return(ctxt->err);
4831 }
4832 if (elemDecl->subtypes == NULL) {
4833 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
4834 if (ctxt->error != NULL)
4835 ctxt->error(ctxt->userData, "Element %s has no type\n",
4836 elem->name);
4837 return(ctxt->err);
4838 }
4839 /*
4840 * Verify the attributes
4841 */
4842 attrBase = ctxt->attrBase;
4843 ctxt->attrBase = ctxt->attrNr;
4844 xmlSchemaRegisterAttributes(ctxt, elem->properties);
4845 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
4846 /*
4847 * Verify the element content recursively
4848 */
4849 if (elemDecl->contModel != NULL) {
4850 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
4851 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4852 ctxt);
4853#ifdef DEBUG_AUTOMATA
4854 xmlGenericError(xmlGenericErrorContext,
4855 "====> %s\n", elem->name);
4856#endif
4857 }
4858 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004859 if (elemDecl->contModel != NULL) {
4860 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004861#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00004862 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004863 "====> %s : %d\n", elem->name, ret);
4864#endif
4865 if (ret == 0) {
4866 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
4867 if (ctxt->error != NULL)
4868 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4869 elem->name);
4870 } else if (ret < 0) {
4871 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
4872 if (ctxt->error != NULL)
4873 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4874 elem->name);
4875#ifdef DEBUG_CONTENT
4876 } else {
4877 xmlGenericError(xmlGenericErrorContext,
4878 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004879
4880#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004881 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004882 xmlRegFreeExecCtxt(ctxt->regexp);
4883 }
4884 /*
4885 * Verify that all attributes were Schemas-validated
4886 */
4887 xmlSchemaCheckAttributes(ctxt, elem);
4888 ctxt->attrNr = ctxt->attrBase;
4889 ctxt->attrBase = attrBase;
4890
4891 return(ctxt->err);
4892}
4893
4894/**
4895 * xmlSchemaValidateDocument:
4896 * @ctxt: a schema validation context
4897 * @doc: a parsed document tree
4898 *
4899 * Validate a document tree in memory.
4900 *
4901 * Returns 0 if the document is schemas valid, a positive error code
4902 * number otherwise and -1 in case of internal or API error.
4903 */
4904static int
4905xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
4906 xmlNodePtr root;
4907 xmlSchemaElementPtr elemDecl;
4908
4909 root = xmlDocGetRootElement(doc);
4910 if (root == NULL) {
4911 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
4912 if (ctxt->error != NULL)
4913 ctxt->error(ctxt->userData, "document has no root\n");
4914 return(ctxt->err);
4915 }
4916 if (root->ns != NULL)
4917 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
4918 root->name, root->ns->href, NULL);
4919 else
4920 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
4921 root->name, NULL, NULL);
4922 if (elemDecl == NULL) {
4923 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
4924 if (ctxt->error != NULL)
4925 ctxt->error(ctxt->userData, "Element %s not declared\n",
4926 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004927 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004928 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
4929 if (ctxt->error != NULL)
4930 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
4931 root->name);
4932 }
4933 /*
4934 * Okay, start the recursive validation
4935 */
4936 xmlSchemaValidateElement(ctxt, root);
4937
4938 return(ctxt->err);
4939}
4940
4941/************************************************************************
4942 * *
4943 * SAX Validation code *
4944 * *
4945 ************************************************************************/
4946
4947/************************************************************************
4948 * *
4949 * Validation interfaces *
4950 * *
4951 ************************************************************************/
4952
4953/**
4954 * xmlSchemaNewValidCtxt:
4955 * @schema: a precompiled XML Schemas
4956 *
4957 * Create an XML Schemas validation context based on the given schema
4958 *
4959 * Returns the validation context or NULL in case of error
4960 */
4961xmlSchemaValidCtxtPtr
4962xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
4963 xmlSchemaValidCtxtPtr ret;
4964
4965 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
4966 if (ret == NULL) {
4967 xmlGenericError(xmlGenericErrorContext,
4968 "Failed to allocate new schama validation context\n");
4969 return (NULL);
4970 }
4971 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
4972 ret->schema = schema;
4973 ret->attrNr = 0;
4974 ret->attrMax = 10;
4975 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
4976 sizeof(xmlSchemaAttrState));
4977 if (ret->attr == NULL) {
4978 free(ret);
4979 return(NULL);
4980 }
4981 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
4982 return (ret);
4983}
4984
4985/**
4986 * xmlSchemaFreeValidCtxt:
4987 * @ctxt: the schema validation context
4988 *
4989 * Free the resources associated to the schema validation context
4990 */
4991void
4992xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
4993 if (ctxt == NULL)
4994 return;
4995 if (ctxt->attr != NULL)
4996 xmlFree(ctxt->attr);
4997 xmlFree(ctxt);
4998}
4999
5000/**
5001 * xmlSchemaSetValidErrors:
5002 * @ctxt: a schema validation context
5003 * @err: the error function
5004 * @warn: the warning function
5005 * @ctxt: the functions context
5006 *
5007 * Set the error and warning callback informations
5008 */
5009void
5010xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5011 xmlSchemaValidityErrorFunc err,
5012 xmlSchemaValidityWarningFunc warn, void *ctx) {
5013 if (ctxt == NULL)
5014 return;
5015 ctxt->error = err;
5016 ctxt->warning = warn;
5017 ctxt->userData = ctx;
5018}
5019
5020/**
5021 * xmlSchemaValidateDoc:
5022 * @ctxt: a schema validation context
5023 * @doc: a parsed document tree
5024 *
5025 * Validate a document tree in memory.
5026 *
5027 * Returns 0 if the document is schemas valid, a positive error code
5028 * number otherwise and -1 in case of internal or API error.
5029 */
5030int
5031xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5032 int ret;
5033
5034 if ((ctxt == NULL) || (doc == NULL))
5035 return(-1);
5036
5037 ctxt->doc = doc;
5038 ret = xmlSchemaValidateDocument(ctxt, doc);
5039 return(ret);
5040}
5041
5042/**
5043 * xmlSchemaValidateStream:
5044 * @ctxt: a schema validation context
5045 * @input: the input to use for reading the data
5046 * @enc: an optional encoding information
5047 * @sax: a SAX handler for the resulting events
5048 * @user_data: the context to provide to the SAX handler.
5049 *
5050 * Validate a document tree in memory.
5051 *
5052 * Returns 0 if the document is schemas valid, a positive error code
5053 * number otherwise and -1 in case of internal or API error.
5054 */
5055int
5056xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5057 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5058 xmlSAXHandlerPtr sax, void *user_data) {
5059 if ((ctxt == NULL) || (input == NULL))
5060 return(-1);
5061 ctxt->input = input;
5062 ctxt->enc = enc;
5063 ctxt->sax = sax;
5064 ctxt->user_data = user_data;
5065 TODO
5066 return(0);
5067}
5068
5069#endif /* LIBXML_SCHEMAS_ENABLED */