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