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