blob: 721f3263bf063607e7faf92bacca247fcc38faac [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);
3168
Daniel Veillard4255d502002-04-16 15:50:10 +00003169 } else {
3170 if (elem->refDecl != NULL) {
3171 xmlSchemaBuildAContentModel(
3172 (xmlSchemaTypePtr) elem->refDecl,
3173 ctxt, elem->refDecl->name);
3174 } else {
3175 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3176 ctxt->state, NULL, elem->name, type);
3177 }
3178 if (elem->minOccurs == 0) {
3179 /* basically an elem? */
3180 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3181 }
3182 }
3183 break;
3184 }
3185 case XML_SCHEMA_TYPE_SEQUENCE: {
3186 xmlSchemaTypePtr subtypes;
3187
3188 /*
3189 * Simply iterate over the subtypes
3190 */
3191 subtypes = type->subtypes;
3192 while (subtypes != NULL) {
3193 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3194 subtypes = subtypes->next;
3195 }
3196 break;
3197 }
3198 case XML_SCHEMA_TYPE_CHOICE: {
3199 xmlSchemaTypePtr subtypes;
3200 xmlAutomataStatePtr start, end;
3201
3202 start = ctxt->state;
3203 end = xmlAutomataNewState(ctxt->am);
3204
3205 /*
3206 * iterate over the subtypes and remerge the end with an
3207 * epsilon transition
3208 */
Daniel Veillardb509f152002-04-17 16:28:10 +00003209 if (type->maxOccurs == 1) {
3210 subtypes = type->subtypes;
3211 while (subtypes != NULL) {
3212 ctxt->state = start;
3213 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3214 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3215 subtypes = subtypes->next;
3216 }
3217 } else {
3218 int counter;
3219 xmlAutomataStatePtr hop;
3220
3221 /*
3222 * use a counter to keep track of the number of transtions
3223 * which went through the choice.
3224 */
3225 if (type->minOccurs < 1) {
3226 counter = xmlAutomataNewCounter(ctxt->am, 0,
3227 type->maxOccurs - 1);
3228 } else {
3229 counter = xmlAutomataNewCounter(ctxt->am,
3230 type->minOccurs - 1, type->maxOccurs - 1);
3231 }
3232 hop = xmlAutomataNewState(ctxt->am);
3233
3234 subtypes = type->subtypes;
3235 while (subtypes != NULL) {
3236 ctxt->state = start;
3237 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3238 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3239 subtypes = subtypes->next;
3240 }
3241 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3242 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3243 }
3244 if (type->minOccurs == 0) {
3245 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003246 }
3247 ctxt->state = end;
3248 break;
3249 }
3250 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003251 xmlAutomataStatePtr start;
3252 xmlSchemaTypePtr subtypes;
3253 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard441bc322002-04-20 17:38:48 +00003254 int lax;
Daniel Veillard7646b182002-04-20 06:41:40 +00003255
3256 subtypes = type->subtypes;
3257 if (subtypes == NULL)
3258 break;
3259 start = ctxt->state;
3260 while (subtypes != NULL) {
3261 ctxt->state = start;
3262 elem = (xmlSchemaElementPtr) subtypes;
3263
3264 /* TODO : handle the namespace too */
3265 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3266 elem->name, elem->minOccurs, elem->maxOccurs,
3267 subtypes);
3268 subtypes = subtypes->next;
3269 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003270 lax = type->minOccurs == 0;
3271 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3272 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003273 break;
3274 }
3275 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003276 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003277 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3278 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003279 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003280 if (type->baseType != NULL) {
3281 xmlSchemaTypePtr subtypes;
3282
3283 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3284 subtypes = type->subtypes;
3285 while (subtypes != NULL) {
3286 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3287 subtypes = subtypes->next;
3288 }
3289 } else if (type->subtypes != NULL)
3290 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3291 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003292 case XML_SCHEMA_TYPE_GROUP:
3293 case XML_SCHEMA_TYPE_COMPLEX:
3294 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3295 if (type->subtypes != NULL)
3296 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3297 break;
3298 default:
3299 xmlGenericError(xmlGenericErrorContext,
3300 "Found unexpected type %d in %s content model\n",
3301 type->type, name);
3302 return;
3303 }
3304}
3305/**
3306 * xmlSchemaBuildContentModel:
3307 * @typeDecl: the schema type definition
3308 * @ctxt: the schema parser context
3309 *
3310 * Fixes the content model of the element.
3311 */
3312static void
3313xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3314 xmlSchemaParserCtxtPtr ctxt,
3315 const xmlChar *name) {
3316 xmlAutomataStatePtr start;
3317
Daniel Veillard4255d502002-04-16 15:50:10 +00003318 if (elem->contModel != NULL)
3319 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003320 if (elem->subtypes == NULL) {
3321 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003322 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003323 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003324 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3325 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003326 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3327 return;
3328
3329#ifdef DEBUG_CONTENT
3330 xmlGenericError(xmlGenericErrorContext,
3331 "Building content model for %s\n", name);
3332#endif
3333
Daniel Veillard4255d502002-04-16 15:50:10 +00003334 ctxt->am = xmlNewAutomata();
3335 if (ctxt->am == NULL) {
3336 xmlGenericError(xmlGenericErrorContext,
3337 "Cannot create automata for elem %s\n", name);
3338 return;
3339 }
3340 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3341 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3342 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003343 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003344 if (!xmlAutomataIsDeterminist(ctxt->am)) {
3345 xmlGenericError(xmlGenericErrorContext,
3346 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003347 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillard4402ab42002-09-12 16:02:56 +00003348 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003349 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00003350#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillarde19fc232002-04-22 16:01:24 +00003351 xmlGenericError(xmlGenericErrorContext,
3352 "Content model of %s:\n", name);
3353 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003354#endif
Daniel Veillard4402ab42002-09-12 16:02:56 +00003355 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003356 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003357 xmlFreeAutomata(ctxt->am);
3358 ctxt->am = NULL;
3359}
3360
3361/**
3362 * xmlSchemaRefFixupCallback:
3363 * @elem: the schema element context
3364 * @ctxt: the schema parser context
3365 *
3366 * Free the resources associated to the schema parser context
3367 */
3368static void
3369xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3370 xmlSchemaParserCtxtPtr ctxt,
3371 const xmlChar *name,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003372 const xmlChar *context ATTRIBUTE_UNUSED,
3373 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00003374{
3375 if ((ctxt == NULL) || (elem == NULL))
3376 return;
3377 if (elem->ref != NULL) {
3378 xmlSchemaElementPtr elemDecl;
3379
3380 if (elem->subtypes != NULL) {
3381 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3382 if ((ctxt != NULL) && (ctxt->error != NULL))
3383 ctxt->error(ctxt->userData,
3384 "Schemas: element %s have both ref and subtype\n",
3385 name);
3386 return;
3387 }
3388 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3389 elem->ref, elem->refNs);
3390
3391 if (elemDecl == NULL) {
3392 if ((ctxt != NULL) && (ctxt->error != NULL))
3393 ctxt->error(ctxt->userData,
3394 "Schemas: element %s ref to %s not found\n",
3395 name, elem->ref);
3396 return;
3397 }
3398 elem->refDecl = elemDecl;
3399 } else if (elem->namedType != NULL) {
3400 xmlSchemaTypePtr typeDecl;
3401
3402 if (elem->subtypes != NULL) {
3403 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3404 if ((ctxt != NULL) && (ctxt->error != NULL))
3405 ctxt->error(ctxt->userData,
3406 "Schemas: element %s have both type and subtype\n",
3407 name);
3408 return;
3409 }
3410 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3411 elem->namedTypeNs);
3412
3413 if (typeDecl == NULL) {
3414 if ((ctxt != NULL) && (ctxt->error != NULL))
3415 ctxt->error(ctxt->userData,
3416 "Schemas: element %s type %s not found\n",
3417 name, elem->namedType);
3418 return;
3419 }
3420 elem->subtypes = typeDecl;
3421 }
3422}
3423
3424/**
3425 * xmlSchemaTypeFixup:
3426 * @typeDecl: the schema type definition
3427 * @ctxt: the schema parser context
3428 *
3429 * Fixes the content model of the type.
3430 */
3431static void
3432xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3433 xmlSchemaParserCtxtPtr ctxt,
3434 const xmlChar *name)
3435{
3436 if (name == NULL)
3437 name = typeDecl->name;
3438 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3439 switch (typeDecl->type) {
3440 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3441 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3442 typeDecl->contentType = typeDecl->subtypes->contentType;
3443 break;
3444 }
3445 case XML_SCHEMA_TYPE_RESTRICTION: {
3446 if (typeDecl->subtypes != NULL)
3447 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3448
3449 if (typeDecl->base != NULL) {
3450 xmlSchemaTypePtr baseType;
3451
3452 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3453 typeDecl->baseNs);
3454 if (baseType == NULL) {
3455 if ((ctxt != NULL) && (ctxt->error != NULL))
3456 ctxt->error(ctxt->userData,
3457 "Schemas: type %s base type %s not found\n",
3458 name, typeDecl->base);
3459 }
3460 typeDecl->baseType = baseType;
3461 }
3462 if (typeDecl->subtypes == NULL)
3463 /* 1.1.1 */
3464 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3465 else if ((typeDecl->subtypes->subtypes == NULL) &&
3466 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3467 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3468 /* 1.1.2 */
3469 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3470 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3471 (typeDecl->subtypes->subtypes == NULL))
3472 /* 1.1.3 */
3473 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3474 else {
3475 /* 1.2 and 2.X are applied at the other layer */
3476 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3477 }
3478 break;
3479 }
3480 case XML_SCHEMA_TYPE_EXTENSION: {
3481 xmlSchemaContentType explicitContentType;
3482 xmlSchemaTypePtr base;
3483
3484 if (typeDecl->base != NULL) {
3485 xmlSchemaTypePtr baseType;
3486
3487 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3488 typeDecl->baseNs);
3489 if (baseType == NULL) {
3490 if ((ctxt != NULL) && (ctxt->error != NULL))
3491 ctxt->error(ctxt->userData,
3492 "Schemas: type %s base type %s not found\n",
3493 name, typeDecl->base);
3494 }
3495 typeDecl->baseType = baseType;
3496 }
3497 if (typeDecl->subtypes != NULL)
3498 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3499
Daniel Veillard8651f532002-04-17 09:06:27 +00003500 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003501 if (typeDecl->subtypes == NULL)
3502 /* 1.1.1 */
3503 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3504 else if ((typeDecl->subtypes->subtypes == NULL) &&
3505 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3506 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3507 /* 1.1.2 */
3508 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3509 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3510 (typeDecl->subtypes->subtypes == NULL))
3511 /* 1.1.3 */
3512 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3513
3514 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3515 typeDecl->baseNs);
3516 if (base == NULL) {
3517 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3518 if ((ctxt != NULL) && (ctxt->error != NULL))
3519 ctxt->error(ctxt->userData,
3520 "Schemas: base type %s of type %s not found\n",
3521 typeDecl->base, name);
3522 return;
3523 }
3524 xmlSchemaTypeFixup(base, ctxt, NULL);
3525 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3526 /* 2.1 */
3527 typeDecl->contentType = base->contentType;
3528 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3529 /* 2.2 imbitable ! */
3530 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3531 } else {
3532 /* 2.3 imbitable pareil ! */
3533 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3534 }
3535 break;
3536 }
3537 case XML_SCHEMA_TYPE_COMPLEX: {
3538 if (typeDecl->subtypes == NULL) {
3539 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3540 } else {
3541 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3542 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3543 else {
3544 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3545 typeDecl->contentType = typeDecl->subtypes->contentType;
3546 }
3547 }
3548 break;
3549 }
3550 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3551 if (typeDecl->subtypes == NULL) {
3552 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3553 } else {
3554 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3555 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3556 else {
3557 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3558 typeDecl->contentType = typeDecl->subtypes->contentType;
3559 }
3560 }
3561 break;
3562 }
3563 case XML_SCHEMA_TYPE_SEQUENCE:
3564 case XML_SCHEMA_TYPE_GROUP:
3565 case XML_SCHEMA_TYPE_ALL:
3566 case XML_SCHEMA_TYPE_CHOICE:
3567 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3568 break;
3569 case XML_SCHEMA_TYPE_BASIC:
3570 case XML_SCHEMA_TYPE_ANY:
3571 case XML_SCHEMA_TYPE_FACET:
3572 case XML_SCHEMA_TYPE_SIMPLE:
3573 case XML_SCHEMA_TYPE_UR:
3574 case XML_SCHEMA_TYPE_ELEMENT:
3575 case XML_SCHEMA_TYPE_ATTRIBUTE:
Daniel Veillard118aed72002-09-24 14:13:13 +00003576 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
Daniel Veillard4255d502002-04-16 15:50:10 +00003577 case XML_SCHEMA_TYPE_NOTATION:
3578 case XML_SCHEMA_TYPE_LIST:
3579 case XML_SCHEMA_TYPE_UNION:
3580 case XML_SCHEMA_FACET_MININCLUSIVE:
3581 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3582 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3583 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3584 case XML_SCHEMA_FACET_TOTALDIGITS:
3585 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3586 case XML_SCHEMA_FACET_PATTERN:
3587 case XML_SCHEMA_FACET_ENUMERATION:
3588 case XML_SCHEMA_FACET_WHITESPACE:
3589 case XML_SCHEMA_FACET_LENGTH:
3590 case XML_SCHEMA_FACET_MAXLENGTH:
3591 case XML_SCHEMA_FACET_MINLENGTH:
3592 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3593 break;
3594 }
3595 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003596#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003597 if (typeDecl->node != NULL) {
3598 xmlGenericError(xmlGenericErrorContext,
3599 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3600 xmlGetLineNo(typeDecl->node));
3601 } else {
3602 xmlGenericError(xmlGenericErrorContext,
3603 "Type of %s :", name);
3604 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003605 switch (typeDecl->contentType) {
3606 case XML_SCHEMA_CONTENT_SIMPLE:
3607 xmlGenericError(xmlGenericErrorContext,
3608 "simple\n"); break;
3609 case XML_SCHEMA_CONTENT_ELEMENTS:
3610 xmlGenericError(xmlGenericErrorContext,
3611 "elements\n"); break;
3612 case XML_SCHEMA_CONTENT_UNKNOWN:
3613 xmlGenericError(xmlGenericErrorContext,
3614 "unknown !!!\n"); break;
3615 case XML_SCHEMA_CONTENT_EMPTY:
3616 xmlGenericError(xmlGenericErrorContext,
3617 "empty\n"); break;
3618 case XML_SCHEMA_CONTENT_MIXED:
3619 xmlGenericError(xmlGenericErrorContext,
3620 "mixed\n"); break;
3621 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3622 xmlGenericError(xmlGenericErrorContext,
3623 "mixed or elems\n"); break;
3624 case XML_SCHEMA_CONTENT_BASIC:
3625 xmlGenericError(xmlGenericErrorContext,
3626 "basic\n"); break;
3627 default:
3628 xmlGenericError(xmlGenericErrorContext,
3629 "not registered !!!\n"); break;
3630 }
3631#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003632}
3633
3634/**
3635 * xmlSchemaCheckDefaults:
3636 * @typeDecl: the schema type definition
3637 * @ctxt: the schema parser context
3638 *
3639 * Checks the default values types, especially for facets
3640 */
3641static void
3642xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
3643 xmlSchemaParserCtxtPtr ctxt,
3644 const xmlChar *name)
3645{
3646 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3647 if (name == NULL)
3648 name = typeDecl->name;
3649 if (nonNegativeIntegerType == NULL) {
3650 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3651 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3652 }
3653 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
3654 if (typeDecl->facets != NULL) {
3655 xmlSchemaFacetPtr facet = typeDecl->facets;
3656 while (facet != NULL) {
3657 switch (facet->type) {
3658 case XML_SCHEMA_FACET_MININCLUSIVE:
3659 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3660 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3661 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3662 /*
3663 * Okay we need to validate the value
3664 * at that point.
3665 */
3666 xmlSchemaValidCtxtPtr vctxt;
3667
3668 vctxt = xmlSchemaNewValidCtxt(NULL);
3669 if (vctxt == NULL)
3670 break;
3671 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3672 facet->value);
3673 facet->val = vctxt->value;
3674 vctxt->value = NULL;
3675 if (facet->val == NULL) {
3676 /* error code */
3677 xmlSchemaErrorContext(ctxt, NULL,
3678 facet->node, NULL);
3679 ctxt->error(ctxt->userData,
3680 "Schemas: type %s facet value %s invalid\n",
3681 name, facet->value);
3682 }
3683 xmlSchemaFreeValidCtxt(vctxt);
3684 break;
3685 }
3686 case XML_SCHEMA_FACET_ENUMERATION: {
3687 /*
3688 * Okay we need to validate the value
3689 * at that point.
3690 */
3691 xmlSchemaValidCtxtPtr vctxt;
3692 int ret;
3693
3694 vctxt = xmlSchemaNewValidCtxt(NULL);
3695 if (vctxt == NULL)
3696 break;
3697 ret = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3698 facet->value);
3699 if (ret != 0) {
3700 xmlSchemaErrorContext(ctxt, NULL,
3701 facet->node, NULL);
3702 ctxt->error(ctxt->userData,
3703 "Schemas: type %s enumeration value %s invalid\n",
3704 name, facet->value);
3705 }
3706 xmlSchemaFreeValidCtxt(vctxt);
3707 break;
3708 }
3709 case XML_SCHEMA_FACET_PATTERN:
3710 facet->regexp = xmlRegexpCompile(facet->value);
3711 if (facet->regexp == NULL) {
3712 /* error code */
3713 ctxt->error(ctxt->userData,
3714 "Schemas: type %s facet regexp %s invalid\n",
3715 name, facet->value);
3716 }
3717 break;
3718 case XML_SCHEMA_FACET_TOTALDIGITS:
3719 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3720 case XML_SCHEMA_FACET_LENGTH:
3721 case XML_SCHEMA_FACET_MAXLENGTH:
3722 case XML_SCHEMA_FACET_MINLENGTH: {
3723 int ret;
3724
3725 ret = xmlSchemaValidatePredefinedType(
3726 nonNegativeIntegerType, facet->value,
3727 &facet->val);
3728 if (ret != 0) {
3729 /* error code */
3730 xmlSchemaErrorContext(ctxt, NULL,
3731 facet->node, NULL);
3732 ctxt->error(ctxt->userData,
3733 "Schemas: type %s facet value %s invalid\n",
3734 name, facet->value);
3735 }
3736 break;
3737 }
3738 case XML_SCHEMA_FACET_WHITESPACE: {
3739 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
3740 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
3741 } else if (xmlStrEqual(facet->value,
3742 BAD_CAST"replace")) {
3743 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
3744 } else if (xmlStrEqual(facet->value,
3745 BAD_CAST"collapse")) {
3746 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
3747 } else {
3748 xmlSchemaErrorContext(ctxt, NULL,
3749 facet->node, NULL);
3750 ctxt->error(ctxt->userData,
3751 "Schemas: type %s whiteSpace value %s invalid\n",
3752 name, facet->value);
3753 }
3754 }
3755 default:
3756 break;
3757 }
3758 facet = facet->next;
3759 }
3760 }
3761 }
3762}
3763
3764/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00003765 * xmlSchemaAttrGrpFixup:
3766 * @attrgrpDecl: the schema attribute definition
3767 * @ctxt: the schema parser context
3768 * @name: the attribute name
3769 *
3770 * Fixes finish doing the computations on the attributes definitions
3771 */
3772static void
3773xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
3774 xmlSchemaParserCtxtPtr ctxt,
3775 const xmlChar *name)
3776{
3777 if (name == NULL)
3778 name = attrgrpDecl->name;
3779 if (attrgrpDecl->attributes != NULL)
3780 return;
3781 if (attrgrpDecl->ref != NULL) {
3782 xmlSchemaAttributeGroupPtr ref;
3783
3784 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
3785 attrgrpDecl->refNs);
3786 if (ref == NULL) {
3787 if ((ctxt != NULL) && (ctxt->error != NULL))
3788 ctxt->error(ctxt->userData,
3789 "Schemas: attribute group %s reference %s not found\n",
3790 name, attrgrpDecl->ref);
3791 return;
3792 }
3793 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
3794 attrgrpDecl->attributes = ref->attributes;
3795 } else {
3796 if ((ctxt != NULL) && (ctxt->error != NULL))
3797 ctxt->error(ctxt->userData,
3798 "Schemas: attribute %s has no attributes nor reference\n",
3799 name);
3800 }
3801}
3802
3803/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003804 * xmlSchemaAttrFixup:
3805 * @attrDecl: the schema attribute definition
3806 * @ctxt: the schema parser context
3807 * @name: the attribute name
3808 *
3809 * Fixes finish doing the computations on the attributes definitions
3810 */
3811static void
3812xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
3813 xmlSchemaParserCtxtPtr ctxt,
3814 const xmlChar *name)
3815{
3816 if (name == NULL)
3817 name = attrDecl->name;
3818 if (attrDecl->subtypes != NULL)
3819 return;
3820 if (attrDecl->typeName != NULL) {
3821 xmlSchemaTypePtr type;
3822
3823 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
3824 attrDecl->typeNs);
3825 if (type == NULL) {
3826 if ((ctxt != NULL) && (ctxt->error != NULL))
3827 ctxt->error(ctxt->userData,
3828 "Schemas: attribute %s type %s not found\n",
3829 name, attrDecl->typeName);
3830 }
3831 attrDecl->subtypes = type;
3832 } else if (attrDecl->ref != NULL) {
3833 xmlSchemaAttributePtr ref;
3834
3835 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
3836 attrDecl->refNs);
3837 if (ref == NULL) {
3838 if ((ctxt != NULL) && (ctxt->error != NULL))
3839 ctxt->error(ctxt->userData,
3840 "Schemas: attribute %s reference %s not found\n",
3841 name, attrDecl->ref);
3842 return;
3843 }
3844 xmlSchemaAttrFixup(ref, ctxt, NULL);
3845 attrDecl->subtypes = ref->subtypes;
3846 } else {
3847 if ((ctxt != NULL) && (ctxt->error != NULL))
3848 ctxt->error(ctxt->userData,
3849 "Schemas: attribute %s has no type nor reference\n",
3850 name);
3851 }
3852}
3853
3854/**
3855 * xmlSchemaParse:
3856 * @ctxt: a schema validation context
3857 * @URL: the location of the schema
3858 *
3859 * Load, XML parse a schema definition resource and build an internal
3860 * XML Shema struture which can be used to validate instances.
3861 * *WARNING* this interface is highly subject to change
3862 *
3863 * Returns the internal XML Schema structure built from the resource or
3864 * NULL in case of error
3865 */
3866xmlSchemaPtr
3867xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
3868{
3869 xmlSchemaPtr ret = NULL;
3870 xmlDocPtr doc;
3871 xmlNodePtr root, cur, delete;
3872
3873 xmlSchemaInitTypes();
3874
Daniel Veillard6045c902002-10-09 21:13:59 +00003875 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00003876 return (NULL);
3877
3878 ctxt->counter = 0;
3879 ctxt->container = NULL;
3880
3881 /*
3882 * First step is to parse the input document into an DOM/Infoset
3883 */
Daniel Veillard6045c902002-10-09 21:13:59 +00003884 if (ctxt->URL != NULL) {
3885 doc = xmlParseFile((const char *) ctxt->URL);
3886 if (doc == NULL) {
3887 if (ctxt->error != NULL)
3888 ctxt->error(ctxt->userData,
3889 "xmlSchemaParse: could not load %s\n", ctxt->URL);
3890 return (NULL);
3891 }
3892 } else if (ctxt->buffer != NULL) {
3893 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
3894 if (doc == NULL) {
3895 if (ctxt->error != NULL)
3896 ctxt->error(ctxt->userData,
3897 "xmlSchemaParse: could not parse schemas\n");
3898 return (NULL);
3899 }
3900 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
3901 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
3902 } else {
3903 if (ctxt->error != NULL)
3904 ctxt->error(ctxt->userData,
3905 "xmlSchemaParse: nothing to parse\n");
3906 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003907 }
3908
3909 /*
3910 * Then extract the root and Schema parse it
3911 */
3912 root = xmlDocGetRootElement(doc);
3913 if (root == NULL) {
3914 if (ctxt->error != NULL)
3915 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
3916 ctxt->URL);
3917 return (NULL);
3918 }
3919
3920 /*
3921 * Remove all the blank text nodes
3922 */
3923 delete = NULL;
3924 cur = root;
3925 while (cur != NULL) {
3926 if (delete != NULL) {
3927 xmlUnlinkNode(delete);
3928 xmlFreeNode(delete);
3929 delete = NULL;
3930 }
3931 if (cur->type == XML_TEXT_NODE) {
3932 if (IS_BLANK_NODE(cur)) {
3933 if (xmlNodeGetSpacePreserve(cur) != 1) {
3934 delete = cur;
3935 }
3936 }
3937 } else if ((cur->type != XML_ELEMENT_NODE) &&
3938 (cur->type != XML_CDATA_SECTION_NODE)) {
3939 delete = cur;
3940 goto skip_children;
3941 }
3942
3943 /*
3944 * Skip to next node
3945 */
3946 if (cur->children != NULL) {
3947 if ((cur->children->type != XML_ENTITY_DECL) &&
3948 (cur->children->type != XML_ENTITY_REF_NODE) &&
3949 (cur->children->type != XML_ENTITY_NODE)) {
3950 cur = cur->children;
3951 continue;
3952 }
3953 }
3954skip_children:
3955 if (cur->next != NULL) {
3956 cur = cur->next;
3957 continue;
3958 }
3959
3960 do {
3961 cur = cur->parent;
3962 if (cur == NULL)
3963 break;
3964 if (cur == root) {
3965 cur = NULL;
3966 break;
3967 }
3968 if (cur->next != NULL) {
3969 cur = cur->next;
3970 break;
3971 }
3972 } while (cur != NULL);
3973 }
3974 if (delete != NULL) {
3975 xmlUnlinkNode(delete);
3976 xmlFreeNode(delete);
3977 delete = NULL;
3978 }
3979
3980 /*
3981 * Then do the parsing for good
3982 */
3983 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00003984 if (ret == NULL)
3985 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003986 ret->doc = doc;
3987
3988 /*
3989 * Then fix all the references.
3990 */
3991 ctxt->schema = ret;
3992 xmlHashScanFull(ret->elemDecl,
3993 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
3994
3995 /*
3996 * Then fixup all types properties
3997 */
3998 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
3999
4000 /*
4001 * Then build the content model for all elements
4002 */
4003 xmlHashScan(ret->elemDecl,
4004 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
4005
4006 /*
4007 * Then check the defaults part of the type like facets values
4008 */
4009 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
4010
4011 /*
4012 * Then fixup all attributes declarations
4013 */
4014 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4015
Daniel Veillard13e04c62002-04-23 17:51:29 +00004016 /*
4017 * Then fixup all attributes group declarations
4018 */
4019 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
4020
Daniel Veillard4255d502002-04-16 15:50:10 +00004021 return (ret);
4022}
4023
4024/**
4025 * xmlSchemaParse:
4026 * @ctxt: a schema validation context
4027 * @URL: the location of the schema
4028 *
4029 * Load, XML parse a schema definition resource and build an internal
4030 * XML Shema struture which can be used to validate instances.
4031 * *WARNING* this interface is highly subject to change
4032 *
4033 * Returns the internal XML Schema structure built from the resource or
4034 * NULL in case of error
4035 */
4036void
4037xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
4038 xmlSchemaValidityErrorFunc err,
4039 xmlSchemaValidityWarningFunc warn, void *ctx) {
4040 if (ctxt == NULL)
4041 return;
4042 ctxt->error = err;
4043 ctxt->warning = warn;
4044 ctxt->userData = ctx;
4045}
4046
4047/************************************************************************
4048 * *
4049 * Simple type validation *
4050 * *
4051 ************************************************************************/
4052
4053/**
4054 * xmlSchemaValidateSimpleValue:
4055 * @ctxt: a schema validation context
4056 * @type: the type declaration
4057 * @value: the value to validate
4058 *
4059 * Validate a value against a simple type
4060 *
4061 * Returns 0 if the value is valid, a positive error code
4062 * number otherwise and -1 in case of internal or API error.
4063 */
4064static int
4065xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4066 xmlSchemaTypePtr type,
4067 xmlChar *value) {
4068 int ret = 0;
4069 /*
4070 * First normalize the value accordingly to Schema Datatype
4071 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4072 */
4073 /*
4074 * Then check the normalized value against the lexical space of the
4075 * type.
4076 */
4077 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4078 if (ctxt->value != NULL) {
4079 xmlSchemaFreeValue(ctxt->value);
4080 ctxt->value = NULL;
4081 }
4082 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4083 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4084 xmlSchemaTypePtr base;
4085 xmlSchemaFacetPtr facet;
4086 int tmp;
4087
4088 base = type->baseType;
4089 if (base != NULL) {
4090 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4091 } else if (type->subtypes != NULL) {
4092
4093 }
4094 /*
4095 * Do not validate facets when working on building the Schemas
4096 */
4097 if (ctxt->schema != NULL) {
4098 if (ret == 0) {
4099 facet = type->facets;
Daniel Veillard88c58912002-04-23 07:12:20 +00004100 if ((type->type == XML_SCHEMA_TYPE_RESTRICTION) &&
4101 (facet != NULL) &&
4102 (facet->type == XML_SCHEMA_FACET_ENUMERATION)) {
4103 while (facet != NULL) {
4104 ret = 1;
4105
4106 tmp = xmlSchemaValidateFacet(base, facet, value,
4107 ctxt->value);
4108 if (tmp == 0) {
4109 ret = 0;
4110 break;
4111 }
4112 facet = facet->next;
4113 }
4114 } else {
4115 while (facet != NULL) {
4116 tmp = xmlSchemaValidateFacet(base, facet, value,
4117 ctxt->value);
4118 if (tmp != 0)
4119 ret = tmp;
4120 facet = facet->next;
4121 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004122 }
4123 }
4124 }
4125 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4126 xmlSchemaTypePtr base;
4127
4128 base = type->subtypes;
4129 if (base != NULL) {
4130 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4131 } else {
4132 TODO
4133 }
4134 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4135 xmlSchemaTypePtr base;
4136 xmlChar *cur, *end, tmp;
4137 int ret2;
4138
4139 base = type->subtypes;
4140 if (base == NULL) {
4141 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4142 if (ctxt->error != NULL) {
4143 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4144 ctxt->error(ctxt->userData,
4145 "Internal: List type %s has no base type\n",
4146 type->name);
4147 }
4148 return(-1);
4149 }
4150 cur = value;
4151 do {
4152 while (IS_BLANK(*cur)) cur++;
4153 end = cur;
4154 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4155 if (end == cur)
4156 break;
4157 tmp = *end;
4158 *end = 0;
4159 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4160 if (ret2 != 0)
4161 ret = 1;
4162 *end = tmp;
4163 cur = end;
4164 } while (*cur != 0);
4165 } else {
4166 TODO
4167 }
4168 return(ret);
4169}
4170
4171/************************************************************************
4172 * *
4173 * DOM Validation code *
4174 * *
4175 ************************************************************************/
4176
4177static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4178 xmlNodePtr node);
4179static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4180 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4181static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4182 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4183
4184/**
4185 * xmlSchemaRegisterAttributes:
4186 * @ctxt: a schema validation context
4187 * @attrs: a list of attributes
4188 *
4189 * Register the list of attributes as the set to be validated on that element
4190 *
4191 * Returns -1 in case of error, 0 otherwise
4192 */
4193static int
4194xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4195 xmlAttrPtr attrs) {
4196 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004197 if ((attrs->ns != NULL) &&
4198 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4199 attrs = attrs->next;
4200 continue;
4201 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004202 if (ctxt->attrNr >= ctxt->attrMax) {
4203 xmlSchemaAttrStatePtr tmp;
4204
4205 ctxt->attrMax *= 2;
4206 tmp = (xmlSchemaAttrStatePtr)
4207 xmlRealloc(ctxt->attr, ctxt->attrMax *
4208 sizeof(xmlSchemaAttrState));
4209 if (tmp == NULL) {
4210 ctxt->attrMax /= 2;
4211 return(-1);
4212 }
4213 ctxt->attr = tmp;
4214 }
4215 ctxt->attr[ctxt->attrNr].attr = attrs;
4216 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4217 ctxt->attrNr++;
4218 attrs = attrs->next;
4219 }
4220 return(0);
4221}
4222
4223/**
4224 * xmlSchemaCheckAttributes:
4225 * @ctxt: a schema validation context
4226 * @node: the node carrying it.
4227 *
4228 * Check that the registered set of attributes on the current node
4229 * has been properly validated.
4230 *
4231 * Returns 0 if validity constraints are met, 1 otherwise.
4232 */
4233static int
4234xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4235 int ret = 0;
4236 int i;
4237
4238 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4239 if (ctxt->attr[i].attr == NULL)
4240 break;
4241 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4242 ret = 1;
4243 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
4244 if (ctxt->error != NULL)
4245 ctxt->error(ctxt->userData,
4246 "Attribute %s on %s is unknown\n",
4247 ctxt->attr[i].attr->name,
4248 node->name);
4249 }
4250 }
4251 return(ret);
4252}
4253
4254/**
4255 * xmlSchemaValidateSimpleContent:
4256 * @ctxt: a schema validation context
4257 * @elem: an element
4258 * @type: the type declaration
4259 *
4260 * Validate the content of an element expected to be a simple type
4261 *
4262 * Returns 0 if the element is schemas valid, a positive error code
4263 * number otherwise and -1 in case of internal or API error.
4264 */
4265static int
4266xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004267 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004268 xmlNodePtr child;
4269 xmlSchemaTypePtr type, base;
4270 xmlChar *value;
4271 int ret = 0, tmp;
4272
4273 child = ctxt->node;
4274 type = ctxt->type;
4275
4276 /*
4277 * Validation Rule: Element Locally Valid (Type): 3.1.3
4278 */
4279 value = xmlNodeGetContent(child);
4280 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4281 switch (type->type) {
4282 case XML_SCHEMA_TYPE_RESTRICTION: {
4283 xmlSchemaFacetPtr facet;
4284
4285 base = type->baseType;
4286 if (base != NULL) {
4287 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4288 } else {
4289 TODO
4290 }
4291 if (ret == 0) {
4292 facet = type->facets;
4293 while (facet != NULL) {
4294 tmp = xmlSchemaValidateFacet(base, facet, value,
4295 ctxt->value);
4296 if (tmp != 0)
4297 ret = tmp;
4298 facet = facet->next;
4299 }
4300 }
4301 break;
4302 }
4303 default:
4304 TODO
4305 }
4306 if (value != NULL)
4307 xmlFree(value);
4308
4309 return(ret);
4310}
4311
4312/**
4313 * xmlSchemaValidateCheckNodeList
4314 * @nodelist: the list of nodes
4315 *
4316 * Check the node list is only made of text nodes and entities pointing
4317 * to text nodes
4318 *
4319 * Returns 1 if true, 0 if false and -1 in case of error
4320 */
4321static int
4322xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4323 while (nodelist != NULL) {
4324 if (nodelist->type == XML_ENTITY_REF_NODE) {
4325 TODO /* implement recursion in the entity content */
4326 }
4327 if ((nodelist->type != XML_TEXT_NODE) &&
4328 (nodelist->type != XML_COMMENT_NODE) &&
4329 (nodelist->type != XML_PI_NODE) &&
4330 (nodelist->type != XML_PI_NODE)) {
4331 return(0);
4332 }
4333 nodelist = nodelist->next;
4334 }
4335 return(1);
4336}
4337
4338/**
4339 * xmlSchemaSkipIgnored:
4340 * @ctxt: a schema validation context
4341 * @type: the current type context
4342 * @node: the top node.
4343 *
4344 * Skip ignorable nodes in that context
4345 *
4346 * Returns the new sibling
4347 * number otherwise and -1 in case of internal or API error.
4348 */
4349static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004350xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004351 xmlSchemaTypePtr type,
4352 xmlNodePtr node) {
4353 int mixed = 0;
4354 /*
4355 * TODO complete and handle entities
4356 */
4357 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4358 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4359 while ((node != NULL) &&
4360 ((node->type == XML_COMMENT_NODE) ||
4361 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4362 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4363 (node->type == XML_TEXT_NODE) &&
4364 (IS_BLANK_NODE(node)))))) {
4365 node = node->next;
4366 }
4367 return(node);
4368}
4369
4370/**
4371 * xmlSchemaValidateCallback:
4372 * @ctxt: a schema validation context
4373 * @name: the name of the element detected (might be NULL)
4374 * @type: the type
4375 *
4376 * A transition has been made in the automata associated to an element
4377 * content model
4378 */
4379static void
4380xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004381 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004382 xmlSchemaTypePtr type,
4383 xmlNodePtr node) {
4384 xmlSchemaTypePtr oldtype = ctxt->type;
4385 xmlNodePtr oldnode = ctxt->node;
4386#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004387 xmlGenericError(xmlGenericErrorContext,
4388 "xmlSchemaValidateCallback: %s, %s, %s\n",
4389 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004390#endif
4391 ctxt->type = type;
4392 ctxt->node = node;
4393 xmlSchemaValidateContent(ctxt, node);
4394 ctxt->type = oldtype;
4395 ctxt->node = oldnode;
4396}
4397
4398
4399#if 0
4400/**
4401 * xmlSchemaValidateSimpleRestrictionType:
4402 * @ctxt: a schema validation context
4403 * @node: the top node.
4404 *
4405 * Validate the content of a restriction type.
4406 *
4407 * Returns 0 if the element is schemas valid, a positive error code
4408 * number otherwise and -1 in case of internal or API error.
4409 */
4410static int
4411xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4412 xmlNodePtr node)
4413{
4414 xmlNodePtr child;
4415 xmlSchemaTypePtr type;
4416 int ret;
4417
4418 child = ctxt->node;
4419 type = ctxt->type;
4420
4421 if ((ctxt == NULL) || (type == NULL)) {
4422 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4423 if (ctxt->error != NULL)
4424 ctxt->error(ctxt->userData,
4425 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4426 node->name);
4427 return (-1);
4428 }
4429 /*
4430 * Only text and text based entities references shall be found there
4431 */
4432 ret = xmlSchemaValidateCheckNodeList(child);
4433 if (ret < 0) {
4434 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4435 if (ctxt->error != NULL)
4436 ctxt->error(ctxt->userData,
4437 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4438 node->name);
4439 return (-1);
4440 } else if (ret == 0) {
4441 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4442 if (ctxt->error != NULL)
4443 ctxt->error(ctxt->userData,
4444 "Element %s content is not a simple type\n",
4445 node->name);
4446 return (-1);
4447 }
4448 ctxt->type = type->subtypes;
4449 xmlSchemaValidateContent(ctxt, node);
4450 ctxt->type = type;
4451 return (ret);
4452}
4453#endif
4454
4455/**
4456 * xmlSchemaValidateSimpleType:
4457 * @ctxt: a schema validation context
4458 * @node: the top node.
4459 *
4460 * Validate the content of an simple type.
4461 *
4462 * Returns 0 if the element is schemas valid, a positive error code
4463 * number otherwise and -1 in case of internal or API error.
4464 */
4465static int
4466xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4467 xmlNodePtr child;
4468 xmlSchemaTypePtr type;
4469 xmlAttrPtr attr;
4470 int ret;
4471
4472 child = ctxt->node;
4473 type = ctxt->type;
4474
4475 if ((ctxt == NULL) || (type == NULL)) {
4476 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4477 if (ctxt->error != NULL)
4478 ctxt->error(ctxt->userData,
4479 "Internal error: xmlSchemaValidateSimpleType %s\n",
4480 node->name);
4481 return(-1);
4482 }
4483 /*
4484 * Only text and text based entities references shall be found there
4485 */
4486 ret = xmlSchemaValidateCheckNodeList(child);
4487 if (ret < 0) {
4488 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4489 if (ctxt->error != NULL)
4490 ctxt->error(ctxt->userData,
4491 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4492 node->name);
4493 return(-1);
4494 } else if (ret == 0) {
4495 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4496 if (ctxt->error != NULL)
4497 ctxt->error(ctxt->userData,
4498 "Element %s content is not a simple type\n",
4499 node->name);
4500 return(-1);
4501 }
4502 /*
4503 * Validation Rule: Element Locally Valid (Type): 3.1.1
4504 */
4505 attr = node->properties;
4506 while (attr != NULL) {
4507 if ((attr->ns == NULL) ||
4508 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4509 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4510 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4511 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4512 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4513 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4514 if (ctxt->error != NULL)
4515 ctxt->error(ctxt->userData,
4516 "Element %s: attribute %s should not be present\n",
4517 child->name, attr->name);
4518 return(ctxt->err);
4519 }
4520 }
4521
4522 ctxt->type = type->subtypes;
4523 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4524 ctxt->type = type;
4525 return(ret);
4526}
4527
4528/**
4529 * xmlSchemaValidateElementType:
4530 * @ctxt: a schema validation context
4531 * @node: the top node.
4532 *
4533 * Validate the content of an element type.
4534 * Validation Rule: Element Locally Valid (Complex Type)
4535 *
4536 * Returns 0 if the element is schemas valid, a positive error code
4537 * number otherwise and -1 in case of internal or API error.
4538 */
4539static int
4540xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4541 xmlNodePtr child;
4542 xmlSchemaTypePtr type;
4543 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4544 xmlSchemaElementPtr decl;
4545 int ret, attrBase;
4546
4547 oldregexp = ctxt->regexp;
4548
4549 child = ctxt->node;
4550 type = ctxt->type;
4551
4552 if ((ctxt == NULL) || (type == NULL)) {
4553 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4554 if (ctxt->error != NULL)
4555 ctxt->error(ctxt->userData,
4556 "Internal error: xmlSchemaValidateElementType\n",
4557 node->name);
4558 return(-1);
4559 }
4560 if (child == NULL) {
4561 if (type->minOccurs > 0) {
4562 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4563 if (ctxt->error != NULL)
4564 ctxt->error(ctxt->userData,
4565 "Element %s: missing child %s\n",
4566 node->name, type->name);
4567 }
4568 return(ctxt->err);
4569 }
4570
4571 /*
4572 * Verify the element matches
4573 */
4574 if (!xmlStrEqual(child->name, type->name)) {
4575 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4576 if (ctxt->error != NULL)
4577 ctxt->error(ctxt->userData,
4578 "Element %s: missing child %s found %s\n",
4579 node->name, type->name, child->name);
4580 return(ctxt->err);
4581 }
4582 /*
4583 * Verify the attributes
4584 */
4585 attrBase = ctxt->attrBase;
4586 ctxt->attrBase = ctxt->attrNr;
4587 xmlSchemaRegisterAttributes(ctxt, child->properties);
4588 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4589 /*
4590 * Verify the element content recursively
4591 */
4592 decl = (xmlSchemaElementPtr) type;
4593 oldregexp = ctxt->regexp;
4594 if (decl->contModel != NULL) {
4595 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4596 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4597 ctxt);
4598#ifdef DEBUG_AUTOMATA
4599 xmlGenericError(xmlGenericErrorContext,
4600 "====> %s\n", node->name);
4601#endif
4602 }
4603 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4604 type->subtypes);
4605
4606 if (decl->contModel != NULL) {
4607 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4608#ifdef DEBUG_AUTOMATA
4609 xmlGenericError(xmlGenericErrorContext,
4610 "====> %s : %d\n", node->name, ret);
4611#endif
4612 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004613 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004614 if (ctxt->error != NULL)
4615 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4616 node->name);
4617 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004618 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004619 if (ctxt->error != NULL)
4620 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4621 node->name);
4622#ifdef DEBUG_CONTENT
4623 } else {
4624 xmlGenericError(xmlGenericErrorContext,
4625 "Element %s content check succeeded\n", node->name);
4626
4627#endif
4628 }
4629 xmlRegFreeExecCtxt(ctxt->regexp);
4630 }
4631 /*
4632 * Verify that all attributes were Schemas-validated
4633 */
4634 xmlSchemaCheckAttributes(ctxt, node);
4635 ctxt->attrNr = ctxt->attrBase;
4636 ctxt->attrBase = attrBase;
4637
4638 ctxt->regexp = oldregexp;
4639
4640 ctxt->node = child;
4641 ctxt->type = type;
4642 return(ctxt->err);
4643}
4644
4645/**
4646 * xmlSchemaValidateBasicType:
4647 * @ctxt: a schema validation context
4648 * @node: the top node.
4649 *
4650 * Validate the content of an element expected to be a basic type type
4651 *
4652 * Returns 0 if the element is schemas valid, a positive error code
4653 * number otherwise and -1 in case of internal or API error.
4654 */
4655static int
4656xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4657 int ret;
4658 xmlNodePtr child, cur;
4659 xmlSchemaTypePtr type;
4660 xmlChar *value; /* lexical representation */
4661
4662 child = ctxt->node;
4663 type = ctxt->type;
4664
4665 if ((ctxt == NULL) || (type == NULL)) {
4666 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4667 if (ctxt->error != NULL)
4668 ctxt->error(ctxt->userData,
4669 "Internal error: xmlSchemaValidateBasicType\n",
4670 node->name);
4671 return(-1);
4672 }
4673 /*
4674 * First check the content model of the node.
4675 */
4676 cur = child;
4677 while (cur != NULL) {
4678 switch (cur->type) {
4679 case XML_TEXT_NODE:
4680 case XML_CDATA_SECTION_NODE:
4681 case XML_PI_NODE:
4682 case XML_COMMENT_NODE:
4683 case XML_XINCLUDE_START:
4684 case XML_XINCLUDE_END:
4685 break;
4686 case XML_ENTITY_REF_NODE:
4687 case XML_ENTITY_NODE:
4688 TODO
4689 break;
4690 case XML_ELEMENT_NODE:
4691 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4692 if (ctxt->error != NULL)
4693 ctxt->error(ctxt->userData,
4694 "Element %s: child %s should not be present\n",
4695 node->name, cur->name);
4696 return(ctxt->err);
4697 case XML_ATTRIBUTE_NODE:
4698 case XML_DOCUMENT_NODE:
4699 case XML_DOCUMENT_TYPE_NODE:
4700 case XML_DOCUMENT_FRAG_NODE:
4701 case XML_NOTATION_NODE:
4702 case XML_HTML_DOCUMENT_NODE:
4703 case XML_DTD_NODE:
4704 case XML_ELEMENT_DECL:
4705 case XML_ATTRIBUTE_DECL:
4706 case XML_ENTITY_DECL:
4707 case XML_NAMESPACE_DECL:
4708#ifdef LIBXML_DOCB_ENABLED
4709 case XML_DOCB_DOCUMENT_NODE:
4710#endif
4711 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4712 if (ctxt->error != NULL)
4713 ctxt->error(ctxt->userData,
4714 "Element %s: node type %d unexpected here\n",
4715 node->name, cur->type);
4716 return(ctxt->err);
4717 }
4718 cur = cur->next;
4719 }
4720 if (child == NULL)
4721 value = NULL;
4722 else
4723 value = xmlNodeGetContent(child->parent);
4724
4725 if (ctxt->value != NULL) {
4726 xmlSchemaFreeValue(ctxt->value);
4727 ctxt->value = NULL;
4728 }
4729 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4730 if (value != NULL)
4731 xmlFree(value);
4732 if (ret != 0) {
4733 ctxt->error(ctxt->userData,
4734 "Element %s: failed to validate basic type %s\n",
4735 node->name, type->name);
4736 }
4737 return(ret);
4738}
4739
4740/**
4741 * xmlSchemaValidateComplexType:
4742 * @ctxt: a schema validation context
4743 * @node: the top node.
4744 *
4745 * Validate the content of an element expected to be a complex type type
4746 * xmlschema-1.html#cvc-complex-type
4747 * Validation Rule: Element Locally Valid (Complex Type)
4748 *
4749 * Returns 0 if the element is schemas valid, a positive error code
4750 * number otherwise and -1 in case of internal or API error.
4751 */
4752static int
4753xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4754 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004755 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004756 int ret;
4757
4758 child = ctxt->node;
4759 type = ctxt->type;
4760
Daniel Veillard4255d502002-04-16 15:50:10 +00004761 switch (type->contentType) {
4762 case XML_SCHEMA_CONTENT_EMPTY:
4763 if (child != NULL) {
4764 if (ctxt->error != NULL)
4765 ctxt->error(ctxt->userData,
4766 "Element %s is supposed to be empty\n",
4767 node->name);
4768 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00004769 if (type->attributes != NULL) {
4770 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4771 }
4772 subtype = type->subtypes;
4773 while (subtype != NULL) {
4774 ctxt->type = subtype;
4775 xmlSchemaValidateComplexType(ctxt, node);
4776 subtype = subtype->next;
4777 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004778 break;
4779 case XML_SCHEMA_CONTENT_ELEMENTS:
4780 case XML_SCHEMA_CONTENT_MIXED:
4781 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4782 /*
4783 * Skip ignorable nodes in that context
4784 */
4785 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00004786 while (child != NULL) {
4787 if (child->type == XML_ELEMENT_NODE) {
4788 ret = xmlRegExecPushString(ctxt->regexp,
4789 child->name, child);
4790#ifdef DEBUG_AUTOMATA
4791 if (ret < 0)
4792 xmlGenericError(xmlGenericErrorContext,
4793 " --> %s Error\n", child->name);
4794 else
4795 xmlGenericError(xmlGenericErrorContext,
4796 " --> %s\n", child->name);
4797#endif
4798 }
4799 child = child->next;
4800 /*
4801 * Skip ignorable nodes in that context
4802 */
4803 child = xmlSchemaSkipIgnored(ctxt, type, child);
4804 }
4805 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004806 case XML_SCHEMA_CONTENT_BASIC: {
4807 if (type->subtypes != NULL) {
4808 ctxt->type = type->subtypes;
4809 xmlSchemaValidateComplexType(ctxt, node);
4810 }
4811 if (type->baseType != NULL) {
4812 ctxt->type = type->baseType;
4813 xmlSchemaValidateBasicType(ctxt, node);
4814 }
4815 if (type->attributes != NULL) {
4816 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4817 }
4818 ctxt->type = type;
4819 break;
4820 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004821 default:
4822 TODO
4823 xmlGenericError(xmlGenericErrorContext,
4824 "unimplemented content type %d\n",
4825 type->contentType);
4826 }
4827 return(ctxt->err);
4828}
4829
4830/**
4831 * xmlSchemaValidateContent:
4832 * @ctxt: a schema validation context
4833 * @elem: an element
4834 * @type: the type declaration
4835 *
4836 * Validate the content of an element against the type.
4837 *
4838 * Returns 0 if the element is schemas valid, a positive error code
4839 * number otherwise and -1 in case of internal or API error.
4840 */
4841static int
4842xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4843 xmlNodePtr child;
4844 xmlSchemaTypePtr type;
4845
4846 child = ctxt->node;
4847 type = ctxt->type;
4848
Daniel Veillarde19fc232002-04-22 16:01:24 +00004849 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4850
Daniel Veillard4255d502002-04-16 15:50:10 +00004851 switch (type->type) {
4852 case XML_SCHEMA_TYPE_ANY:
4853 /* Any type will do it, fine */
4854 TODO /* handle recursivity */
4855 break;
4856 case XML_SCHEMA_TYPE_COMPLEX:
4857 xmlSchemaValidateComplexType(ctxt, node);
4858 break;
4859 case XML_SCHEMA_TYPE_ELEMENT: {
4860 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
4861 /*
4862 * Handle element reference here
4863 */
4864 if (decl->ref != NULL) {
4865 if (decl->refDecl == NULL) {
4866 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4867 if (ctxt->error != NULL)
4868 ctxt->error(ctxt->userData,
4869 "Internal error: element reference %s not resolved\n",
4870 decl->ref);
4871 return(-1);
4872 }
4873 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
4874 decl = decl->refDecl;
4875 }
4876 xmlSchemaValidateElementType(ctxt, node);
4877 ctxt->type = type;
4878 break;
4879 }
4880 case XML_SCHEMA_TYPE_BASIC:
4881 xmlSchemaValidateBasicType(ctxt, node);
4882 break;
4883 case XML_SCHEMA_TYPE_FACET:
4884 TODO
4885 break;
4886 case XML_SCHEMA_TYPE_SIMPLE:
4887 xmlSchemaValidateSimpleType(ctxt, node);
4888 break;
4889 case XML_SCHEMA_TYPE_SEQUENCE:
4890 TODO
4891 break;
4892 case XML_SCHEMA_TYPE_CHOICE:
4893 TODO
4894 break;
4895 case XML_SCHEMA_TYPE_ALL:
4896 TODO
4897 break;
4898 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
4899 TODO
4900 break;
4901 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4902 TODO
4903 break;
4904 case XML_SCHEMA_TYPE_UR:
4905 TODO
4906 break;
4907 case XML_SCHEMA_TYPE_RESTRICTION:
4908 /*xmlSchemaValidateRestrictionType(ctxt, node); */
4909 TODO
4910 break;
4911 case XML_SCHEMA_TYPE_EXTENSION:
4912 TODO
4913 break;
4914 case XML_SCHEMA_TYPE_ATTRIBUTE:
4915 TODO
4916 break;
4917 case XML_SCHEMA_TYPE_GROUP:
4918 TODO
4919 break;
4920 case XML_SCHEMA_TYPE_NOTATION:
4921 TODO
4922 break;
4923 case XML_SCHEMA_TYPE_LIST:
4924 TODO
4925 break;
4926 case XML_SCHEMA_TYPE_UNION:
4927 TODO
4928 break;
4929 case XML_SCHEMA_FACET_MININCLUSIVE:
4930 TODO
4931 break;
4932 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4933 TODO
4934 break;
4935 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4936 TODO
4937 break;
4938 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4939 TODO
4940 break;
4941 case XML_SCHEMA_FACET_TOTALDIGITS:
4942 TODO
4943 break;
4944 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4945 TODO
4946 break;
4947 case XML_SCHEMA_FACET_PATTERN:
4948 TODO
4949 break;
4950 case XML_SCHEMA_FACET_ENUMERATION:
4951 TODO
4952 break;
4953 case XML_SCHEMA_FACET_WHITESPACE:
4954 TODO
4955 break;
4956 case XML_SCHEMA_FACET_LENGTH:
4957 TODO
4958 break;
4959 case XML_SCHEMA_FACET_MAXLENGTH:
4960 TODO
4961 break;
4962 case XML_SCHEMA_FACET_MINLENGTH:
4963 TODO
4964 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00004965 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4966 TODO
4967 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00004968 }
4969 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4970
4971 if (ctxt->node == NULL)
4972 return(ctxt->err);
4973 ctxt->node = ctxt->node->next;
4974 ctxt->type = type->next;
4975 return(ctxt->err);
4976}
4977
4978/**
4979 * xmlSchemaValidateType:
4980 * @ctxt: a schema validation context
4981 * @elem: an element
4982 * @type: the list of type declarations
4983 *
4984 * Validate the content of an element against the types.
4985 *
4986 * Returns 0 if the element is schemas valid, a positive error code
4987 * number otherwise and -1 in case of internal or API error.
4988 */
4989static int
4990xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4991 xmlSchemaElementPtr elemDecl,
4992 xmlSchemaTypePtr type) {
4993 xmlChar *nil;
4994
4995 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
4996 return(0);
4997 /*
4998 * 3.3.4 : 2
4999 */
5000 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
5001 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
5002 if (ctxt->error != NULL)
5003 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
5004 return(ctxt->err);
5005 }
5006 /*
5007 * 3.3.4: 3
5008 */
5009 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5010 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
5011 /* 3.3.4: 3.2 */
5012 if (xmlStrEqual(nil, BAD_CAST "true")) {
5013 if (elem->children != NULL) {
5014 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
5015 if (ctxt->error != NULL)
5016 ctxt->error(ctxt->userData, "Element %s is not empty\n",
5017 elem->name);
5018 return(ctxt->err);
5019 }
5020 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5021 (elemDecl->value != NULL)) {
5022 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
5023 if (ctxt->error != NULL)
5024 ctxt->error(ctxt->userData,
5025 "Empty element %s cannot get a fixed value\n",
5026 elem->name);
5027 return(ctxt->err);
5028 }
5029 }
5030 } else {
5031 /* 3.3.4: 3.1 */
5032 if (nil != NULL) {
5033 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
5034 if (ctxt->error != NULL)
5035 ctxt->error(ctxt->userData,
5036 "Element %s with xs:nil but not nillable\n",
5037 elem->name);
5038 xmlFree(nil);
5039 return(ctxt->err);
5040 }
5041 }
5042
5043 /* TODO 3.3.4: 4 if the element carries xs:type*/
5044
5045 ctxt->type = elemDecl->subtypes;
5046 ctxt->node = elem->children;
5047 xmlSchemaValidateContent(ctxt, elem);
5048 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5049
5050 return(ctxt->err);
5051}
5052
5053
5054/**
5055 * xmlSchemaValidateAttributes:
5056 * @ctxt: a schema validation context
5057 * @elem: an element
5058 * @attributes: the list of attribute declarations
5059 *
5060 * Validate the attributes of an element.
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
5066xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5067 xmlSchemaAttributePtr attributes) {
5068 int i, ret;
5069 xmlAttrPtr attr;
5070 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005071 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005072
5073 if (attributes == NULL)
5074 return(0);
5075 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005076 /*
5077 * Handle attribute groups
5078 */
5079 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5080 group = (xmlSchemaAttributeGroupPtr) attributes;
5081 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5082 attributes = group->next;
5083 continue;
5084 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005085 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5086 attr = ctxt->attr[i].attr;
5087 if (attr == NULL)
5088 continue;
5089 if (!xmlStrEqual(attr->name, attributes->name))
5090 continue;
5091 /*
5092 * TODO: handle the mess about namespaces here.
5093 */
5094 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5095 TODO
5096 }
5097 if (attributes->subtypes == NULL) {
5098 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5099 if (ctxt->error != NULL)
5100 ctxt->error(ctxt->userData,
5101 "Internal error: attribute %s type not resolved\n",
5102 attr->name);
5103 continue;
5104 }
5105 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5106 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005107 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005108 if (ret != 0) {
5109 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5110 if (ctxt->error != NULL)
5111 ctxt->error(ctxt->userData,
5112 "attribute %s on %s does not match type\n",
5113 attr->name, elem->name);
5114 } else {
5115 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5116 }
5117 if (value != NULL) {
5118 xmlFree(value);
5119 }
5120 }
5121 attributes = attributes->next;
5122 }
5123 return(ctxt->err);
5124}
5125
5126/**
5127 * xmlSchemaValidateElement:
5128 * @ctxt: a schema validation context
5129 * @elem: an element
5130 *
5131 * Validate an element in a tree
5132 *
5133 * Returns 0 if the element is schemas valid, a positive error code
5134 * number otherwise and -1 in case of internal or API error.
5135 */
5136static int
5137xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5138 xmlSchemaElementPtr elemDecl;
5139 int ret, attrBase;
5140
5141 if (elem->ns != NULL)
5142 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5143 elem->name, elem->ns->href, NULL);
5144 else
5145 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5146 elem->name, NULL, NULL);
5147 /*
5148 * 3.3.4 : 1
5149 */
5150 if (elemDecl == NULL) {
5151 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5152 if (ctxt->error != NULL)
5153 ctxt->error(ctxt->userData, "Element %s not declared\n",
5154 elem->name);
5155 return(ctxt->err);
5156 }
5157 if (elemDecl->subtypes == NULL) {
5158 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5159 if (ctxt->error != NULL)
5160 ctxt->error(ctxt->userData, "Element %s has no type\n",
5161 elem->name);
5162 return(ctxt->err);
5163 }
5164 /*
5165 * Verify the attributes
5166 */
5167 attrBase = ctxt->attrBase;
5168 ctxt->attrBase = ctxt->attrNr;
5169 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5170 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5171 /*
5172 * Verify the element content recursively
5173 */
5174 if (elemDecl->contModel != NULL) {
5175 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5176 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5177 ctxt);
5178#ifdef DEBUG_AUTOMATA
5179 xmlGenericError(xmlGenericErrorContext,
5180 "====> %s\n", elem->name);
5181#endif
5182 }
5183 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005184 if (elemDecl->contModel != NULL) {
5185 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005186#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005188 "====> %s : %d\n", elem->name, ret);
5189#endif
5190 if (ret == 0) {
5191 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5192 if (ctxt->error != NULL)
5193 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5194 elem->name);
5195 } else if (ret < 0) {
5196 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5197 if (ctxt->error != NULL)
5198 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5199 elem->name);
5200#ifdef DEBUG_CONTENT
5201 } else {
5202 xmlGenericError(xmlGenericErrorContext,
5203 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005204
5205#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005206 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005207 xmlRegFreeExecCtxt(ctxt->regexp);
5208 }
5209 /*
5210 * Verify that all attributes were Schemas-validated
5211 */
5212 xmlSchemaCheckAttributes(ctxt, elem);
5213 ctxt->attrNr = ctxt->attrBase;
5214 ctxt->attrBase = attrBase;
5215
5216 return(ctxt->err);
5217}
5218
5219/**
5220 * xmlSchemaValidateDocument:
5221 * @ctxt: a schema validation context
5222 * @doc: a parsed document tree
5223 *
5224 * Validate a document tree in memory.
5225 *
5226 * Returns 0 if the document is schemas valid, a positive error code
5227 * number otherwise and -1 in case of internal or API error.
5228 */
5229static int
5230xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5231 xmlNodePtr root;
5232 xmlSchemaElementPtr elemDecl;
5233
5234 root = xmlDocGetRootElement(doc);
5235 if (root == NULL) {
5236 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
5237 if (ctxt->error != NULL)
5238 ctxt->error(ctxt->userData, "document has no root\n");
5239 return(ctxt->err);
5240 }
5241 if (root->ns != NULL)
5242 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5243 root->name, root->ns->href, NULL);
5244 else
5245 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5246 root->name, NULL, NULL);
5247 if (elemDecl == NULL) {
5248 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5249 if (ctxt->error != NULL)
5250 ctxt->error(ctxt->userData, "Element %s not declared\n",
5251 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005252 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005253 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
5254 if (ctxt->error != NULL)
5255 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5256 root->name);
5257 }
5258 /*
5259 * Okay, start the recursive validation
5260 */
5261 xmlSchemaValidateElement(ctxt, root);
5262
5263 return(ctxt->err);
5264}
5265
5266/************************************************************************
5267 * *
5268 * SAX Validation code *
5269 * *
5270 ************************************************************************/
5271
5272/************************************************************************
5273 * *
5274 * Validation interfaces *
5275 * *
5276 ************************************************************************/
5277
5278/**
5279 * xmlSchemaNewValidCtxt:
5280 * @schema: a precompiled XML Schemas
5281 *
5282 * Create an XML Schemas validation context based on the given schema
5283 *
5284 * Returns the validation context or NULL in case of error
5285 */
5286xmlSchemaValidCtxtPtr
5287xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5288 xmlSchemaValidCtxtPtr ret;
5289
5290 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5291 if (ret == NULL) {
5292 xmlGenericError(xmlGenericErrorContext,
5293 "Failed to allocate new schama validation context\n");
5294 return (NULL);
5295 }
5296 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5297 ret->schema = schema;
5298 ret->attrNr = 0;
5299 ret->attrMax = 10;
5300 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5301 sizeof(xmlSchemaAttrState));
5302 if (ret->attr == NULL) {
5303 free(ret);
5304 return(NULL);
5305 }
5306 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5307 return (ret);
5308}
5309
5310/**
5311 * xmlSchemaFreeValidCtxt:
5312 * @ctxt: the schema validation context
5313 *
5314 * Free the resources associated to the schema validation context
5315 */
5316void
5317xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5318 if (ctxt == NULL)
5319 return;
5320 if (ctxt->attr != NULL)
5321 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005322 if (ctxt->value != NULL)
5323 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005324 xmlFree(ctxt);
5325}
5326
5327/**
5328 * xmlSchemaSetValidErrors:
5329 * @ctxt: a schema validation context
5330 * @err: the error function
5331 * @warn: the warning function
5332 * @ctxt: the functions context
5333 *
5334 * Set the error and warning callback informations
5335 */
5336void
5337xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5338 xmlSchemaValidityErrorFunc err,
5339 xmlSchemaValidityWarningFunc warn, void *ctx) {
5340 if (ctxt == NULL)
5341 return;
5342 ctxt->error = err;
5343 ctxt->warning = warn;
5344 ctxt->userData = ctx;
5345}
5346
5347/**
5348 * xmlSchemaValidateDoc:
5349 * @ctxt: a schema validation context
5350 * @doc: a parsed document tree
5351 *
5352 * Validate a document tree in memory.
5353 *
5354 * Returns 0 if the document is schemas valid, a positive error code
5355 * number otherwise and -1 in case of internal or API error.
5356 */
5357int
5358xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5359 int ret;
5360
5361 if ((ctxt == NULL) || (doc == NULL))
5362 return(-1);
5363
5364 ctxt->doc = doc;
5365 ret = xmlSchemaValidateDocument(ctxt, doc);
5366 return(ret);
5367}
5368
5369/**
5370 * xmlSchemaValidateStream:
5371 * @ctxt: a schema validation context
5372 * @input: the input to use for reading the data
5373 * @enc: an optional encoding information
5374 * @sax: a SAX handler for the resulting events
5375 * @user_data: the context to provide to the SAX handler.
5376 *
5377 * Validate a document tree in memory.
5378 *
5379 * Returns 0 if the document is schemas valid, a positive error code
5380 * number otherwise and -1 in case of internal or API error.
5381 */
5382int
5383xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5384 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5385 xmlSAXHandlerPtr sax, void *user_data) {
5386 if ((ctxt == NULL) || (input == NULL))
5387 return(-1);
5388 ctxt->input = input;
5389 ctxt->enc = enc;
5390 ctxt->sax = sax;
5391 ctxt->user_data = user_data;
5392 TODO
5393 return(0);
5394}
5395
5396#endif /* LIBXML_SCHEMAS_ENABLED */