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