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