blob: e49a0b0d0f412cad0a713d4651abea8e2d2d8afc [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemas.c : implementation of the XML Schema handling and
3 * schema validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
Daniel Veillard5a872412002-05-22 06:40:27 +000020#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000021
22#include <libxml/xmlschemas.h>
23#include <libxml/schemasInternals.h>
24#include <libxml/xmlschemastypes.h>
25#include <libxml/xmlautomata.h>
26#include <libxml/xmlregexp.h>
27
Daniel Veillard8651f532002-04-17 09:06:27 +000028#define DEBUG 1 /* very verbose output */
29#define DEBUG_CONTENT 1
30#define DEBUG_TYPE 1
Daniel Veillard118aed72002-09-24 14:13:13 +000031/* #define DEBUG_CONTENT_REGEXP 1 */
Daniel Veillard4255d502002-04-16 15:50:10 +000032/* #define DEBUG_AUTOMATA 1 */
33
34#define UNBOUNDED (1 << 30)
35#define TODO \
36 xmlGenericError(xmlGenericErrorContext, \
37 "Unimplemented block at %s:%d\n", \
38 __FILE__, __LINE__);
39
Daniel Veillard5a872412002-05-22 06:40:27 +000040#define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar *)"the default namespace"
41
Daniel Veillard4255d502002-04-16 15:50:10 +000042/*
43 * The XML Schemas namespaces
44 */
45static const xmlChar *xmlSchemaNs = (const xmlChar *)
46 "http://www.w3.org/2001/XMLSchema";
47
48static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
49 "http://www.w3.org/2001/XMLSchema-instance";
50
51#define IS_SCHEMA(node, type) \
52 ((node != NULL) && (node->ns != NULL) && \
53 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
54 (xmlStrEqual(node->ns->href, xmlSchemaNs)))
55
56#define XML_SCHEMAS_PARSE_ERROR 1
57
58struct _xmlSchemaParserCtxt {
59 void *userData; /* user specific data block */
60 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
61 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillarde19fc232002-04-22 16:01:24 +000062 xmlSchemaValidError err;
Daniel Veillard4255d502002-04-16 15:50:10 +000063
64 xmlSchemaPtr schema; /* The schema in use */
65 xmlChar *container; /* the current element, group, ... */
66 int counter;
67
68 xmlChar *URL;
69 xmlDocPtr doc;
70
Daniel Veillard6045c902002-10-09 21:13:59 +000071 const char *buffer;
72 int size;
73
Daniel Veillard4255d502002-04-16 15:50:10 +000074 /*
75 * Used to build complex element content models
76 */
77 xmlAutomataPtr am;
78 xmlAutomataStatePtr start;
79 xmlAutomataStatePtr end;
80 xmlAutomataStatePtr state;
81};
82
83
84#define XML_SCHEMAS_ATTR_UNKNOWN 1
85#define XML_SCHEMAS_ATTR_CHECKED 2
86
87typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
88typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
89struct _xmlSchemaAttrState {
90 xmlAttrPtr attr;
91 int state;
92};
93
94/**
95 * xmlSchemaValidCtxt:
96 *
97 * A Schemas validation context
98 */
99
100struct _xmlSchemaValidCtxt {
101 void *userData; /* user specific data block */
102 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
103 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
104
105 xmlSchemaPtr schema; /* The schema in use */
106 xmlDocPtr doc;
107 xmlParserInputBufferPtr input;
108 xmlCharEncoding enc;
109 xmlSAXHandlerPtr sax;
110 void *user_data;
111
112 xmlDocPtr myDoc;
113 int err;
114
115 xmlNodePtr node;
116 xmlSchemaTypePtr type;
117
118 xmlRegExecCtxtPtr regexp;
119 xmlSchemaValPtr value;
120
121 int attrNr;
122 int attrBase;
123 int attrMax;
124 xmlSchemaAttrStatePtr attr;
125};
126
127
128/************************************************************************
129 * *
130 * Some predeclarations *
131 * *
132 ************************************************************************/
133static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
134 xmlSchemaTypePtr type,
135 xmlChar *value);
136
137/************************************************************************
138 * *
139 * Allocation functions *
140 * *
141 ************************************************************************/
142
143/**
144 * xmlSchemaNewSchema:
145 * @ctxt: a schema validation context (optional)
146 *
147 * Allocate a new Schema structure.
148 *
149 * Returns the newly allocated structure or NULL in case or error
150 */
151static xmlSchemaPtr
152xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
153{
154 xmlSchemaPtr ret;
155
156 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
157 if (ret == NULL) {
158 if ((ctxt != NULL) && (ctxt->error != NULL))
159 ctxt->error(ctxt->userData, "Out of memory\n");
160 return (NULL);
161 }
162 memset(ret, 0, sizeof(xmlSchema));
163
164 return (ret);
165}
166
167/**
168 * xmlSchemaNewFacet:
169 * @ctxt: a schema validation context (optional)
170 *
171 * Allocate a new Facet structure.
172 *
173 * Returns the newly allocated structure or NULL in case or error
174 */
175static xmlSchemaFacetPtr
176xmlSchemaNewFacet(xmlSchemaParserCtxtPtr ctxt)
177{
178 xmlSchemaFacetPtr ret;
179
180 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
181 if (ret == NULL) {
182 if ((ctxt != NULL) && (ctxt->error != NULL))
183 ctxt->error(ctxt->userData, "Out of memory\n");
184 return (NULL);
185 }
186 memset(ret, 0, sizeof(xmlSchemaFacet));
187
188 return (ret);
189}
190
191/**
192 * xmlSchemaNewAnnot:
193 * @ctxt: a schema validation context (optional)
194 * @node: a node
195 *
196 * Allocate a new annotation structure.
197 *
198 * Returns the newly allocated structure or NULL in case or error
199 */
200static xmlSchemaAnnotPtr
201xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
202{
203 xmlSchemaAnnotPtr ret;
204
205 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
206 if (ret == NULL) {
207 if ((ctxt != NULL) && (ctxt->error != NULL))
208 ctxt->error(ctxt->userData, "Out of memory\n");
209 return (NULL);
210 }
211 memset(ret, 0, sizeof(xmlSchemaAnnot));
212 ret->content = node;
213 return (ret);
214}
215
216/**
Daniel Veillardfdc91562002-07-01 21:52:03 +0000217 * xmlSchemaFreeAnnot:
218 * @annot: a schema type structure
219 *
220 * Deallocate a annotation structure
221 */
222static void
223xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
224{
225 if (annot == NULL)
226 return;
227 xmlFree(annot);
228}
229
230/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000231 * xmlSchemaFreeNotation:
232 * @schema: a schema notation structure
233 *
234 * Deallocate a Schema Notation structure.
235 */
236static void
237xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
238{
239 if (nota == NULL)
240 return;
241 if (nota->name != NULL)
242 xmlFree((xmlChar *) nota->name);
243 xmlFree(nota);
244}
245
246/**
247 * xmlSchemaFreeAttribute:
248 * @schema: a schema attribute structure
249 *
250 * Deallocate a Schema Attribute structure.
251 */
252static void
253xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
254{
255 if (attr == NULL)
256 return;
257 if (attr->name != NULL)
258 xmlFree((xmlChar *) attr->name);
259 if (attr->ref != NULL)
260 xmlFree((xmlChar *) attr->ref);
261 if (attr->refNs != NULL)
262 xmlFree((xmlChar *) attr->refNs);
263 if (attr->typeName != NULL)
264 xmlFree((xmlChar *) attr->typeName);
265 if (attr->typeNs != NULL)
266 xmlFree((xmlChar *) attr->typeNs);
267 xmlFree(attr);
268}
269
270/**
271 * xmlSchemaFreeAttributeGroup:
272 * @schema: a schema attribute group structure
273 *
274 * Deallocate a Schema Attribute Group structure.
275 */
276static void
277xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
278{
279 if (attr == NULL)
280 return;
281 if (attr->name != NULL)
282 xmlFree((xmlChar *) attr->name);
283 xmlFree(attr);
284}
285
286/**
287 * xmlSchemaFreeElement:
288 * @schema: a schema element structure
289 *
290 * Deallocate a Schema Element structure.
291 */
292static void
293xmlSchemaFreeElement(xmlSchemaElementPtr elem)
294{
295 if (elem == NULL)
296 return;
297 if (elem->name != NULL)
298 xmlFree((xmlChar *) elem->name);
299 if (elem->namedType != NULL)
300 xmlFree((xmlChar *) elem->namedType);
301 if (elem->namedTypeNs != NULL)
302 xmlFree((xmlChar *) elem->namedTypeNs);
303 if (elem->ref != NULL)
304 xmlFree((xmlChar *) elem->ref);
305 if (elem->refNs != NULL)
306 xmlFree((xmlChar *) elem->refNs);
307 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 */
318static void
319xmlSchemaFreeFacet(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)
354 xmlFree((xmlChar *) type->annot);
355 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)
705 fprintf(output, "%s", schema->targetNamespace);
706 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
1339 facet = xmlSchemaNewFacet(ctxt);
1340 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) {
3102 if (elem->refDecl != NULL) {
3103 xmlSchemaBuildAContentModel(
3104 (xmlSchemaTypePtr) elem->refDecl,
3105 ctxt, elem->refDecl->name);
3106 } else {
3107 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3108 ctxt->state, NULL, elem->name, type);
3109 }
3110 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3111 if (elem->minOccurs == 0) {
3112 /* basically an elem* */
3113 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3114 }
3115 } else if (elem->maxOccurs > 1) {
3116 if (elem->refDecl != NULL) {
3117 TODO
3118 xmlSchemaBuildAContentModel(
3119 (xmlSchemaTypePtr) elem->refDecl,
3120 ctxt, elem->refDecl->name);
3121 } else {
3122 ctxt->state = xmlAutomataNewCountTrans(ctxt->am,
3123 ctxt->state, NULL, elem->name,
3124 elem->minOccurs, elem->maxOccurs, type);
3125 }
3126 } else {
3127 if (elem->refDecl != NULL) {
3128 xmlSchemaBuildAContentModel(
3129 (xmlSchemaTypePtr) elem->refDecl,
3130 ctxt, elem->refDecl->name);
3131 } else {
3132 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3133 ctxt->state, NULL, elem->name, type);
3134 }
3135 if (elem->minOccurs == 0) {
3136 /* basically an elem? */
3137 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3138 }
3139 }
3140 break;
3141 }
3142 case XML_SCHEMA_TYPE_SEQUENCE: {
3143 xmlSchemaTypePtr subtypes;
3144
3145 /*
3146 * Simply iterate over the subtypes
3147 */
3148 subtypes = type->subtypes;
3149 while (subtypes != NULL) {
3150 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3151 subtypes = subtypes->next;
3152 }
3153 break;
3154 }
3155 case XML_SCHEMA_TYPE_CHOICE: {
3156 xmlSchemaTypePtr subtypes;
3157 xmlAutomataStatePtr start, end;
3158
3159 start = ctxt->state;
3160 end = xmlAutomataNewState(ctxt->am);
3161
3162 /*
3163 * iterate over the subtypes and remerge the end with an
3164 * epsilon transition
3165 */
Daniel Veillardb509f152002-04-17 16:28:10 +00003166 if (type->maxOccurs == 1) {
3167 subtypes = type->subtypes;
3168 while (subtypes != NULL) {
3169 ctxt->state = start;
3170 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3171 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3172 subtypes = subtypes->next;
3173 }
3174 } else {
3175 int counter;
3176 xmlAutomataStatePtr hop;
3177
3178 /*
3179 * use a counter to keep track of the number of transtions
3180 * which went through the choice.
3181 */
3182 if (type->minOccurs < 1) {
3183 counter = xmlAutomataNewCounter(ctxt->am, 0,
3184 type->maxOccurs - 1);
3185 } else {
3186 counter = xmlAutomataNewCounter(ctxt->am,
3187 type->minOccurs - 1, type->maxOccurs - 1);
3188 }
3189 hop = xmlAutomataNewState(ctxt->am);
3190
3191 subtypes = type->subtypes;
3192 while (subtypes != NULL) {
3193 ctxt->state = start;
3194 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3195 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3196 subtypes = subtypes->next;
3197 }
3198 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3199 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3200 }
3201 if (type->minOccurs == 0) {
3202 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003203 }
3204 ctxt->state = end;
3205 break;
3206 }
3207 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003208 xmlAutomataStatePtr start;
3209 xmlSchemaTypePtr subtypes;
3210 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard441bc322002-04-20 17:38:48 +00003211 int lax;
Daniel Veillard7646b182002-04-20 06:41:40 +00003212
3213 subtypes = type->subtypes;
3214 if (subtypes == NULL)
3215 break;
3216 start = ctxt->state;
3217 while (subtypes != NULL) {
3218 ctxt->state = start;
3219 elem = (xmlSchemaElementPtr) subtypes;
3220
3221 /* TODO : handle the namespace too */
3222 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3223 elem->name, elem->minOccurs, elem->maxOccurs,
3224 subtypes);
3225 subtypes = subtypes->next;
3226 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003227 lax = type->minOccurs == 0;
3228 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3229 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003230 break;
3231 }
3232 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003233 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003234 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3235 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003236 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003237 if (type->baseType != NULL) {
3238 xmlSchemaTypePtr subtypes;
3239
3240 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3241 subtypes = type->subtypes;
3242 while (subtypes != NULL) {
3243 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3244 subtypes = subtypes->next;
3245 }
3246 } else if (type->subtypes != NULL)
3247 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3248 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003249 case XML_SCHEMA_TYPE_GROUP:
3250 case XML_SCHEMA_TYPE_COMPLEX:
3251 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3252 if (type->subtypes != NULL)
3253 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3254 break;
3255 default:
3256 xmlGenericError(xmlGenericErrorContext,
3257 "Found unexpected type %d in %s content model\n",
3258 type->type, name);
3259 return;
3260 }
3261}
3262/**
3263 * xmlSchemaBuildContentModel:
3264 * @typeDecl: the schema type definition
3265 * @ctxt: the schema parser context
3266 *
3267 * Fixes the content model of the element.
3268 */
3269static void
3270xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3271 xmlSchemaParserCtxtPtr ctxt,
3272 const xmlChar *name) {
3273 xmlAutomataStatePtr start;
3274
Daniel Veillard4255d502002-04-16 15:50:10 +00003275 if (elem->contModel != NULL)
3276 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003277 if (elem->subtypes == NULL) {
3278 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003279 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003280 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003281 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3282 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003283 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3284 return;
3285
3286#ifdef DEBUG_CONTENT
3287 xmlGenericError(xmlGenericErrorContext,
3288 "Building content model for %s\n", name);
3289#endif
3290
Daniel Veillard4255d502002-04-16 15:50:10 +00003291 ctxt->am = xmlNewAutomata();
3292 if (ctxt->am == NULL) {
3293 xmlGenericError(xmlGenericErrorContext,
3294 "Cannot create automata for elem %s\n", name);
3295 return;
3296 }
3297 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3298 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3299 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003300 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003301 if (!xmlAutomataIsDeterminist(ctxt->am)) {
3302 xmlGenericError(xmlGenericErrorContext,
3303 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003304 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillard4402ab42002-09-12 16:02:56 +00003305 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003306 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00003307#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillarde19fc232002-04-22 16:01:24 +00003308 xmlGenericError(xmlGenericErrorContext,
3309 "Content model of %s:\n", name);
3310 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003311#endif
Daniel Veillard4402ab42002-09-12 16:02:56 +00003312 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003313 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003314 xmlFreeAutomata(ctxt->am);
3315 ctxt->am = NULL;
3316}
3317
3318/**
3319 * xmlSchemaRefFixupCallback:
3320 * @elem: the schema element context
3321 * @ctxt: the schema parser context
3322 *
3323 * Free the resources associated to the schema parser context
3324 */
3325static void
3326xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3327 xmlSchemaParserCtxtPtr ctxt,
3328 const xmlChar *name,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003329 const xmlChar *context ATTRIBUTE_UNUSED,
3330 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00003331{
3332 if ((ctxt == NULL) || (elem == NULL))
3333 return;
3334 if (elem->ref != NULL) {
3335 xmlSchemaElementPtr elemDecl;
3336
3337 if (elem->subtypes != NULL) {
3338 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3339 if ((ctxt != NULL) && (ctxt->error != NULL))
3340 ctxt->error(ctxt->userData,
3341 "Schemas: element %s have both ref and subtype\n",
3342 name);
3343 return;
3344 }
3345 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3346 elem->ref, elem->refNs);
3347
3348 if (elemDecl == NULL) {
3349 if ((ctxt != NULL) && (ctxt->error != NULL))
3350 ctxt->error(ctxt->userData,
3351 "Schemas: element %s ref to %s not found\n",
3352 name, elem->ref);
3353 return;
3354 }
3355 elem->refDecl = elemDecl;
3356 } else if (elem->namedType != NULL) {
3357 xmlSchemaTypePtr typeDecl;
3358
3359 if (elem->subtypes != NULL) {
3360 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3361 if ((ctxt != NULL) && (ctxt->error != NULL))
3362 ctxt->error(ctxt->userData,
3363 "Schemas: element %s have both type and subtype\n",
3364 name);
3365 return;
3366 }
3367 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3368 elem->namedTypeNs);
3369
3370 if (typeDecl == NULL) {
3371 if ((ctxt != NULL) && (ctxt->error != NULL))
3372 ctxt->error(ctxt->userData,
3373 "Schemas: element %s type %s not found\n",
3374 name, elem->namedType);
3375 return;
3376 }
3377 elem->subtypes = typeDecl;
3378 }
3379}
3380
3381/**
3382 * xmlSchemaTypeFixup:
3383 * @typeDecl: the schema type definition
3384 * @ctxt: the schema parser context
3385 *
3386 * Fixes the content model of the type.
3387 */
3388static void
3389xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3390 xmlSchemaParserCtxtPtr ctxt,
3391 const xmlChar *name)
3392{
3393 if (name == NULL)
3394 name = typeDecl->name;
3395 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3396 switch (typeDecl->type) {
3397 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3398 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3399 typeDecl->contentType = typeDecl->subtypes->contentType;
3400 break;
3401 }
3402 case XML_SCHEMA_TYPE_RESTRICTION: {
3403 if (typeDecl->subtypes != NULL)
3404 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3405
3406 if (typeDecl->base != NULL) {
3407 xmlSchemaTypePtr baseType;
3408
3409 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3410 typeDecl->baseNs);
3411 if (baseType == NULL) {
3412 if ((ctxt != NULL) && (ctxt->error != NULL))
3413 ctxt->error(ctxt->userData,
3414 "Schemas: type %s base type %s not found\n",
3415 name, typeDecl->base);
3416 }
3417 typeDecl->baseType = baseType;
3418 }
3419 if (typeDecl->subtypes == NULL)
3420 /* 1.1.1 */
3421 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3422 else if ((typeDecl->subtypes->subtypes == NULL) &&
3423 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3424 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3425 /* 1.1.2 */
3426 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3427 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3428 (typeDecl->subtypes->subtypes == NULL))
3429 /* 1.1.3 */
3430 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3431 else {
3432 /* 1.2 and 2.X are applied at the other layer */
3433 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3434 }
3435 break;
3436 }
3437 case XML_SCHEMA_TYPE_EXTENSION: {
3438 xmlSchemaContentType explicitContentType;
3439 xmlSchemaTypePtr base;
3440
3441 if (typeDecl->base != NULL) {
3442 xmlSchemaTypePtr baseType;
3443
3444 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3445 typeDecl->baseNs);
3446 if (baseType == NULL) {
3447 if ((ctxt != NULL) && (ctxt->error != NULL))
3448 ctxt->error(ctxt->userData,
3449 "Schemas: type %s base type %s not found\n",
3450 name, typeDecl->base);
3451 }
3452 typeDecl->baseType = baseType;
3453 }
3454 if (typeDecl->subtypes != NULL)
3455 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3456
Daniel Veillard8651f532002-04-17 09:06:27 +00003457 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003458 if (typeDecl->subtypes == NULL)
3459 /* 1.1.1 */
3460 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3461 else if ((typeDecl->subtypes->subtypes == NULL) &&
3462 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3463 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3464 /* 1.1.2 */
3465 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3466 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3467 (typeDecl->subtypes->subtypes == NULL))
3468 /* 1.1.3 */
3469 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3470
3471 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3472 typeDecl->baseNs);
3473 if (base == NULL) {
3474 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3475 if ((ctxt != NULL) && (ctxt->error != NULL))
3476 ctxt->error(ctxt->userData,
3477 "Schemas: base type %s of type %s not found\n",
3478 typeDecl->base, name);
3479 return;
3480 }
3481 xmlSchemaTypeFixup(base, ctxt, NULL);
3482 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3483 /* 2.1 */
3484 typeDecl->contentType = base->contentType;
3485 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3486 /* 2.2 imbitable ! */
3487 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3488 } else {
3489 /* 2.3 imbitable pareil ! */
3490 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3491 }
3492 break;
3493 }
3494 case XML_SCHEMA_TYPE_COMPLEX: {
3495 if (typeDecl->subtypes == NULL) {
3496 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3497 } else {
3498 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3499 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3500 else {
3501 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3502 typeDecl->contentType = typeDecl->subtypes->contentType;
3503 }
3504 }
3505 break;
3506 }
3507 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3508 if (typeDecl->subtypes == NULL) {
3509 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3510 } else {
3511 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3512 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3513 else {
3514 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3515 typeDecl->contentType = typeDecl->subtypes->contentType;
3516 }
3517 }
3518 break;
3519 }
3520 case XML_SCHEMA_TYPE_SEQUENCE:
3521 case XML_SCHEMA_TYPE_GROUP:
3522 case XML_SCHEMA_TYPE_ALL:
3523 case XML_SCHEMA_TYPE_CHOICE:
3524 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3525 break;
3526 case XML_SCHEMA_TYPE_BASIC:
3527 case XML_SCHEMA_TYPE_ANY:
3528 case XML_SCHEMA_TYPE_FACET:
3529 case XML_SCHEMA_TYPE_SIMPLE:
3530 case XML_SCHEMA_TYPE_UR:
3531 case XML_SCHEMA_TYPE_ELEMENT:
3532 case XML_SCHEMA_TYPE_ATTRIBUTE:
Daniel Veillard118aed72002-09-24 14:13:13 +00003533 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
Daniel Veillard4255d502002-04-16 15:50:10 +00003534 case XML_SCHEMA_TYPE_NOTATION:
3535 case XML_SCHEMA_TYPE_LIST:
3536 case XML_SCHEMA_TYPE_UNION:
3537 case XML_SCHEMA_FACET_MININCLUSIVE:
3538 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3539 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3540 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3541 case XML_SCHEMA_FACET_TOTALDIGITS:
3542 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3543 case XML_SCHEMA_FACET_PATTERN:
3544 case XML_SCHEMA_FACET_ENUMERATION:
3545 case XML_SCHEMA_FACET_WHITESPACE:
3546 case XML_SCHEMA_FACET_LENGTH:
3547 case XML_SCHEMA_FACET_MAXLENGTH:
3548 case XML_SCHEMA_FACET_MINLENGTH:
3549 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3550 break;
3551 }
3552 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003553#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003554 if (typeDecl->node != NULL) {
3555 xmlGenericError(xmlGenericErrorContext,
3556 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3557 xmlGetLineNo(typeDecl->node));
3558 } else {
3559 xmlGenericError(xmlGenericErrorContext,
3560 "Type of %s :", name);
3561 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003562 switch (typeDecl->contentType) {
3563 case XML_SCHEMA_CONTENT_SIMPLE:
3564 xmlGenericError(xmlGenericErrorContext,
3565 "simple\n"); break;
3566 case XML_SCHEMA_CONTENT_ELEMENTS:
3567 xmlGenericError(xmlGenericErrorContext,
3568 "elements\n"); break;
3569 case XML_SCHEMA_CONTENT_UNKNOWN:
3570 xmlGenericError(xmlGenericErrorContext,
3571 "unknown !!!\n"); break;
3572 case XML_SCHEMA_CONTENT_EMPTY:
3573 xmlGenericError(xmlGenericErrorContext,
3574 "empty\n"); break;
3575 case XML_SCHEMA_CONTENT_MIXED:
3576 xmlGenericError(xmlGenericErrorContext,
3577 "mixed\n"); break;
3578 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3579 xmlGenericError(xmlGenericErrorContext,
3580 "mixed or elems\n"); break;
3581 case XML_SCHEMA_CONTENT_BASIC:
3582 xmlGenericError(xmlGenericErrorContext,
3583 "basic\n"); break;
3584 default:
3585 xmlGenericError(xmlGenericErrorContext,
3586 "not registered !!!\n"); break;
3587 }
3588#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003589}
3590
3591/**
3592 * xmlSchemaCheckDefaults:
3593 * @typeDecl: the schema type definition
3594 * @ctxt: the schema parser context
3595 *
3596 * Checks the default values types, especially for facets
3597 */
3598static void
3599xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
3600 xmlSchemaParserCtxtPtr ctxt,
3601 const xmlChar *name)
3602{
3603 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3604 if (name == NULL)
3605 name = typeDecl->name;
3606 if (nonNegativeIntegerType == NULL) {
3607 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3608 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3609 }
3610 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
3611 if (typeDecl->facets != NULL) {
3612 xmlSchemaFacetPtr facet = typeDecl->facets;
3613 while (facet != NULL) {
3614 switch (facet->type) {
3615 case XML_SCHEMA_FACET_MININCLUSIVE:
3616 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3617 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3618 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3619 /*
3620 * Okay we need to validate the value
3621 * at that point.
3622 */
3623 xmlSchemaValidCtxtPtr vctxt;
3624
3625 vctxt = xmlSchemaNewValidCtxt(NULL);
3626 if (vctxt == NULL)
3627 break;
3628 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3629 facet->value);
3630 facet->val = vctxt->value;
3631 vctxt->value = NULL;
3632 if (facet->val == NULL) {
3633 /* error code */
3634 xmlSchemaErrorContext(ctxt, NULL,
3635 facet->node, NULL);
3636 ctxt->error(ctxt->userData,
3637 "Schemas: type %s facet value %s invalid\n",
3638 name, facet->value);
3639 }
3640 xmlSchemaFreeValidCtxt(vctxt);
3641 break;
3642 }
3643 case XML_SCHEMA_FACET_ENUMERATION: {
3644 /*
3645 * Okay we need to validate the value
3646 * at that point.
3647 */
3648 xmlSchemaValidCtxtPtr vctxt;
3649 int ret;
3650
3651 vctxt = xmlSchemaNewValidCtxt(NULL);
3652 if (vctxt == NULL)
3653 break;
3654 ret = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3655 facet->value);
3656 if (ret != 0) {
3657 xmlSchemaErrorContext(ctxt, NULL,
3658 facet->node, NULL);
3659 ctxt->error(ctxt->userData,
3660 "Schemas: type %s enumeration value %s invalid\n",
3661 name, facet->value);
3662 }
3663 xmlSchemaFreeValidCtxt(vctxt);
3664 break;
3665 }
3666 case XML_SCHEMA_FACET_PATTERN:
3667 facet->regexp = xmlRegexpCompile(facet->value);
3668 if (facet->regexp == NULL) {
3669 /* error code */
3670 ctxt->error(ctxt->userData,
3671 "Schemas: type %s facet regexp %s invalid\n",
3672 name, facet->value);
3673 }
3674 break;
3675 case XML_SCHEMA_FACET_TOTALDIGITS:
3676 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3677 case XML_SCHEMA_FACET_LENGTH:
3678 case XML_SCHEMA_FACET_MAXLENGTH:
3679 case XML_SCHEMA_FACET_MINLENGTH: {
3680 int ret;
3681
3682 ret = xmlSchemaValidatePredefinedType(
3683 nonNegativeIntegerType, facet->value,
3684 &facet->val);
3685 if (ret != 0) {
3686 /* error code */
3687 xmlSchemaErrorContext(ctxt, NULL,
3688 facet->node, NULL);
3689 ctxt->error(ctxt->userData,
3690 "Schemas: type %s facet value %s invalid\n",
3691 name, facet->value);
3692 }
3693 break;
3694 }
3695 case XML_SCHEMA_FACET_WHITESPACE: {
3696 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
3697 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
3698 } else if (xmlStrEqual(facet->value,
3699 BAD_CAST"replace")) {
3700 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
3701 } else if (xmlStrEqual(facet->value,
3702 BAD_CAST"collapse")) {
3703 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
3704 } else {
3705 xmlSchemaErrorContext(ctxt, NULL,
3706 facet->node, NULL);
3707 ctxt->error(ctxt->userData,
3708 "Schemas: type %s whiteSpace value %s invalid\n",
3709 name, facet->value);
3710 }
3711 }
3712 default:
3713 break;
3714 }
3715 facet = facet->next;
3716 }
3717 }
3718 }
3719}
3720
3721/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00003722 * xmlSchemaAttrGrpFixup:
3723 * @attrgrpDecl: the schema attribute definition
3724 * @ctxt: the schema parser context
3725 * @name: the attribute name
3726 *
3727 * Fixes finish doing the computations on the attributes definitions
3728 */
3729static void
3730xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
3731 xmlSchemaParserCtxtPtr ctxt,
3732 const xmlChar *name)
3733{
3734 if (name == NULL)
3735 name = attrgrpDecl->name;
3736 if (attrgrpDecl->attributes != NULL)
3737 return;
3738 if (attrgrpDecl->ref != NULL) {
3739 xmlSchemaAttributeGroupPtr ref;
3740
3741 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
3742 attrgrpDecl->refNs);
3743 if (ref == NULL) {
3744 if ((ctxt != NULL) && (ctxt->error != NULL))
3745 ctxt->error(ctxt->userData,
3746 "Schemas: attribute group %s reference %s not found\n",
3747 name, attrgrpDecl->ref);
3748 return;
3749 }
3750 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
3751 attrgrpDecl->attributes = ref->attributes;
3752 } else {
3753 if ((ctxt != NULL) && (ctxt->error != NULL))
3754 ctxt->error(ctxt->userData,
3755 "Schemas: attribute %s has no attributes nor reference\n",
3756 name);
3757 }
3758}
3759
3760/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003761 * xmlSchemaAttrFixup:
3762 * @attrDecl: the schema attribute definition
3763 * @ctxt: the schema parser context
3764 * @name: the attribute name
3765 *
3766 * Fixes finish doing the computations on the attributes definitions
3767 */
3768static void
3769xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
3770 xmlSchemaParserCtxtPtr ctxt,
3771 const xmlChar *name)
3772{
3773 if (name == NULL)
3774 name = attrDecl->name;
3775 if (attrDecl->subtypes != NULL)
3776 return;
3777 if (attrDecl->typeName != NULL) {
3778 xmlSchemaTypePtr type;
3779
3780 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
3781 attrDecl->typeNs);
3782 if (type == NULL) {
3783 if ((ctxt != NULL) && (ctxt->error != NULL))
3784 ctxt->error(ctxt->userData,
3785 "Schemas: attribute %s type %s not found\n",
3786 name, attrDecl->typeName);
3787 }
3788 attrDecl->subtypes = type;
3789 } else if (attrDecl->ref != NULL) {
3790 xmlSchemaAttributePtr ref;
3791
3792 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
3793 attrDecl->refNs);
3794 if (ref == NULL) {
3795 if ((ctxt != NULL) && (ctxt->error != NULL))
3796 ctxt->error(ctxt->userData,
3797 "Schemas: attribute %s reference %s not found\n",
3798 name, attrDecl->ref);
3799 return;
3800 }
3801 xmlSchemaAttrFixup(ref, ctxt, NULL);
3802 attrDecl->subtypes = ref->subtypes;
3803 } else {
3804 if ((ctxt != NULL) && (ctxt->error != NULL))
3805 ctxt->error(ctxt->userData,
3806 "Schemas: attribute %s has no type nor reference\n",
3807 name);
3808 }
3809}
3810
3811/**
3812 * xmlSchemaParse:
3813 * @ctxt: a schema validation context
3814 * @URL: the location of the schema
3815 *
3816 * Load, XML parse a schema definition resource and build an internal
3817 * XML Shema struture which can be used to validate instances.
3818 * *WARNING* this interface is highly subject to change
3819 *
3820 * Returns the internal XML Schema structure built from the resource or
3821 * NULL in case of error
3822 */
3823xmlSchemaPtr
3824xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
3825{
3826 xmlSchemaPtr ret = NULL;
3827 xmlDocPtr doc;
3828 xmlNodePtr root, cur, delete;
3829
3830 xmlSchemaInitTypes();
3831
Daniel Veillard6045c902002-10-09 21:13:59 +00003832 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00003833 return (NULL);
3834
3835 ctxt->counter = 0;
3836 ctxt->container = NULL;
3837
3838 /*
3839 * First step is to parse the input document into an DOM/Infoset
3840 */
Daniel Veillard6045c902002-10-09 21:13:59 +00003841 if (ctxt->URL != NULL) {
3842 doc = xmlParseFile((const char *) ctxt->URL);
3843 if (doc == NULL) {
3844 if (ctxt->error != NULL)
3845 ctxt->error(ctxt->userData,
3846 "xmlSchemaParse: could not load %s\n", ctxt->URL);
3847 return (NULL);
3848 }
3849 } else if (ctxt->buffer != NULL) {
3850 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
3851 if (doc == NULL) {
3852 if (ctxt->error != NULL)
3853 ctxt->error(ctxt->userData,
3854 "xmlSchemaParse: could not parse schemas\n");
3855 return (NULL);
3856 }
3857 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
3858 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
3859 } else {
3860 if (ctxt->error != NULL)
3861 ctxt->error(ctxt->userData,
3862 "xmlSchemaParse: nothing to parse\n");
3863 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003864 }
3865
3866 /*
3867 * Then extract the root and Schema parse it
3868 */
3869 root = xmlDocGetRootElement(doc);
3870 if (root == NULL) {
3871 if (ctxt->error != NULL)
3872 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
3873 ctxt->URL);
3874 return (NULL);
3875 }
3876
3877 /*
3878 * Remove all the blank text nodes
3879 */
3880 delete = NULL;
3881 cur = root;
3882 while (cur != NULL) {
3883 if (delete != NULL) {
3884 xmlUnlinkNode(delete);
3885 xmlFreeNode(delete);
3886 delete = NULL;
3887 }
3888 if (cur->type == XML_TEXT_NODE) {
3889 if (IS_BLANK_NODE(cur)) {
3890 if (xmlNodeGetSpacePreserve(cur) != 1) {
3891 delete = cur;
3892 }
3893 }
3894 } else if ((cur->type != XML_ELEMENT_NODE) &&
3895 (cur->type != XML_CDATA_SECTION_NODE)) {
3896 delete = cur;
3897 goto skip_children;
3898 }
3899
3900 /*
3901 * Skip to next node
3902 */
3903 if (cur->children != NULL) {
3904 if ((cur->children->type != XML_ENTITY_DECL) &&
3905 (cur->children->type != XML_ENTITY_REF_NODE) &&
3906 (cur->children->type != XML_ENTITY_NODE)) {
3907 cur = cur->children;
3908 continue;
3909 }
3910 }
3911skip_children:
3912 if (cur->next != NULL) {
3913 cur = cur->next;
3914 continue;
3915 }
3916
3917 do {
3918 cur = cur->parent;
3919 if (cur == NULL)
3920 break;
3921 if (cur == root) {
3922 cur = NULL;
3923 break;
3924 }
3925 if (cur->next != NULL) {
3926 cur = cur->next;
3927 break;
3928 }
3929 } while (cur != NULL);
3930 }
3931 if (delete != NULL) {
3932 xmlUnlinkNode(delete);
3933 xmlFreeNode(delete);
3934 delete = NULL;
3935 }
3936
3937 /*
3938 * Then do the parsing for good
3939 */
3940 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00003941 if (ret == NULL)
3942 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003943 ret->doc = doc;
3944
3945 /*
3946 * Then fix all the references.
3947 */
3948 ctxt->schema = ret;
3949 xmlHashScanFull(ret->elemDecl,
3950 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
3951
3952 /*
3953 * Then fixup all types properties
3954 */
3955 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
3956
3957 /*
3958 * Then build the content model for all elements
3959 */
3960 xmlHashScan(ret->elemDecl,
3961 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
3962
3963 /*
3964 * Then check the defaults part of the type like facets values
3965 */
3966 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
3967
3968 /*
3969 * Then fixup all attributes declarations
3970 */
3971 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
3972
Daniel Veillard13e04c62002-04-23 17:51:29 +00003973 /*
3974 * Then fixup all attributes group declarations
3975 */
3976 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
3977
Daniel Veillard4255d502002-04-16 15:50:10 +00003978 return (ret);
3979}
3980
3981/**
3982 * xmlSchemaParse:
3983 * @ctxt: a schema validation context
3984 * @URL: the location of the schema
3985 *
3986 * Load, XML parse a schema definition resource and build an internal
3987 * XML Shema struture which can be used to validate instances.
3988 * *WARNING* this interface is highly subject to change
3989 *
3990 * Returns the internal XML Schema structure built from the resource or
3991 * NULL in case of error
3992 */
3993void
3994xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
3995 xmlSchemaValidityErrorFunc err,
3996 xmlSchemaValidityWarningFunc warn, void *ctx) {
3997 if (ctxt == NULL)
3998 return;
3999 ctxt->error = err;
4000 ctxt->warning = warn;
4001 ctxt->userData = ctx;
4002}
4003
4004/************************************************************************
4005 * *
4006 * Simple type validation *
4007 * *
4008 ************************************************************************/
4009
4010/**
4011 * xmlSchemaValidateSimpleValue:
4012 * @ctxt: a schema validation context
4013 * @type: the type declaration
4014 * @value: the value to validate
4015 *
4016 * Validate a value against a simple type
4017 *
4018 * Returns 0 if the value is valid, a positive error code
4019 * number otherwise and -1 in case of internal or API error.
4020 */
4021static int
4022xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4023 xmlSchemaTypePtr type,
4024 xmlChar *value) {
4025 int ret = 0;
4026 /*
4027 * First normalize the value accordingly to Schema Datatype
4028 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4029 */
4030 /*
4031 * Then check the normalized value against the lexical space of the
4032 * type.
4033 */
4034 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4035 if (ctxt->value != NULL) {
4036 xmlSchemaFreeValue(ctxt->value);
4037 ctxt->value = NULL;
4038 }
4039 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4040 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4041 xmlSchemaTypePtr base;
4042 xmlSchemaFacetPtr facet;
4043 int tmp;
4044
4045 base = type->baseType;
4046 if (base != NULL) {
4047 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4048 } else if (type->subtypes != NULL) {
4049
4050 }
4051 /*
4052 * Do not validate facets when working on building the Schemas
4053 */
4054 if (ctxt->schema != NULL) {
4055 if (ret == 0) {
4056 facet = type->facets;
Daniel Veillard88c58912002-04-23 07:12:20 +00004057 if ((type->type == XML_SCHEMA_TYPE_RESTRICTION) &&
4058 (facet != NULL) &&
4059 (facet->type == XML_SCHEMA_FACET_ENUMERATION)) {
4060 while (facet != NULL) {
4061 ret = 1;
4062
4063 tmp = xmlSchemaValidateFacet(base, facet, value,
4064 ctxt->value);
4065 if (tmp == 0) {
4066 ret = 0;
4067 break;
4068 }
4069 facet = facet->next;
4070 }
4071 } else {
4072 while (facet != NULL) {
4073 tmp = xmlSchemaValidateFacet(base, facet, value,
4074 ctxt->value);
4075 if (tmp != 0)
4076 ret = tmp;
4077 facet = facet->next;
4078 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004079 }
4080 }
4081 }
4082 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4083 xmlSchemaTypePtr base;
4084
4085 base = type->subtypes;
4086 if (base != NULL) {
4087 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4088 } else {
4089 TODO
4090 }
4091 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4092 xmlSchemaTypePtr base;
4093 xmlChar *cur, *end, tmp;
4094 int ret2;
4095
4096 base = type->subtypes;
4097 if (base == NULL) {
4098 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4099 if (ctxt->error != NULL) {
4100 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4101 ctxt->error(ctxt->userData,
4102 "Internal: List type %s has no base type\n",
4103 type->name);
4104 }
4105 return(-1);
4106 }
4107 cur = value;
4108 do {
4109 while (IS_BLANK(*cur)) cur++;
4110 end = cur;
4111 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4112 if (end == cur)
4113 break;
4114 tmp = *end;
4115 *end = 0;
4116 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4117 if (ret2 != 0)
4118 ret = 1;
4119 *end = tmp;
4120 cur = end;
4121 } while (*cur != 0);
4122 } else {
4123 TODO
4124 }
4125 return(ret);
4126}
4127
4128/************************************************************************
4129 * *
4130 * DOM Validation code *
4131 * *
4132 ************************************************************************/
4133
4134static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4135 xmlNodePtr node);
4136static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4137 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4138static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4139 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4140
4141/**
4142 * xmlSchemaRegisterAttributes:
4143 * @ctxt: a schema validation context
4144 * @attrs: a list of attributes
4145 *
4146 * Register the list of attributes as the set to be validated on that element
4147 *
4148 * Returns -1 in case of error, 0 otherwise
4149 */
4150static int
4151xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4152 xmlAttrPtr attrs) {
4153 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004154 if ((attrs->ns != NULL) &&
4155 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4156 attrs = attrs->next;
4157 continue;
4158 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004159 if (ctxt->attrNr >= ctxt->attrMax) {
4160 xmlSchemaAttrStatePtr tmp;
4161
4162 ctxt->attrMax *= 2;
4163 tmp = (xmlSchemaAttrStatePtr)
4164 xmlRealloc(ctxt->attr, ctxt->attrMax *
4165 sizeof(xmlSchemaAttrState));
4166 if (tmp == NULL) {
4167 ctxt->attrMax /= 2;
4168 return(-1);
4169 }
4170 ctxt->attr = tmp;
4171 }
4172 ctxt->attr[ctxt->attrNr].attr = attrs;
4173 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4174 ctxt->attrNr++;
4175 attrs = attrs->next;
4176 }
4177 return(0);
4178}
4179
4180/**
4181 * xmlSchemaCheckAttributes:
4182 * @ctxt: a schema validation context
4183 * @node: the node carrying it.
4184 *
4185 * Check that the registered set of attributes on the current node
4186 * has been properly validated.
4187 *
4188 * Returns 0 if validity constraints are met, 1 otherwise.
4189 */
4190static int
4191xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4192 int ret = 0;
4193 int i;
4194
4195 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4196 if (ctxt->attr[i].attr == NULL)
4197 break;
4198 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4199 ret = 1;
4200 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
4201 if (ctxt->error != NULL)
4202 ctxt->error(ctxt->userData,
4203 "Attribute %s on %s is unknown\n",
4204 ctxt->attr[i].attr->name,
4205 node->name);
4206 }
4207 }
4208 return(ret);
4209}
4210
4211/**
4212 * xmlSchemaValidateSimpleContent:
4213 * @ctxt: a schema validation context
4214 * @elem: an element
4215 * @type: the type declaration
4216 *
4217 * Validate the content of an element expected to be a simple type
4218 *
4219 * Returns 0 if the element is schemas valid, a positive error code
4220 * number otherwise and -1 in case of internal or API error.
4221 */
4222static int
4223xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004224 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004225 xmlNodePtr child;
4226 xmlSchemaTypePtr type, base;
4227 xmlChar *value;
4228 int ret = 0, tmp;
4229
4230 child = ctxt->node;
4231 type = ctxt->type;
4232
4233 /*
4234 * Validation Rule: Element Locally Valid (Type): 3.1.3
4235 */
4236 value = xmlNodeGetContent(child);
4237 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4238 switch (type->type) {
4239 case XML_SCHEMA_TYPE_RESTRICTION: {
4240 xmlSchemaFacetPtr facet;
4241
4242 base = type->baseType;
4243 if (base != NULL) {
4244 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4245 } else {
4246 TODO
4247 }
4248 if (ret == 0) {
4249 facet = type->facets;
4250 while (facet != NULL) {
4251 tmp = xmlSchemaValidateFacet(base, facet, value,
4252 ctxt->value);
4253 if (tmp != 0)
4254 ret = tmp;
4255 facet = facet->next;
4256 }
4257 }
4258 break;
4259 }
4260 default:
4261 TODO
4262 }
4263 if (value != NULL)
4264 xmlFree(value);
4265
4266 return(ret);
4267}
4268
4269/**
4270 * xmlSchemaValidateCheckNodeList
4271 * @nodelist: the list of nodes
4272 *
4273 * Check the node list is only made of text nodes and entities pointing
4274 * to text nodes
4275 *
4276 * Returns 1 if true, 0 if false and -1 in case of error
4277 */
4278static int
4279xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4280 while (nodelist != NULL) {
4281 if (nodelist->type == XML_ENTITY_REF_NODE) {
4282 TODO /* implement recursion in the entity content */
4283 }
4284 if ((nodelist->type != XML_TEXT_NODE) &&
4285 (nodelist->type != XML_COMMENT_NODE) &&
4286 (nodelist->type != XML_PI_NODE) &&
4287 (nodelist->type != XML_PI_NODE)) {
4288 return(0);
4289 }
4290 nodelist = nodelist->next;
4291 }
4292 return(1);
4293}
4294
4295/**
4296 * xmlSchemaSkipIgnored:
4297 * @ctxt: a schema validation context
4298 * @type: the current type context
4299 * @node: the top node.
4300 *
4301 * Skip ignorable nodes in that context
4302 *
4303 * Returns the new sibling
4304 * number otherwise and -1 in case of internal or API error.
4305 */
4306static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004307xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004308 xmlSchemaTypePtr type,
4309 xmlNodePtr node) {
4310 int mixed = 0;
4311 /*
4312 * TODO complete and handle entities
4313 */
4314 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4315 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4316 while ((node != NULL) &&
4317 ((node->type == XML_COMMENT_NODE) ||
4318 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4319 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4320 (node->type == XML_TEXT_NODE) &&
4321 (IS_BLANK_NODE(node)))))) {
4322 node = node->next;
4323 }
4324 return(node);
4325}
4326
4327/**
4328 * xmlSchemaValidateCallback:
4329 * @ctxt: a schema validation context
4330 * @name: the name of the element detected (might be NULL)
4331 * @type: the type
4332 *
4333 * A transition has been made in the automata associated to an element
4334 * content model
4335 */
4336static void
4337xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004338 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004339 xmlSchemaTypePtr type,
4340 xmlNodePtr node) {
4341 xmlSchemaTypePtr oldtype = ctxt->type;
4342 xmlNodePtr oldnode = ctxt->node;
4343#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004344 xmlGenericError(xmlGenericErrorContext,
4345 "xmlSchemaValidateCallback: %s, %s, %s\n",
4346 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004347#endif
4348 ctxt->type = type;
4349 ctxt->node = node;
4350 xmlSchemaValidateContent(ctxt, node);
4351 ctxt->type = oldtype;
4352 ctxt->node = oldnode;
4353}
4354
4355
4356#if 0
4357/**
4358 * xmlSchemaValidateSimpleRestrictionType:
4359 * @ctxt: a schema validation context
4360 * @node: the top node.
4361 *
4362 * Validate the content of a restriction type.
4363 *
4364 * Returns 0 if the element is schemas valid, a positive error code
4365 * number otherwise and -1 in case of internal or API error.
4366 */
4367static int
4368xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4369 xmlNodePtr node)
4370{
4371 xmlNodePtr child;
4372 xmlSchemaTypePtr type;
4373 int ret;
4374
4375 child = ctxt->node;
4376 type = ctxt->type;
4377
4378 if ((ctxt == NULL) || (type == NULL)) {
4379 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4380 if (ctxt->error != NULL)
4381 ctxt->error(ctxt->userData,
4382 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4383 node->name);
4384 return (-1);
4385 }
4386 /*
4387 * Only text and text based entities references shall be found there
4388 */
4389 ret = xmlSchemaValidateCheckNodeList(child);
4390 if (ret < 0) {
4391 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4392 if (ctxt->error != NULL)
4393 ctxt->error(ctxt->userData,
4394 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4395 node->name);
4396 return (-1);
4397 } else if (ret == 0) {
4398 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4399 if (ctxt->error != NULL)
4400 ctxt->error(ctxt->userData,
4401 "Element %s content is not a simple type\n",
4402 node->name);
4403 return (-1);
4404 }
4405 ctxt->type = type->subtypes;
4406 xmlSchemaValidateContent(ctxt, node);
4407 ctxt->type = type;
4408 return (ret);
4409}
4410#endif
4411
4412/**
4413 * xmlSchemaValidateSimpleType:
4414 * @ctxt: a schema validation context
4415 * @node: the top node.
4416 *
4417 * Validate the content of an simple type.
4418 *
4419 * Returns 0 if the element is schemas valid, a positive error code
4420 * number otherwise and -1 in case of internal or API error.
4421 */
4422static int
4423xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4424 xmlNodePtr child;
4425 xmlSchemaTypePtr type;
4426 xmlAttrPtr attr;
4427 int ret;
4428
4429 child = ctxt->node;
4430 type = ctxt->type;
4431
4432 if ((ctxt == NULL) || (type == NULL)) {
4433 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4434 if (ctxt->error != NULL)
4435 ctxt->error(ctxt->userData,
4436 "Internal error: xmlSchemaValidateSimpleType %s\n",
4437 node->name);
4438 return(-1);
4439 }
4440 /*
4441 * Only text and text based entities references shall be found there
4442 */
4443 ret = xmlSchemaValidateCheckNodeList(child);
4444 if (ret < 0) {
4445 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4446 if (ctxt->error != NULL)
4447 ctxt->error(ctxt->userData,
4448 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4449 node->name);
4450 return(-1);
4451 } else if (ret == 0) {
4452 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4453 if (ctxt->error != NULL)
4454 ctxt->error(ctxt->userData,
4455 "Element %s content is not a simple type\n",
4456 node->name);
4457 return(-1);
4458 }
4459 /*
4460 * Validation Rule: Element Locally Valid (Type): 3.1.1
4461 */
4462 attr = node->properties;
4463 while (attr != NULL) {
4464 if ((attr->ns == NULL) ||
4465 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4466 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4467 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4468 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4469 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4470 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4471 if (ctxt->error != NULL)
4472 ctxt->error(ctxt->userData,
4473 "Element %s: attribute %s should not be present\n",
4474 child->name, attr->name);
4475 return(ctxt->err);
4476 }
4477 }
4478
4479 ctxt->type = type->subtypes;
4480 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4481 ctxt->type = type;
4482 return(ret);
4483}
4484
4485/**
4486 * xmlSchemaValidateElementType:
4487 * @ctxt: a schema validation context
4488 * @node: the top node.
4489 *
4490 * Validate the content of an element type.
4491 * Validation Rule: Element Locally Valid (Complex Type)
4492 *
4493 * Returns 0 if the element is schemas valid, a positive error code
4494 * number otherwise and -1 in case of internal or API error.
4495 */
4496static int
4497xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4498 xmlNodePtr child;
4499 xmlSchemaTypePtr type;
4500 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4501 xmlSchemaElementPtr decl;
4502 int ret, attrBase;
4503
4504 oldregexp = ctxt->regexp;
4505
4506 child = ctxt->node;
4507 type = ctxt->type;
4508
4509 if ((ctxt == NULL) || (type == NULL)) {
4510 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4511 if (ctxt->error != NULL)
4512 ctxt->error(ctxt->userData,
4513 "Internal error: xmlSchemaValidateElementType\n",
4514 node->name);
4515 return(-1);
4516 }
4517 if (child == NULL) {
4518 if (type->minOccurs > 0) {
4519 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4520 if (ctxt->error != NULL)
4521 ctxt->error(ctxt->userData,
4522 "Element %s: missing child %s\n",
4523 node->name, type->name);
4524 }
4525 return(ctxt->err);
4526 }
4527
4528 /*
4529 * Verify the element matches
4530 */
4531 if (!xmlStrEqual(child->name, type->name)) {
4532 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4533 if (ctxt->error != NULL)
4534 ctxt->error(ctxt->userData,
4535 "Element %s: missing child %s found %s\n",
4536 node->name, type->name, child->name);
4537 return(ctxt->err);
4538 }
4539 /*
4540 * Verify the attributes
4541 */
4542 attrBase = ctxt->attrBase;
4543 ctxt->attrBase = ctxt->attrNr;
4544 xmlSchemaRegisterAttributes(ctxt, child->properties);
4545 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4546 /*
4547 * Verify the element content recursively
4548 */
4549 decl = (xmlSchemaElementPtr) type;
4550 oldregexp = ctxt->regexp;
4551 if (decl->contModel != NULL) {
4552 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4553 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4554 ctxt);
4555#ifdef DEBUG_AUTOMATA
4556 xmlGenericError(xmlGenericErrorContext,
4557 "====> %s\n", node->name);
4558#endif
4559 }
4560 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4561 type->subtypes);
4562
4563 if (decl->contModel != NULL) {
4564 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4565#ifdef DEBUG_AUTOMATA
4566 xmlGenericError(xmlGenericErrorContext,
4567 "====> %s : %d\n", node->name, ret);
4568#endif
4569 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004570 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004571 if (ctxt->error != NULL)
4572 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4573 node->name);
4574 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004575 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004576 if (ctxt->error != NULL)
4577 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4578 node->name);
4579#ifdef DEBUG_CONTENT
4580 } else {
4581 xmlGenericError(xmlGenericErrorContext,
4582 "Element %s content check succeeded\n", node->name);
4583
4584#endif
4585 }
4586 xmlRegFreeExecCtxt(ctxt->regexp);
4587 }
4588 /*
4589 * Verify that all attributes were Schemas-validated
4590 */
4591 xmlSchemaCheckAttributes(ctxt, node);
4592 ctxt->attrNr = ctxt->attrBase;
4593 ctxt->attrBase = attrBase;
4594
4595 ctxt->regexp = oldregexp;
4596
4597 ctxt->node = child;
4598 ctxt->type = type;
4599 return(ctxt->err);
4600}
4601
4602/**
4603 * xmlSchemaValidateBasicType:
4604 * @ctxt: a schema validation context
4605 * @node: the top node.
4606 *
4607 * Validate the content of an element expected to be a basic type type
4608 *
4609 * Returns 0 if the element is schemas valid, a positive error code
4610 * number otherwise and -1 in case of internal or API error.
4611 */
4612static int
4613xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4614 int ret;
4615 xmlNodePtr child, cur;
4616 xmlSchemaTypePtr type;
4617 xmlChar *value; /* lexical representation */
4618
4619 child = ctxt->node;
4620 type = ctxt->type;
4621
4622 if ((ctxt == NULL) || (type == NULL)) {
4623 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4624 if (ctxt->error != NULL)
4625 ctxt->error(ctxt->userData,
4626 "Internal error: xmlSchemaValidateBasicType\n",
4627 node->name);
4628 return(-1);
4629 }
4630 /*
4631 * First check the content model of the node.
4632 */
4633 cur = child;
4634 while (cur != NULL) {
4635 switch (cur->type) {
4636 case XML_TEXT_NODE:
4637 case XML_CDATA_SECTION_NODE:
4638 case XML_PI_NODE:
4639 case XML_COMMENT_NODE:
4640 case XML_XINCLUDE_START:
4641 case XML_XINCLUDE_END:
4642 break;
4643 case XML_ENTITY_REF_NODE:
4644 case XML_ENTITY_NODE:
4645 TODO
4646 break;
4647 case XML_ELEMENT_NODE:
4648 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4649 if (ctxt->error != NULL)
4650 ctxt->error(ctxt->userData,
4651 "Element %s: child %s should not be present\n",
4652 node->name, cur->name);
4653 return(ctxt->err);
4654 case XML_ATTRIBUTE_NODE:
4655 case XML_DOCUMENT_NODE:
4656 case XML_DOCUMENT_TYPE_NODE:
4657 case XML_DOCUMENT_FRAG_NODE:
4658 case XML_NOTATION_NODE:
4659 case XML_HTML_DOCUMENT_NODE:
4660 case XML_DTD_NODE:
4661 case XML_ELEMENT_DECL:
4662 case XML_ATTRIBUTE_DECL:
4663 case XML_ENTITY_DECL:
4664 case XML_NAMESPACE_DECL:
4665#ifdef LIBXML_DOCB_ENABLED
4666 case XML_DOCB_DOCUMENT_NODE:
4667#endif
4668 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4669 if (ctxt->error != NULL)
4670 ctxt->error(ctxt->userData,
4671 "Element %s: node type %d unexpected here\n",
4672 node->name, cur->type);
4673 return(ctxt->err);
4674 }
4675 cur = cur->next;
4676 }
4677 if (child == NULL)
4678 value = NULL;
4679 else
4680 value = xmlNodeGetContent(child->parent);
4681
4682 if (ctxt->value != NULL) {
4683 xmlSchemaFreeValue(ctxt->value);
4684 ctxt->value = NULL;
4685 }
4686 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4687 if (value != NULL)
4688 xmlFree(value);
4689 if (ret != 0) {
4690 ctxt->error(ctxt->userData,
4691 "Element %s: failed to validate basic type %s\n",
4692 node->name, type->name);
4693 }
4694 return(ret);
4695}
4696
4697/**
4698 * xmlSchemaValidateComplexType:
4699 * @ctxt: a schema validation context
4700 * @node: the top node.
4701 *
4702 * Validate the content of an element expected to be a complex type type
4703 * xmlschema-1.html#cvc-complex-type
4704 * Validation Rule: Element Locally Valid (Complex Type)
4705 *
4706 * Returns 0 if the element is schemas valid, a positive error code
4707 * number otherwise and -1 in case of internal or API error.
4708 */
4709static int
4710xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4711 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004712 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004713 int ret;
4714
4715 child = ctxt->node;
4716 type = ctxt->type;
4717
Daniel Veillard4255d502002-04-16 15:50:10 +00004718 switch (type->contentType) {
4719 case XML_SCHEMA_CONTENT_EMPTY:
4720 if (child != NULL) {
4721 if (ctxt->error != NULL)
4722 ctxt->error(ctxt->userData,
4723 "Element %s is supposed to be empty\n",
4724 node->name);
4725 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00004726 if (type->attributes != NULL) {
4727 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4728 }
4729 subtype = type->subtypes;
4730 while (subtype != NULL) {
4731 ctxt->type = subtype;
4732 xmlSchemaValidateComplexType(ctxt, node);
4733 subtype = subtype->next;
4734 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004735 break;
4736 case XML_SCHEMA_CONTENT_ELEMENTS:
4737 case XML_SCHEMA_CONTENT_MIXED:
4738 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4739 /*
4740 * Skip ignorable nodes in that context
4741 */
4742 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00004743 while (child != NULL) {
4744 if (child->type == XML_ELEMENT_NODE) {
4745 ret = xmlRegExecPushString(ctxt->regexp,
4746 child->name, child);
4747#ifdef DEBUG_AUTOMATA
4748 if (ret < 0)
4749 xmlGenericError(xmlGenericErrorContext,
4750 " --> %s Error\n", child->name);
4751 else
4752 xmlGenericError(xmlGenericErrorContext,
4753 " --> %s\n", child->name);
4754#endif
4755 }
4756 child = child->next;
4757 /*
4758 * Skip ignorable nodes in that context
4759 */
4760 child = xmlSchemaSkipIgnored(ctxt, type, child);
4761 }
4762 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004763 case XML_SCHEMA_CONTENT_BASIC: {
4764 if (type->subtypes != NULL) {
4765 ctxt->type = type->subtypes;
4766 xmlSchemaValidateComplexType(ctxt, node);
4767 }
4768 if (type->baseType != NULL) {
4769 ctxt->type = type->baseType;
4770 xmlSchemaValidateBasicType(ctxt, node);
4771 }
4772 if (type->attributes != NULL) {
4773 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4774 }
4775 ctxt->type = type;
4776 break;
4777 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004778 default:
4779 TODO
4780 xmlGenericError(xmlGenericErrorContext,
4781 "unimplemented content type %d\n",
4782 type->contentType);
4783 }
4784 return(ctxt->err);
4785}
4786
4787/**
4788 * xmlSchemaValidateContent:
4789 * @ctxt: a schema validation context
4790 * @elem: an element
4791 * @type: the type declaration
4792 *
4793 * Validate the content of an element against the type.
4794 *
4795 * Returns 0 if the element is schemas valid, a positive error code
4796 * number otherwise and -1 in case of internal or API error.
4797 */
4798static int
4799xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4800 xmlNodePtr child;
4801 xmlSchemaTypePtr type;
4802
4803 child = ctxt->node;
4804 type = ctxt->type;
4805
Daniel Veillarde19fc232002-04-22 16:01:24 +00004806 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4807
Daniel Veillard4255d502002-04-16 15:50:10 +00004808 switch (type->type) {
4809 case XML_SCHEMA_TYPE_ANY:
4810 /* Any type will do it, fine */
4811 TODO /* handle recursivity */
4812 break;
4813 case XML_SCHEMA_TYPE_COMPLEX:
4814 xmlSchemaValidateComplexType(ctxt, node);
4815 break;
4816 case XML_SCHEMA_TYPE_ELEMENT: {
4817 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
4818 /*
4819 * Handle element reference here
4820 */
4821 if (decl->ref != NULL) {
4822 if (decl->refDecl == NULL) {
4823 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4824 if (ctxt->error != NULL)
4825 ctxt->error(ctxt->userData,
4826 "Internal error: element reference %s not resolved\n",
4827 decl->ref);
4828 return(-1);
4829 }
4830 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
4831 decl = decl->refDecl;
4832 }
4833 xmlSchemaValidateElementType(ctxt, node);
4834 ctxt->type = type;
4835 break;
4836 }
4837 case XML_SCHEMA_TYPE_BASIC:
4838 xmlSchemaValidateBasicType(ctxt, node);
4839 break;
4840 case XML_SCHEMA_TYPE_FACET:
4841 TODO
4842 break;
4843 case XML_SCHEMA_TYPE_SIMPLE:
4844 xmlSchemaValidateSimpleType(ctxt, node);
4845 break;
4846 case XML_SCHEMA_TYPE_SEQUENCE:
4847 TODO
4848 break;
4849 case XML_SCHEMA_TYPE_CHOICE:
4850 TODO
4851 break;
4852 case XML_SCHEMA_TYPE_ALL:
4853 TODO
4854 break;
4855 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
4856 TODO
4857 break;
4858 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4859 TODO
4860 break;
4861 case XML_SCHEMA_TYPE_UR:
4862 TODO
4863 break;
4864 case XML_SCHEMA_TYPE_RESTRICTION:
4865 /*xmlSchemaValidateRestrictionType(ctxt, node); */
4866 TODO
4867 break;
4868 case XML_SCHEMA_TYPE_EXTENSION:
4869 TODO
4870 break;
4871 case XML_SCHEMA_TYPE_ATTRIBUTE:
4872 TODO
4873 break;
4874 case XML_SCHEMA_TYPE_GROUP:
4875 TODO
4876 break;
4877 case XML_SCHEMA_TYPE_NOTATION:
4878 TODO
4879 break;
4880 case XML_SCHEMA_TYPE_LIST:
4881 TODO
4882 break;
4883 case XML_SCHEMA_TYPE_UNION:
4884 TODO
4885 break;
4886 case XML_SCHEMA_FACET_MININCLUSIVE:
4887 TODO
4888 break;
4889 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4890 TODO
4891 break;
4892 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4893 TODO
4894 break;
4895 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4896 TODO
4897 break;
4898 case XML_SCHEMA_FACET_TOTALDIGITS:
4899 TODO
4900 break;
4901 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4902 TODO
4903 break;
4904 case XML_SCHEMA_FACET_PATTERN:
4905 TODO
4906 break;
4907 case XML_SCHEMA_FACET_ENUMERATION:
4908 TODO
4909 break;
4910 case XML_SCHEMA_FACET_WHITESPACE:
4911 TODO
4912 break;
4913 case XML_SCHEMA_FACET_LENGTH:
4914 TODO
4915 break;
4916 case XML_SCHEMA_FACET_MAXLENGTH:
4917 TODO
4918 break;
4919 case XML_SCHEMA_FACET_MINLENGTH:
4920 TODO
4921 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00004922 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4923 TODO
4924 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004925 }
4926 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4927
4928 if (ctxt->node == NULL)
4929 return(ctxt->err);
4930 ctxt->node = ctxt->node->next;
4931 ctxt->type = type->next;
4932 return(ctxt->err);
4933}
4934
4935/**
4936 * xmlSchemaValidateType:
4937 * @ctxt: a schema validation context
4938 * @elem: an element
4939 * @type: the list of type declarations
4940 *
4941 * Validate the content of an element against the types.
4942 *
4943 * Returns 0 if the element is schemas valid, a positive error code
4944 * number otherwise and -1 in case of internal or API error.
4945 */
4946static int
4947xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4948 xmlSchemaElementPtr elemDecl,
4949 xmlSchemaTypePtr type) {
4950 xmlChar *nil;
4951
4952 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
4953 return(0);
4954 /*
4955 * 3.3.4 : 2
4956 */
4957 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
4958 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
4959 if (ctxt->error != NULL)
4960 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
4961 return(ctxt->err);
4962 }
4963 /*
4964 * 3.3.4: 3
4965 */
4966 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
4967 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
4968 /* 3.3.4: 3.2 */
4969 if (xmlStrEqual(nil, BAD_CAST "true")) {
4970 if (elem->children != NULL) {
4971 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
4972 if (ctxt->error != NULL)
4973 ctxt->error(ctxt->userData, "Element %s is not empty\n",
4974 elem->name);
4975 return(ctxt->err);
4976 }
4977 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
4978 (elemDecl->value != NULL)) {
4979 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
4980 if (ctxt->error != NULL)
4981 ctxt->error(ctxt->userData,
4982 "Empty element %s cannot get a fixed value\n",
4983 elem->name);
4984 return(ctxt->err);
4985 }
4986 }
4987 } else {
4988 /* 3.3.4: 3.1 */
4989 if (nil != NULL) {
4990 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
4991 if (ctxt->error != NULL)
4992 ctxt->error(ctxt->userData,
4993 "Element %s with xs:nil but not nillable\n",
4994 elem->name);
4995 xmlFree(nil);
4996 return(ctxt->err);
4997 }
4998 }
4999
5000 /* TODO 3.3.4: 4 if the element carries xs:type*/
5001
5002 ctxt->type = elemDecl->subtypes;
5003 ctxt->node = elem->children;
5004 xmlSchemaValidateContent(ctxt, elem);
5005 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5006
5007 return(ctxt->err);
5008}
5009
5010
5011/**
5012 * xmlSchemaValidateAttributes:
5013 * @ctxt: a schema validation context
5014 * @elem: an element
5015 * @attributes: the list of attribute declarations
5016 *
5017 * Validate the attributes of an element.
5018 *
5019 * Returns 0 if the element is schemas valid, a positive error code
5020 * number otherwise and -1 in case of internal or API error.
5021 */
5022static int
5023xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5024 xmlSchemaAttributePtr attributes) {
5025 int i, ret;
5026 xmlAttrPtr attr;
5027 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005028 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005029
5030 if (attributes == NULL)
5031 return(0);
5032 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005033 /*
5034 * Handle attribute groups
5035 */
5036 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5037 group = (xmlSchemaAttributeGroupPtr) attributes;
5038 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5039 attributes = group->next;
5040 continue;
5041 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005042 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5043 attr = ctxt->attr[i].attr;
5044 if (attr == NULL)
5045 continue;
5046 if (!xmlStrEqual(attr->name, attributes->name))
5047 continue;
5048 /*
5049 * TODO: handle the mess about namespaces here.
5050 */
5051 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5052 TODO
5053 }
5054 if (attributes->subtypes == NULL) {
5055 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5056 if (ctxt->error != NULL)
5057 ctxt->error(ctxt->userData,
5058 "Internal error: attribute %s type not resolved\n",
5059 attr->name);
5060 continue;
5061 }
5062 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5063 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005064 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005065 if (ret != 0) {
5066 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5067 if (ctxt->error != NULL)
5068 ctxt->error(ctxt->userData,
5069 "attribute %s on %s does not match type\n",
5070 attr->name, elem->name);
5071 } else {
5072 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5073 }
5074 if (value != NULL) {
5075 xmlFree(value);
5076 }
5077 }
5078 attributes = attributes->next;
5079 }
5080 return(ctxt->err);
5081}
5082
5083/**
5084 * xmlSchemaValidateElement:
5085 * @ctxt: a schema validation context
5086 * @elem: an element
5087 *
5088 * Validate an element in a tree
5089 *
5090 * Returns 0 if the element is schemas valid, a positive error code
5091 * number otherwise and -1 in case of internal or API error.
5092 */
5093static int
5094xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5095 xmlSchemaElementPtr elemDecl;
5096 int ret, attrBase;
5097
5098 if (elem->ns != NULL)
5099 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5100 elem->name, elem->ns->href, NULL);
5101 else
5102 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5103 elem->name, NULL, NULL);
5104 /*
5105 * 3.3.4 : 1
5106 */
5107 if (elemDecl == NULL) {
5108 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5109 if (ctxt->error != NULL)
5110 ctxt->error(ctxt->userData, "Element %s not declared\n",
5111 elem->name);
5112 return(ctxt->err);
5113 }
5114 if (elemDecl->subtypes == NULL) {
5115 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5116 if (ctxt->error != NULL)
5117 ctxt->error(ctxt->userData, "Element %s has no type\n",
5118 elem->name);
5119 return(ctxt->err);
5120 }
5121 /*
5122 * Verify the attributes
5123 */
5124 attrBase = ctxt->attrBase;
5125 ctxt->attrBase = ctxt->attrNr;
5126 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5127 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5128 /*
5129 * Verify the element content recursively
5130 */
5131 if (elemDecl->contModel != NULL) {
5132 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5133 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5134 ctxt);
5135#ifdef DEBUG_AUTOMATA
5136 xmlGenericError(xmlGenericErrorContext,
5137 "====> %s\n", elem->name);
5138#endif
5139 }
5140 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005141 if (elemDecl->contModel != NULL) {
5142 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005143#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005144 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005145 "====> %s : %d\n", elem->name, ret);
5146#endif
5147 if (ret == 0) {
5148 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5149 if (ctxt->error != NULL)
5150 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5151 elem->name);
5152 } else if (ret < 0) {
5153 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5154 if (ctxt->error != NULL)
5155 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5156 elem->name);
5157#ifdef DEBUG_CONTENT
5158 } else {
5159 xmlGenericError(xmlGenericErrorContext,
5160 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005161
5162#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005163 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005164 xmlRegFreeExecCtxt(ctxt->regexp);
5165 }
5166 /*
5167 * Verify that all attributes were Schemas-validated
5168 */
5169 xmlSchemaCheckAttributes(ctxt, elem);
5170 ctxt->attrNr = ctxt->attrBase;
5171 ctxt->attrBase = attrBase;
5172
5173 return(ctxt->err);
5174}
5175
5176/**
5177 * xmlSchemaValidateDocument:
5178 * @ctxt: a schema validation context
5179 * @doc: a parsed document tree
5180 *
5181 * Validate a document tree in memory.
5182 *
5183 * Returns 0 if the document is schemas valid, a positive error code
5184 * number otherwise and -1 in case of internal or API error.
5185 */
5186static int
5187xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5188 xmlNodePtr root;
5189 xmlSchemaElementPtr elemDecl;
5190
5191 root = xmlDocGetRootElement(doc);
5192 if (root == NULL) {
5193 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
5194 if (ctxt->error != NULL)
5195 ctxt->error(ctxt->userData, "document has no root\n");
5196 return(ctxt->err);
5197 }
5198 if (root->ns != NULL)
5199 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5200 root->name, root->ns->href, NULL);
5201 else
5202 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5203 root->name, NULL, NULL);
5204 if (elemDecl == NULL) {
5205 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5206 if (ctxt->error != NULL)
5207 ctxt->error(ctxt->userData, "Element %s not declared\n",
5208 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005209 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005210 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
5211 if (ctxt->error != NULL)
5212 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5213 root->name);
5214 }
5215 /*
5216 * Okay, start the recursive validation
5217 */
5218 xmlSchemaValidateElement(ctxt, root);
5219
5220 return(ctxt->err);
5221}
5222
5223/************************************************************************
5224 * *
5225 * SAX Validation code *
5226 * *
5227 ************************************************************************/
5228
5229/************************************************************************
5230 * *
5231 * Validation interfaces *
5232 * *
5233 ************************************************************************/
5234
5235/**
5236 * xmlSchemaNewValidCtxt:
5237 * @schema: a precompiled XML Schemas
5238 *
5239 * Create an XML Schemas validation context based on the given schema
5240 *
5241 * Returns the validation context or NULL in case of error
5242 */
5243xmlSchemaValidCtxtPtr
5244xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5245 xmlSchemaValidCtxtPtr ret;
5246
5247 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5248 if (ret == NULL) {
5249 xmlGenericError(xmlGenericErrorContext,
5250 "Failed to allocate new schama validation context\n");
5251 return (NULL);
5252 }
5253 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5254 ret->schema = schema;
5255 ret->attrNr = 0;
5256 ret->attrMax = 10;
5257 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5258 sizeof(xmlSchemaAttrState));
5259 if (ret->attr == NULL) {
5260 free(ret);
5261 return(NULL);
5262 }
5263 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5264 return (ret);
5265}
5266
5267/**
5268 * xmlSchemaFreeValidCtxt:
5269 * @ctxt: the schema validation context
5270 *
5271 * Free the resources associated to the schema validation context
5272 */
5273void
5274xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5275 if (ctxt == NULL)
5276 return;
5277 if (ctxt->attr != NULL)
5278 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005279 if (ctxt->value != NULL)
5280 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005281 xmlFree(ctxt);
5282}
5283
5284/**
5285 * xmlSchemaSetValidErrors:
5286 * @ctxt: a schema validation context
5287 * @err: the error function
5288 * @warn: the warning function
5289 * @ctxt: the functions context
5290 *
5291 * Set the error and warning callback informations
5292 */
5293void
5294xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5295 xmlSchemaValidityErrorFunc err,
5296 xmlSchemaValidityWarningFunc warn, void *ctx) {
5297 if (ctxt == NULL)
5298 return;
5299 ctxt->error = err;
5300 ctxt->warning = warn;
5301 ctxt->userData = ctx;
5302}
5303
5304/**
5305 * xmlSchemaValidateDoc:
5306 * @ctxt: a schema validation context
5307 * @doc: a parsed document tree
5308 *
5309 * Validate a document tree in memory.
5310 *
5311 * Returns 0 if the document is schemas valid, a positive error code
5312 * number otherwise and -1 in case of internal or API error.
5313 */
5314int
5315xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5316 int ret;
5317
5318 if ((ctxt == NULL) || (doc == NULL))
5319 return(-1);
5320
5321 ctxt->doc = doc;
5322 ret = xmlSchemaValidateDocument(ctxt, doc);
5323 return(ret);
5324}
5325
5326/**
5327 * xmlSchemaValidateStream:
5328 * @ctxt: a schema validation context
5329 * @input: the input to use for reading the data
5330 * @enc: an optional encoding information
5331 * @sax: a SAX handler for the resulting events
5332 * @user_data: the context to provide to the SAX handler.
5333 *
5334 * Validate a document tree in memory.
5335 *
5336 * Returns 0 if the document is schemas valid, a positive error code
5337 * number otherwise and -1 in case of internal or API error.
5338 */
5339int
5340xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5341 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5342 xmlSAXHandlerPtr sax, void *user_data) {
5343 if ((ctxt == NULL) || (input == NULL))
5344 return(-1);
5345 ctxt->input = input;
5346 ctxt->enc = enc;
5347 ctxt->sax = sax;
5348 ctxt->user_data = user_data;
5349 TODO
5350 return(0);
5351}
5352
5353#endif /* LIBXML_SCHEMAS_ENABLED */