blob: 6c9e2f4d1b48b0f4db0e058d09a64d81aad6f00f [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
4170/************************************************************************
4171 * *
4172 * Simple type validation *
4173 * *
4174 ************************************************************************/
4175
4176/**
4177 * xmlSchemaValidateSimpleValue:
4178 * @ctxt: a schema validation context
4179 * @type: the type declaration
4180 * @value: the value to validate
4181 *
4182 * Validate a value against a simple type
4183 *
4184 * Returns 0 if the value is valid, a positive error code
4185 * number otherwise and -1 in case of internal or API error.
4186 */
4187static int
4188xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4189 xmlSchemaTypePtr type,
4190 xmlChar *value) {
4191 int ret = 0;
4192 /*
4193 * First normalize the value accordingly to Schema Datatype
4194 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4195 */
4196 /*
4197 * Then check the normalized value against the lexical space of the
4198 * type.
4199 */
4200 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4201 if (ctxt->value != NULL) {
4202 xmlSchemaFreeValue(ctxt->value);
4203 ctxt->value = NULL;
4204 }
4205 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4206 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4207 xmlSchemaTypePtr base;
4208 xmlSchemaFacetPtr facet;
4209 int tmp;
4210
4211 base = type->baseType;
4212 if (base != NULL) {
4213 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4214 } else if (type->subtypes != NULL) {
4215
4216 }
4217 /*
4218 * Do not validate facets when working on building the Schemas
4219 */
4220 if (ctxt->schema != NULL) {
4221 if (ret == 0) {
4222 facet = type->facets;
Daniel Veillard88c58912002-04-23 07:12:20 +00004223 if ((type->type == XML_SCHEMA_TYPE_RESTRICTION) &&
4224 (facet != NULL) &&
4225 (facet->type == XML_SCHEMA_FACET_ENUMERATION)) {
4226 while (facet != NULL) {
4227 ret = 1;
4228
4229 tmp = xmlSchemaValidateFacet(base, facet, value,
4230 ctxt->value);
4231 if (tmp == 0) {
4232 ret = 0;
4233 break;
4234 }
4235 facet = facet->next;
4236 }
4237 } else {
4238 while (facet != NULL) {
4239 tmp = xmlSchemaValidateFacet(base, facet, value,
4240 ctxt->value);
4241 if (tmp != 0)
4242 ret = tmp;
4243 facet = facet->next;
4244 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004245 }
4246 }
4247 }
4248 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4249 xmlSchemaTypePtr base;
4250
4251 base = type->subtypes;
4252 if (base != NULL) {
4253 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4254 } else {
4255 TODO
4256 }
4257 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4258 xmlSchemaTypePtr base;
4259 xmlChar *cur, *end, tmp;
4260 int ret2;
4261
4262 base = type->subtypes;
4263 if (base == NULL) {
4264 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4265 if (ctxt->error != NULL) {
4266 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4267 ctxt->error(ctxt->userData,
4268 "Internal: List type %s has no base type\n",
4269 type->name);
4270 }
4271 return(-1);
4272 }
4273 cur = value;
4274 do {
4275 while (IS_BLANK(*cur)) cur++;
4276 end = cur;
4277 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4278 if (end == cur)
4279 break;
4280 tmp = *end;
4281 *end = 0;
4282 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4283 if (ret2 != 0)
4284 ret = 1;
4285 *end = tmp;
4286 cur = end;
4287 } while (*cur != 0);
4288 } else {
4289 TODO
4290 }
4291 return(ret);
4292}
4293
4294/************************************************************************
4295 * *
4296 * DOM Validation code *
4297 * *
4298 ************************************************************************/
4299
4300static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4301 xmlNodePtr node);
4302static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4303 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4304static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4305 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4306
4307/**
4308 * xmlSchemaRegisterAttributes:
4309 * @ctxt: a schema validation context
4310 * @attrs: a list of attributes
4311 *
4312 * Register the list of attributes as the set to be validated on that element
4313 *
4314 * Returns -1 in case of error, 0 otherwise
4315 */
4316static int
4317xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4318 xmlAttrPtr attrs) {
4319 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004320 if ((attrs->ns != NULL) &&
4321 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4322 attrs = attrs->next;
4323 continue;
4324 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004325 if (ctxt->attrNr >= ctxt->attrMax) {
4326 xmlSchemaAttrStatePtr tmp;
4327
4328 ctxt->attrMax *= 2;
4329 tmp = (xmlSchemaAttrStatePtr)
4330 xmlRealloc(ctxt->attr, ctxt->attrMax *
4331 sizeof(xmlSchemaAttrState));
4332 if (tmp == NULL) {
4333 ctxt->attrMax /= 2;
4334 return(-1);
4335 }
4336 ctxt->attr = tmp;
4337 }
4338 ctxt->attr[ctxt->attrNr].attr = attrs;
4339 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4340 ctxt->attrNr++;
4341 attrs = attrs->next;
4342 }
4343 return(0);
4344}
4345
4346/**
4347 * xmlSchemaCheckAttributes:
4348 * @ctxt: a schema validation context
4349 * @node: the node carrying it.
4350 *
4351 * Check that the registered set of attributes on the current node
4352 * has been properly validated.
4353 *
4354 * Returns 0 if validity constraints are met, 1 otherwise.
4355 */
4356static int
4357xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4358 int ret = 0;
4359 int i;
4360
4361 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4362 if (ctxt->attr[i].attr == NULL)
4363 break;
4364 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4365 ret = 1;
4366 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
4367 if (ctxt->error != NULL)
4368 ctxt->error(ctxt->userData,
4369 "Attribute %s on %s is unknown\n",
4370 ctxt->attr[i].attr->name,
4371 node->name);
4372 }
4373 }
4374 return(ret);
4375}
4376
4377/**
4378 * xmlSchemaValidateSimpleContent:
4379 * @ctxt: a schema validation context
4380 * @elem: an element
4381 * @type: the type declaration
4382 *
4383 * Validate the content of an element expected to be a simple type
4384 *
4385 * Returns 0 if the element is schemas valid, a positive error code
4386 * number otherwise and -1 in case of internal or API error.
4387 */
4388static int
4389xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004390 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004391 xmlNodePtr child;
4392 xmlSchemaTypePtr type, base;
4393 xmlChar *value;
4394 int ret = 0, tmp;
4395
4396 child = ctxt->node;
4397 type = ctxt->type;
4398
4399 /*
4400 * Validation Rule: Element Locally Valid (Type): 3.1.3
4401 */
4402 value = xmlNodeGetContent(child);
4403 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4404 switch (type->type) {
4405 case XML_SCHEMA_TYPE_RESTRICTION: {
4406 xmlSchemaFacetPtr facet;
4407
4408 base = type->baseType;
4409 if (base != NULL) {
4410 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4411 } else {
4412 TODO
4413 }
4414 if (ret == 0) {
4415 facet = type->facets;
4416 while (facet != NULL) {
4417 tmp = xmlSchemaValidateFacet(base, facet, value,
4418 ctxt->value);
4419 if (tmp != 0)
4420 ret = tmp;
4421 facet = facet->next;
4422 }
4423 }
4424 break;
4425 }
4426 default:
4427 TODO
4428 }
4429 if (value != NULL)
4430 xmlFree(value);
4431
4432 return(ret);
4433}
4434
4435/**
4436 * xmlSchemaValidateCheckNodeList
4437 * @nodelist: the list of nodes
4438 *
4439 * Check the node list is only made of text nodes and entities pointing
4440 * to text nodes
4441 *
4442 * Returns 1 if true, 0 if false and -1 in case of error
4443 */
4444static int
4445xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4446 while (nodelist != NULL) {
4447 if (nodelist->type == XML_ENTITY_REF_NODE) {
4448 TODO /* implement recursion in the entity content */
4449 }
4450 if ((nodelist->type != XML_TEXT_NODE) &&
4451 (nodelist->type != XML_COMMENT_NODE) &&
4452 (nodelist->type != XML_PI_NODE) &&
4453 (nodelist->type != XML_PI_NODE)) {
4454 return(0);
4455 }
4456 nodelist = nodelist->next;
4457 }
4458 return(1);
4459}
4460
4461/**
4462 * xmlSchemaSkipIgnored:
4463 * @ctxt: a schema validation context
4464 * @type: the current type context
4465 * @node: the top node.
4466 *
4467 * Skip ignorable nodes in that context
4468 *
4469 * Returns the new sibling
4470 * number otherwise and -1 in case of internal or API error.
4471 */
4472static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004473xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004474 xmlSchemaTypePtr type,
4475 xmlNodePtr node) {
4476 int mixed = 0;
4477 /*
4478 * TODO complete and handle entities
4479 */
4480 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4481 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4482 while ((node != NULL) &&
4483 ((node->type == XML_COMMENT_NODE) ||
4484 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4485 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4486 (node->type == XML_TEXT_NODE) &&
4487 (IS_BLANK_NODE(node)))))) {
4488 node = node->next;
4489 }
4490 return(node);
4491}
4492
4493/**
4494 * xmlSchemaValidateCallback:
4495 * @ctxt: a schema validation context
4496 * @name: the name of the element detected (might be NULL)
4497 * @type: the type
4498 *
4499 * A transition has been made in the automata associated to an element
4500 * content model
4501 */
4502static void
4503xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004504 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004505 xmlSchemaTypePtr type,
4506 xmlNodePtr node) {
4507 xmlSchemaTypePtr oldtype = ctxt->type;
4508 xmlNodePtr oldnode = ctxt->node;
4509#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004510 xmlGenericError(xmlGenericErrorContext,
4511 "xmlSchemaValidateCallback: %s, %s, %s\n",
4512 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004513#endif
4514 ctxt->type = type;
4515 ctxt->node = node;
4516 xmlSchemaValidateContent(ctxt, node);
4517 ctxt->type = oldtype;
4518 ctxt->node = oldnode;
4519}
4520
4521
4522#if 0
4523/**
4524 * xmlSchemaValidateSimpleRestrictionType:
4525 * @ctxt: a schema validation context
4526 * @node: the top node.
4527 *
4528 * Validate the content of a restriction type.
4529 *
4530 * Returns 0 if the element is schemas valid, a positive error code
4531 * number otherwise and -1 in case of internal or API error.
4532 */
4533static int
4534xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4535 xmlNodePtr node)
4536{
4537 xmlNodePtr child;
4538 xmlSchemaTypePtr type;
4539 int ret;
4540
4541 child = ctxt->node;
4542 type = ctxt->type;
4543
4544 if ((ctxt == NULL) || (type == NULL)) {
4545 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4546 if (ctxt->error != NULL)
4547 ctxt->error(ctxt->userData,
4548 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4549 node->name);
4550 return (-1);
4551 }
4552 /*
4553 * Only text and text based entities references shall be found there
4554 */
4555 ret = xmlSchemaValidateCheckNodeList(child);
4556 if (ret < 0) {
4557 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4558 if (ctxt->error != NULL)
4559 ctxt->error(ctxt->userData,
4560 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4561 node->name);
4562 return (-1);
4563 } else if (ret == 0) {
4564 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4565 if (ctxt->error != NULL)
4566 ctxt->error(ctxt->userData,
4567 "Element %s content is not a simple type\n",
4568 node->name);
4569 return (-1);
4570 }
4571 ctxt->type = type->subtypes;
4572 xmlSchemaValidateContent(ctxt, node);
4573 ctxt->type = type;
4574 return (ret);
4575}
4576#endif
4577
4578/**
4579 * xmlSchemaValidateSimpleType:
4580 * @ctxt: a schema validation context
4581 * @node: the top node.
4582 *
4583 * Validate the content of an simple type.
4584 *
4585 * Returns 0 if the element is schemas valid, a positive error code
4586 * number otherwise and -1 in case of internal or API error.
4587 */
4588static int
4589xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4590 xmlNodePtr child;
4591 xmlSchemaTypePtr type;
4592 xmlAttrPtr attr;
4593 int ret;
4594
4595 child = ctxt->node;
4596 type = ctxt->type;
4597
4598 if ((ctxt == NULL) || (type == NULL)) {
4599 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4600 if (ctxt->error != NULL)
4601 ctxt->error(ctxt->userData,
4602 "Internal error: xmlSchemaValidateSimpleType %s\n",
4603 node->name);
4604 return(-1);
4605 }
4606 /*
4607 * Only text and text based entities references shall be found there
4608 */
4609 ret = xmlSchemaValidateCheckNodeList(child);
4610 if (ret < 0) {
4611 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4612 if (ctxt->error != NULL)
4613 ctxt->error(ctxt->userData,
4614 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4615 node->name);
4616 return(-1);
4617 } else if (ret == 0) {
4618 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4619 if (ctxt->error != NULL)
4620 ctxt->error(ctxt->userData,
4621 "Element %s content is not a simple type\n",
4622 node->name);
4623 return(-1);
4624 }
4625 /*
4626 * Validation Rule: Element Locally Valid (Type): 3.1.1
4627 */
4628 attr = node->properties;
4629 while (attr != NULL) {
4630 if ((attr->ns == NULL) ||
4631 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4632 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4633 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4634 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4635 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4636 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4637 if (ctxt->error != NULL)
4638 ctxt->error(ctxt->userData,
4639 "Element %s: attribute %s should not be present\n",
4640 child->name, attr->name);
4641 return(ctxt->err);
4642 }
4643 }
4644
4645 ctxt->type = type->subtypes;
4646 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4647 ctxt->type = type;
4648 return(ret);
4649}
4650
4651/**
4652 * xmlSchemaValidateElementType:
4653 * @ctxt: a schema validation context
4654 * @node: the top node.
4655 *
4656 * Validate the content of an element type.
4657 * Validation Rule: Element Locally Valid (Complex Type)
4658 *
4659 * Returns 0 if the element is schemas valid, a positive error code
4660 * number otherwise and -1 in case of internal or API error.
4661 */
4662static int
4663xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4664 xmlNodePtr child;
4665 xmlSchemaTypePtr type;
4666 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4667 xmlSchemaElementPtr decl;
4668 int ret, attrBase;
4669
4670 oldregexp = ctxt->regexp;
4671
4672 child = ctxt->node;
4673 type = ctxt->type;
4674
4675 if ((ctxt == NULL) || (type == NULL)) {
4676 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4677 if (ctxt->error != NULL)
4678 ctxt->error(ctxt->userData,
4679 "Internal error: xmlSchemaValidateElementType\n",
4680 node->name);
4681 return(-1);
4682 }
4683 if (child == NULL) {
4684 if (type->minOccurs > 0) {
4685 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4686 if (ctxt->error != NULL)
4687 ctxt->error(ctxt->userData,
4688 "Element %s: missing child %s\n",
4689 node->name, type->name);
4690 }
4691 return(ctxt->err);
4692 }
4693
4694 /*
4695 * Verify the element matches
4696 */
4697 if (!xmlStrEqual(child->name, type->name)) {
4698 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4699 if (ctxt->error != NULL)
4700 ctxt->error(ctxt->userData,
4701 "Element %s: missing child %s found %s\n",
4702 node->name, type->name, child->name);
4703 return(ctxt->err);
4704 }
4705 /*
4706 * Verify the attributes
4707 */
4708 attrBase = ctxt->attrBase;
4709 ctxt->attrBase = ctxt->attrNr;
4710 xmlSchemaRegisterAttributes(ctxt, child->properties);
4711 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4712 /*
4713 * Verify the element content recursively
4714 */
4715 decl = (xmlSchemaElementPtr) type;
4716 oldregexp = ctxt->regexp;
4717 if (decl->contModel != NULL) {
4718 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4719 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4720 ctxt);
4721#ifdef DEBUG_AUTOMATA
4722 xmlGenericError(xmlGenericErrorContext,
4723 "====> %s\n", node->name);
4724#endif
4725 }
4726 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4727 type->subtypes);
4728
4729 if (decl->contModel != NULL) {
4730 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4731#ifdef DEBUG_AUTOMATA
4732 xmlGenericError(xmlGenericErrorContext,
4733 "====> %s : %d\n", node->name, ret);
4734#endif
4735 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004736 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004737 if (ctxt->error != NULL)
4738 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4739 node->name);
4740 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004741 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004742 if (ctxt->error != NULL)
4743 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4744 node->name);
4745#ifdef DEBUG_CONTENT
4746 } else {
4747 xmlGenericError(xmlGenericErrorContext,
4748 "Element %s content check succeeded\n", node->name);
4749
4750#endif
4751 }
4752 xmlRegFreeExecCtxt(ctxt->regexp);
4753 }
4754 /*
4755 * Verify that all attributes were Schemas-validated
4756 */
4757 xmlSchemaCheckAttributes(ctxt, node);
4758 ctxt->attrNr = ctxt->attrBase;
4759 ctxt->attrBase = attrBase;
4760
4761 ctxt->regexp = oldregexp;
4762
4763 ctxt->node = child;
4764 ctxt->type = type;
4765 return(ctxt->err);
4766}
4767
4768/**
4769 * xmlSchemaValidateBasicType:
4770 * @ctxt: a schema validation context
4771 * @node: the top node.
4772 *
4773 * Validate the content of an element expected to be a basic type type
4774 *
4775 * Returns 0 if the element is schemas valid, a positive error code
4776 * number otherwise and -1 in case of internal or API error.
4777 */
4778static int
4779xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4780 int ret;
4781 xmlNodePtr child, cur;
4782 xmlSchemaTypePtr type;
4783 xmlChar *value; /* lexical representation */
4784
4785 child = ctxt->node;
4786 type = ctxt->type;
4787
4788 if ((ctxt == NULL) || (type == NULL)) {
4789 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4790 if (ctxt->error != NULL)
4791 ctxt->error(ctxt->userData,
4792 "Internal error: xmlSchemaValidateBasicType\n",
4793 node->name);
4794 return(-1);
4795 }
4796 /*
4797 * First check the content model of the node.
4798 */
4799 cur = child;
4800 while (cur != NULL) {
4801 switch (cur->type) {
4802 case XML_TEXT_NODE:
4803 case XML_CDATA_SECTION_NODE:
4804 case XML_PI_NODE:
4805 case XML_COMMENT_NODE:
4806 case XML_XINCLUDE_START:
4807 case XML_XINCLUDE_END:
4808 break;
4809 case XML_ENTITY_REF_NODE:
4810 case XML_ENTITY_NODE:
4811 TODO
4812 break;
4813 case XML_ELEMENT_NODE:
4814 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4815 if (ctxt->error != NULL)
4816 ctxt->error(ctxt->userData,
4817 "Element %s: child %s should not be present\n",
4818 node->name, cur->name);
4819 return(ctxt->err);
4820 case XML_ATTRIBUTE_NODE:
4821 case XML_DOCUMENT_NODE:
4822 case XML_DOCUMENT_TYPE_NODE:
4823 case XML_DOCUMENT_FRAG_NODE:
4824 case XML_NOTATION_NODE:
4825 case XML_HTML_DOCUMENT_NODE:
4826 case XML_DTD_NODE:
4827 case XML_ELEMENT_DECL:
4828 case XML_ATTRIBUTE_DECL:
4829 case XML_ENTITY_DECL:
4830 case XML_NAMESPACE_DECL:
4831#ifdef LIBXML_DOCB_ENABLED
4832 case XML_DOCB_DOCUMENT_NODE:
4833#endif
4834 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4835 if (ctxt->error != NULL)
4836 ctxt->error(ctxt->userData,
4837 "Element %s: node type %d unexpected here\n",
4838 node->name, cur->type);
4839 return(ctxt->err);
4840 }
4841 cur = cur->next;
4842 }
4843 if (child == NULL)
4844 value = NULL;
4845 else
4846 value = xmlNodeGetContent(child->parent);
4847
4848 if (ctxt->value != NULL) {
4849 xmlSchemaFreeValue(ctxt->value);
4850 ctxt->value = NULL;
4851 }
4852 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4853 if (value != NULL)
4854 xmlFree(value);
4855 if (ret != 0) {
4856 ctxt->error(ctxt->userData,
4857 "Element %s: failed to validate basic type %s\n",
4858 node->name, type->name);
Daniel Veillard91a13252003-03-27 23:44:43 +00004859 ctxt->err = XML_SCHEMAS_ERR_VALUE;
Daniel Veillard4255d502002-04-16 15:50:10 +00004860 }
4861 return(ret);
4862}
4863
4864/**
4865 * xmlSchemaValidateComplexType:
4866 * @ctxt: a schema validation context
4867 * @node: the top node.
4868 *
4869 * Validate the content of an element expected to be a complex type type
4870 * xmlschema-1.html#cvc-complex-type
4871 * Validation Rule: Element Locally Valid (Complex Type)
4872 *
4873 * Returns 0 if the element is schemas valid, a positive error code
4874 * number otherwise and -1 in case of internal or API error.
4875 */
4876static int
4877xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4878 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004879 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004880 int ret;
4881
4882 child = ctxt->node;
4883 type = ctxt->type;
4884
Daniel Veillard4255d502002-04-16 15:50:10 +00004885 switch (type->contentType) {
4886 case XML_SCHEMA_CONTENT_EMPTY:
4887 if (child != NULL) {
4888 if (ctxt->error != NULL)
4889 ctxt->error(ctxt->userData,
4890 "Element %s is supposed to be empty\n",
4891 node->name);
4892 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00004893 if (type->attributes != NULL) {
4894 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4895 }
4896 subtype = type->subtypes;
4897 while (subtype != NULL) {
4898 ctxt->type = subtype;
4899 xmlSchemaValidateComplexType(ctxt, node);
4900 subtype = subtype->next;
4901 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004902 break;
4903 case XML_SCHEMA_CONTENT_ELEMENTS:
4904 case XML_SCHEMA_CONTENT_MIXED:
4905 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4906 /*
4907 * Skip ignorable nodes in that context
4908 */
4909 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00004910 while (child != NULL) {
4911 if (child->type == XML_ELEMENT_NODE) {
4912 ret = xmlRegExecPushString(ctxt->regexp,
4913 child->name, child);
4914#ifdef DEBUG_AUTOMATA
4915 if (ret < 0)
4916 xmlGenericError(xmlGenericErrorContext,
4917 " --> %s Error\n", child->name);
4918 else
4919 xmlGenericError(xmlGenericErrorContext,
4920 " --> %s\n", child->name);
4921#endif
4922 }
4923 child = child->next;
4924 /*
4925 * Skip ignorable nodes in that context
4926 */
4927 child = xmlSchemaSkipIgnored(ctxt, type, child);
4928 }
4929 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004930 case XML_SCHEMA_CONTENT_BASIC: {
4931 if (type->subtypes != NULL) {
4932 ctxt->type = type->subtypes;
4933 xmlSchemaValidateComplexType(ctxt, node);
4934 }
4935 if (type->baseType != NULL) {
4936 ctxt->type = type->baseType;
4937 xmlSchemaValidateBasicType(ctxt, node);
4938 }
4939 if (type->attributes != NULL) {
4940 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4941 }
4942 ctxt->type = type;
4943 break;
4944 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004945 default:
4946 TODO
4947 xmlGenericError(xmlGenericErrorContext,
4948 "unimplemented content type %d\n",
4949 type->contentType);
4950 }
4951 return(ctxt->err);
4952}
4953
4954/**
4955 * xmlSchemaValidateContent:
4956 * @ctxt: a schema validation context
4957 * @elem: an element
4958 * @type: the type declaration
4959 *
4960 * Validate the content of an element against the type.
4961 *
4962 * Returns 0 if the element is schemas valid, a positive error code
4963 * number otherwise and -1 in case of internal or API error.
4964 */
4965static int
4966xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4967 xmlNodePtr child;
4968 xmlSchemaTypePtr type;
4969
4970 child = ctxt->node;
4971 type = ctxt->type;
4972
Daniel Veillarde19fc232002-04-22 16:01:24 +00004973 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4974
Daniel Veillard4255d502002-04-16 15:50:10 +00004975 switch (type->type) {
4976 case XML_SCHEMA_TYPE_ANY:
4977 /* Any type will do it, fine */
4978 TODO /* handle recursivity */
4979 break;
4980 case XML_SCHEMA_TYPE_COMPLEX:
4981 xmlSchemaValidateComplexType(ctxt, node);
4982 break;
4983 case XML_SCHEMA_TYPE_ELEMENT: {
4984 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
4985 /*
4986 * Handle element reference here
4987 */
4988 if (decl->ref != NULL) {
4989 if (decl->refDecl == NULL) {
4990 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4991 if (ctxt->error != NULL)
4992 ctxt->error(ctxt->userData,
4993 "Internal error: element reference %s not resolved\n",
4994 decl->ref);
4995 return(-1);
4996 }
4997 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
4998 decl = decl->refDecl;
4999 }
5000 xmlSchemaValidateElementType(ctxt, node);
5001 ctxt->type = type;
5002 break;
5003 }
5004 case XML_SCHEMA_TYPE_BASIC:
5005 xmlSchemaValidateBasicType(ctxt, node);
5006 break;
5007 case XML_SCHEMA_TYPE_FACET:
5008 TODO
5009 break;
5010 case XML_SCHEMA_TYPE_SIMPLE:
5011 xmlSchemaValidateSimpleType(ctxt, node);
5012 break;
5013 case XML_SCHEMA_TYPE_SEQUENCE:
5014 TODO
5015 break;
5016 case XML_SCHEMA_TYPE_CHOICE:
5017 TODO
5018 break;
5019 case XML_SCHEMA_TYPE_ALL:
5020 TODO
5021 break;
5022 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5023 TODO
5024 break;
5025 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5026 TODO
5027 break;
5028 case XML_SCHEMA_TYPE_UR:
5029 TODO
5030 break;
5031 case XML_SCHEMA_TYPE_RESTRICTION:
5032 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5033 TODO
5034 break;
5035 case XML_SCHEMA_TYPE_EXTENSION:
5036 TODO
5037 break;
5038 case XML_SCHEMA_TYPE_ATTRIBUTE:
5039 TODO
5040 break;
5041 case XML_SCHEMA_TYPE_GROUP:
5042 TODO
5043 break;
5044 case XML_SCHEMA_TYPE_NOTATION:
5045 TODO
5046 break;
5047 case XML_SCHEMA_TYPE_LIST:
5048 TODO
5049 break;
5050 case XML_SCHEMA_TYPE_UNION:
5051 TODO
5052 break;
5053 case XML_SCHEMA_FACET_MININCLUSIVE:
5054 TODO
5055 break;
5056 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5057 TODO
5058 break;
5059 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5060 TODO
5061 break;
5062 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5063 TODO
5064 break;
5065 case XML_SCHEMA_FACET_TOTALDIGITS:
5066 TODO
5067 break;
5068 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5069 TODO
5070 break;
5071 case XML_SCHEMA_FACET_PATTERN:
5072 TODO
5073 break;
5074 case XML_SCHEMA_FACET_ENUMERATION:
5075 TODO
5076 break;
5077 case XML_SCHEMA_FACET_WHITESPACE:
5078 TODO
5079 break;
5080 case XML_SCHEMA_FACET_LENGTH:
5081 TODO
5082 break;
5083 case XML_SCHEMA_FACET_MAXLENGTH:
5084 TODO
5085 break;
5086 case XML_SCHEMA_FACET_MINLENGTH:
5087 TODO
5088 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00005089 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5090 TODO
5091 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005092 }
5093 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5094
5095 if (ctxt->node == NULL)
5096 return(ctxt->err);
5097 ctxt->node = ctxt->node->next;
5098 ctxt->type = type->next;
5099 return(ctxt->err);
5100}
5101
5102/**
5103 * xmlSchemaValidateType:
5104 * @ctxt: a schema validation context
5105 * @elem: an element
5106 * @type: the list of type declarations
5107 *
5108 * Validate the content of an element against the types.
5109 *
5110 * Returns 0 if the element is schemas valid, a positive error code
5111 * number otherwise and -1 in case of internal or API error.
5112 */
5113static int
5114xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5115 xmlSchemaElementPtr elemDecl,
5116 xmlSchemaTypePtr type) {
5117 xmlChar *nil;
5118
5119 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
5120 return(0);
5121 /*
5122 * 3.3.4 : 2
5123 */
5124 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
5125 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
5126 if (ctxt->error != NULL)
5127 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
5128 return(ctxt->err);
5129 }
5130 /*
5131 * 3.3.4: 3
5132 */
5133 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5134 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
5135 /* 3.3.4: 3.2 */
5136 if (xmlStrEqual(nil, BAD_CAST "true")) {
5137 if (elem->children != NULL) {
5138 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
5139 if (ctxt->error != NULL)
5140 ctxt->error(ctxt->userData, "Element %s is not empty\n",
5141 elem->name);
5142 return(ctxt->err);
5143 }
5144 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5145 (elemDecl->value != NULL)) {
5146 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
5147 if (ctxt->error != NULL)
5148 ctxt->error(ctxt->userData,
5149 "Empty element %s cannot get a fixed value\n",
5150 elem->name);
5151 return(ctxt->err);
5152 }
5153 }
5154 } else {
5155 /* 3.3.4: 3.1 */
5156 if (nil != NULL) {
5157 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
5158 if (ctxt->error != NULL)
5159 ctxt->error(ctxt->userData,
5160 "Element %s with xs:nil but not nillable\n",
5161 elem->name);
5162 xmlFree(nil);
5163 return(ctxt->err);
5164 }
5165 }
5166
5167 /* TODO 3.3.4: 4 if the element carries xs:type*/
5168
5169 ctxt->type = elemDecl->subtypes;
5170 ctxt->node = elem->children;
5171 xmlSchemaValidateContent(ctxt, elem);
5172 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5173
5174 return(ctxt->err);
5175}
5176
5177
5178/**
5179 * xmlSchemaValidateAttributes:
5180 * @ctxt: a schema validation context
5181 * @elem: an element
5182 * @attributes: the list of attribute declarations
5183 *
5184 * Validate the attributes of an element.
5185 *
5186 * Returns 0 if the element is schemas valid, a positive error code
5187 * number otherwise and -1 in case of internal or API error.
5188 */
5189static int
5190xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5191 xmlSchemaAttributePtr attributes) {
5192 int i, ret;
5193 xmlAttrPtr attr;
5194 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005195 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005196
5197 if (attributes == NULL)
5198 return(0);
5199 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005200 /*
5201 * Handle attribute groups
5202 */
5203 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5204 group = (xmlSchemaAttributeGroupPtr) attributes;
5205 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5206 attributes = group->next;
5207 continue;
5208 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005209 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5210 attr = ctxt->attr[i].attr;
5211 if (attr == NULL)
5212 continue;
5213 if (!xmlStrEqual(attr->name, attributes->name))
5214 continue;
5215 /*
5216 * TODO: handle the mess about namespaces here.
5217 */
5218 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5219 TODO
5220 }
5221 if (attributes->subtypes == NULL) {
5222 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5223 if (ctxt->error != NULL)
5224 ctxt->error(ctxt->userData,
5225 "Internal error: attribute %s type not resolved\n",
5226 attr->name);
5227 continue;
5228 }
5229 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5230 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005231 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005232 if (ret != 0) {
5233 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5234 if (ctxt->error != NULL)
5235 ctxt->error(ctxt->userData,
5236 "attribute %s on %s does not match type\n",
5237 attr->name, elem->name);
5238 } else {
5239 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5240 }
5241 if (value != NULL) {
5242 xmlFree(value);
5243 }
5244 }
5245 attributes = attributes->next;
5246 }
5247 return(ctxt->err);
5248}
5249
5250/**
5251 * xmlSchemaValidateElement:
5252 * @ctxt: a schema validation context
5253 * @elem: an element
5254 *
5255 * Validate an element in a tree
5256 *
5257 * Returns 0 if the element is schemas valid, a positive error code
5258 * number otherwise and -1 in case of internal or API error.
5259 */
5260static int
5261xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5262 xmlSchemaElementPtr elemDecl;
5263 int ret, attrBase;
5264
5265 if (elem->ns != NULL)
5266 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5267 elem->name, elem->ns->href, NULL);
5268 else
5269 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5270 elem->name, NULL, NULL);
5271 /*
5272 * 3.3.4 : 1
5273 */
5274 if (elemDecl == NULL) {
5275 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5276 if (ctxt->error != NULL)
5277 ctxt->error(ctxt->userData, "Element %s not declared\n",
5278 elem->name);
5279 return(ctxt->err);
5280 }
5281 if (elemDecl->subtypes == NULL) {
5282 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5283 if (ctxt->error != NULL)
5284 ctxt->error(ctxt->userData, "Element %s has no type\n",
5285 elem->name);
5286 return(ctxt->err);
5287 }
5288 /*
5289 * Verify the attributes
5290 */
5291 attrBase = ctxt->attrBase;
5292 ctxt->attrBase = ctxt->attrNr;
5293 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5294 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5295 /*
5296 * Verify the element content recursively
5297 */
5298 if (elemDecl->contModel != NULL) {
5299 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5300 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5301 ctxt);
5302#ifdef DEBUG_AUTOMATA
5303 xmlGenericError(xmlGenericErrorContext,
5304 "====> %s\n", elem->name);
5305#endif
5306 }
5307 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005308 if (elemDecl->contModel != NULL) {
5309 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005310#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005311 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005312 "====> %s : %d\n", elem->name, ret);
5313#endif
5314 if (ret == 0) {
5315 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5316 if (ctxt->error != NULL)
5317 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5318 elem->name);
5319 } else if (ret < 0) {
5320 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5321 if (ctxt->error != NULL)
5322 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5323 elem->name);
5324#ifdef DEBUG_CONTENT
5325 } else {
5326 xmlGenericError(xmlGenericErrorContext,
5327 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005328
5329#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005330 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005331 xmlRegFreeExecCtxt(ctxt->regexp);
5332 }
5333 /*
5334 * Verify that all attributes were Schemas-validated
5335 */
5336 xmlSchemaCheckAttributes(ctxt, elem);
5337 ctxt->attrNr = ctxt->attrBase;
5338 ctxt->attrBase = attrBase;
5339
5340 return(ctxt->err);
5341}
5342
5343/**
5344 * xmlSchemaValidateDocument:
5345 * @ctxt: a schema validation context
5346 * @doc: a parsed document tree
5347 *
5348 * Validate a document tree in memory.
5349 *
5350 * Returns 0 if the document is schemas valid, a positive error code
5351 * number otherwise and -1 in case of internal or API error.
5352 */
5353static int
5354xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5355 xmlNodePtr root;
5356 xmlSchemaElementPtr elemDecl;
5357
5358 root = xmlDocGetRootElement(doc);
5359 if (root == NULL) {
5360 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
5361 if (ctxt->error != NULL)
5362 ctxt->error(ctxt->userData, "document has no root\n");
5363 return(ctxt->err);
5364 }
5365 if (root->ns != NULL)
5366 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5367 root->name, root->ns->href, NULL);
5368 else
5369 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5370 root->name, NULL, NULL);
5371 if (elemDecl == NULL) {
5372 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5373 if (ctxt->error != NULL)
5374 ctxt->error(ctxt->userData, "Element %s not declared\n",
5375 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005376 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005377 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
5378 if (ctxt->error != NULL)
5379 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5380 root->name);
5381 }
5382 /*
5383 * Okay, start the recursive validation
5384 */
5385 xmlSchemaValidateElement(ctxt, root);
5386
5387 return(ctxt->err);
5388}
5389
5390/************************************************************************
5391 * *
5392 * SAX Validation code *
5393 * *
5394 ************************************************************************/
5395
5396/************************************************************************
5397 * *
5398 * Validation interfaces *
5399 * *
5400 ************************************************************************/
5401
5402/**
5403 * xmlSchemaNewValidCtxt:
5404 * @schema: a precompiled XML Schemas
5405 *
5406 * Create an XML Schemas validation context based on the given schema
5407 *
5408 * Returns the validation context or NULL in case of error
5409 */
5410xmlSchemaValidCtxtPtr
5411xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5412 xmlSchemaValidCtxtPtr ret;
5413
5414 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5415 if (ret == NULL) {
5416 xmlGenericError(xmlGenericErrorContext,
5417 "Failed to allocate new schama validation context\n");
5418 return (NULL);
5419 }
5420 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5421 ret->schema = schema;
5422 ret->attrNr = 0;
5423 ret->attrMax = 10;
5424 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5425 sizeof(xmlSchemaAttrState));
5426 if (ret->attr == NULL) {
5427 free(ret);
5428 return(NULL);
5429 }
5430 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5431 return (ret);
5432}
5433
5434/**
5435 * xmlSchemaFreeValidCtxt:
5436 * @ctxt: the schema validation context
5437 *
5438 * Free the resources associated to the schema validation context
5439 */
5440void
5441xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5442 if (ctxt == NULL)
5443 return;
5444 if (ctxt->attr != NULL)
5445 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005446 if (ctxt->value != NULL)
5447 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005448 xmlFree(ctxt);
5449}
5450
5451/**
5452 * xmlSchemaSetValidErrors:
5453 * @ctxt: a schema validation context
5454 * @err: the error function
5455 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00005456 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00005457 *
5458 * Set the error and warning callback informations
5459 */
5460void
5461xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5462 xmlSchemaValidityErrorFunc err,
5463 xmlSchemaValidityWarningFunc warn, void *ctx) {
5464 if (ctxt == NULL)
5465 return;
5466 ctxt->error = err;
5467 ctxt->warning = warn;
5468 ctxt->userData = ctx;
5469}
5470
5471/**
5472 * xmlSchemaValidateDoc:
5473 * @ctxt: a schema validation context
5474 * @doc: a parsed document tree
5475 *
5476 * Validate a document tree in memory.
5477 *
5478 * Returns 0 if the document is schemas valid, a positive error code
5479 * number otherwise and -1 in case of internal or API error.
5480 */
5481int
5482xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5483 int ret;
5484
5485 if ((ctxt == NULL) || (doc == NULL))
5486 return(-1);
5487
5488 ctxt->doc = doc;
5489 ret = xmlSchemaValidateDocument(ctxt, doc);
5490 return(ret);
5491}
5492
5493/**
5494 * xmlSchemaValidateStream:
5495 * @ctxt: a schema validation context
5496 * @input: the input to use for reading the data
5497 * @enc: an optional encoding information
5498 * @sax: a SAX handler for the resulting events
5499 * @user_data: the context to provide to the SAX handler.
5500 *
5501 * Validate a document tree in memory.
5502 *
5503 * Returns 0 if the document is schemas valid, a positive error code
5504 * number otherwise and -1 in case of internal or API error.
5505 */
5506int
5507xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5508 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5509 xmlSAXHandlerPtr sax, void *user_data) {
5510 if ((ctxt == NULL) || (input == NULL))
5511 return(-1);
5512 ctxt->input = input;
5513 ctxt->enc = enc;
5514 ctxt->sax = sax;
5515 ctxt->user_data = user_data;
5516 TODO
5517 return(0);
5518}
5519
5520#endif /* LIBXML_SCHEMAS_ENABLED */