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