blob: 0f02f211af9946e47ebaf64d65093976652fe6af [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 Veillard82bbbd42003-05-11 20:16:09 +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;
Daniel Veillard82bbbd42003-05-11 20:16:09 +0000116 xmlNodePtr cur;
Daniel Veillard4255d502002-04-16 15:50:10 +0000117 xmlSchemaTypePtr type;
118
119 xmlRegExecCtxtPtr regexp;
120 xmlSchemaValPtr value;
121
122 int attrNr;
123 int attrBase;
124 int attrMax;
125 xmlSchemaAttrStatePtr attr;
126};
127
128
129/************************************************************************
130 * *
131 * Some predeclarations *
132 * *
133 ************************************************************************/
134static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
135 xmlSchemaTypePtr type,
136 xmlChar *value);
137
138/************************************************************************
139 * *
140 * Allocation functions *
141 * *
142 ************************************************************************/
143
144/**
145 * xmlSchemaNewSchema:
146 * @ctxt: a schema validation context (optional)
147 *
148 * Allocate a new Schema structure.
149 *
150 * Returns the newly allocated structure or NULL in case or error
151 */
152static xmlSchemaPtr
153xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
154{
155 xmlSchemaPtr ret;
156
157 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
158 if (ret == NULL) {
159 if ((ctxt != NULL) && (ctxt->error != NULL))
160 ctxt->error(ctxt->userData, "Out of memory\n");
161 return (NULL);
162 }
163 memset(ret, 0, sizeof(xmlSchema));
164
165 return (ret);
166}
167
168/**
169 * xmlSchemaNewFacet:
Daniel Veillard4255d502002-04-16 15:50:10 +0000170 *
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 */
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003354 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
3355 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3356 elem->name, 1, 1, subtypes);
3357 } else {
3358 xmlAutomataNewCountTrans(ctxt->am, ctxt->state, ctxt->state,
3359 elem->name, elem->minOccurs,
3360 elem->maxOccurs, subtypes);
3361 }
Daniel Veillard7646b182002-04-20 06:41:40 +00003362 subtypes = subtypes->next;
3363 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003364 lax = type->minOccurs == 0;
3365 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3366 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003367 break;
3368 }
3369 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003370 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003371 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3372 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003373 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003374 if (type->baseType != NULL) {
3375 xmlSchemaTypePtr subtypes;
3376
3377 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3378 subtypes = type->subtypes;
3379 while (subtypes != NULL) {
3380 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3381 subtypes = subtypes->next;
3382 }
3383 } else if (type->subtypes != NULL)
3384 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3385 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003386 case XML_SCHEMA_TYPE_GROUP:
3387 case XML_SCHEMA_TYPE_COMPLEX:
3388 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3389 if (type->subtypes != NULL)
3390 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3391 break;
3392 default:
3393 xmlGenericError(xmlGenericErrorContext,
3394 "Found unexpected type %d in %s content model\n",
3395 type->type, name);
3396 return;
3397 }
3398}
3399/**
3400 * xmlSchemaBuildContentModel:
3401 * @typeDecl: the schema type definition
3402 * @ctxt: the schema parser context
3403 *
3404 * Fixes the content model of the element.
3405 */
3406static void
3407xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3408 xmlSchemaParserCtxtPtr ctxt,
3409 const xmlChar *name) {
3410 xmlAutomataStatePtr start;
3411
Daniel Veillard4255d502002-04-16 15:50:10 +00003412 if (elem->contModel != NULL)
3413 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003414 if (elem->subtypes == NULL) {
3415 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003416 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003417 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003418 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3419 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003420 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3421 return;
3422
3423#ifdef DEBUG_CONTENT
3424 xmlGenericError(xmlGenericErrorContext,
3425 "Building content model for %s\n", name);
3426#endif
3427
Daniel Veillard4255d502002-04-16 15:50:10 +00003428 ctxt->am = xmlNewAutomata();
3429 if (ctxt->am == NULL) {
3430 xmlGenericError(xmlGenericErrorContext,
3431 "Cannot create automata for elem %s\n", name);
3432 return;
3433 }
3434 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3435 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3436 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003437 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003438 if (!xmlAutomataIsDeterminist(ctxt->am)) {
3439 xmlGenericError(xmlGenericErrorContext,
3440 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003441 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillard4402ab42002-09-12 16:02:56 +00003442 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003443 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00003444#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillarde19fc232002-04-22 16:01:24 +00003445 xmlGenericError(xmlGenericErrorContext,
3446 "Content model of %s:\n", name);
3447 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003448#endif
Daniel Veillard4402ab42002-09-12 16:02:56 +00003449 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003450 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003451 xmlFreeAutomata(ctxt->am);
3452 ctxt->am = NULL;
3453}
3454
3455/**
3456 * xmlSchemaRefFixupCallback:
3457 * @elem: the schema element context
3458 * @ctxt: the schema parser context
3459 *
3460 * Free the resources associated to the schema parser context
3461 */
3462static void
3463xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3464 xmlSchemaParserCtxtPtr ctxt,
3465 const xmlChar *name,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003466 const xmlChar *context ATTRIBUTE_UNUSED,
3467 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00003468{
3469 if ((ctxt == NULL) || (elem == NULL))
3470 return;
3471 if (elem->ref != NULL) {
3472 xmlSchemaElementPtr elemDecl;
3473
3474 if (elem->subtypes != NULL) {
3475 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3476 if ((ctxt != NULL) && (ctxt->error != NULL))
3477 ctxt->error(ctxt->userData,
3478 "Schemas: element %s have both ref and subtype\n",
3479 name);
3480 return;
3481 }
3482 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3483 elem->ref, elem->refNs);
3484
3485 if (elemDecl == NULL) {
3486 if ((ctxt != NULL) && (ctxt->error != NULL))
3487 ctxt->error(ctxt->userData,
3488 "Schemas: element %s ref to %s not found\n",
3489 name, elem->ref);
3490 return;
3491 }
3492 elem->refDecl = elemDecl;
3493 } else if (elem->namedType != NULL) {
3494 xmlSchemaTypePtr typeDecl;
3495
3496 if (elem->subtypes != NULL) {
3497 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3498 if ((ctxt != NULL) && (ctxt->error != NULL))
3499 ctxt->error(ctxt->userData,
3500 "Schemas: element %s have both type and subtype\n",
3501 name);
3502 return;
3503 }
3504 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3505 elem->namedTypeNs);
3506
3507 if (typeDecl == NULL) {
3508 if ((ctxt != NULL) && (ctxt->error != NULL))
3509 ctxt->error(ctxt->userData,
3510 "Schemas: element %s type %s not found\n",
3511 name, elem->namedType);
3512 return;
3513 }
3514 elem->subtypes = typeDecl;
3515 }
3516}
3517
3518/**
3519 * xmlSchemaTypeFixup:
3520 * @typeDecl: the schema type definition
3521 * @ctxt: the schema parser context
3522 *
3523 * Fixes the content model of the type.
3524 */
3525static void
3526xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3527 xmlSchemaParserCtxtPtr ctxt,
3528 const xmlChar *name)
3529{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003530 if (typeDecl == NULL)
3531 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003532 if (name == NULL)
3533 name = typeDecl->name;
3534 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3535 switch (typeDecl->type) {
3536 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3537 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003538 if (typeDecl->subtypes != NULL)
3539 typeDecl->contentType = typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003540 break;
3541 }
3542 case XML_SCHEMA_TYPE_RESTRICTION: {
3543 if (typeDecl->subtypes != NULL)
3544 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3545
3546 if (typeDecl->base != NULL) {
3547 xmlSchemaTypePtr baseType;
3548
3549 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3550 typeDecl->baseNs);
3551 if (baseType == NULL) {
3552 if ((ctxt != NULL) && (ctxt->error != NULL))
3553 ctxt->error(ctxt->userData,
3554 "Schemas: type %s base type %s not found\n",
3555 name, typeDecl->base);
3556 }
3557 typeDecl->baseType = baseType;
3558 }
3559 if (typeDecl->subtypes == NULL)
3560 /* 1.1.1 */
3561 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3562 else if ((typeDecl->subtypes->subtypes == NULL) &&
3563 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3564 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3565 /* 1.1.2 */
3566 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3567 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3568 (typeDecl->subtypes->subtypes == NULL))
3569 /* 1.1.3 */
3570 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3571 else {
3572 /* 1.2 and 2.X are applied at the other layer */
3573 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3574 }
3575 break;
3576 }
3577 case XML_SCHEMA_TYPE_EXTENSION: {
3578 xmlSchemaContentType explicitContentType;
3579 xmlSchemaTypePtr base;
3580
3581 if (typeDecl->base != NULL) {
3582 xmlSchemaTypePtr baseType;
3583
3584 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3585 typeDecl->baseNs);
3586 if (baseType == NULL) {
3587 if ((ctxt != NULL) && (ctxt->error != NULL))
3588 ctxt->error(ctxt->userData,
3589 "Schemas: type %s base type %s not found\n",
3590 name, typeDecl->base);
3591 }
3592 typeDecl->baseType = baseType;
3593 }
3594 if (typeDecl->subtypes != NULL)
3595 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3596
Daniel Veillard8651f532002-04-17 09:06:27 +00003597 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003598 if (typeDecl->subtypes == NULL)
3599 /* 1.1.1 */
3600 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3601 else if ((typeDecl->subtypes->subtypes == NULL) &&
3602 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3603 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3604 /* 1.1.2 */
3605 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3606 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3607 (typeDecl->subtypes->subtypes == NULL))
3608 /* 1.1.3 */
3609 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3610
3611 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3612 typeDecl->baseNs);
3613 if (base == NULL) {
3614 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3615 if ((ctxt != NULL) && (ctxt->error != NULL))
3616 ctxt->error(ctxt->userData,
3617 "Schemas: base type %s of type %s not found\n",
3618 typeDecl->base, name);
3619 return;
3620 }
3621 xmlSchemaTypeFixup(base, ctxt, NULL);
3622 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3623 /* 2.1 */
3624 typeDecl->contentType = base->contentType;
3625 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3626 /* 2.2 imbitable ! */
3627 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3628 } else {
3629 /* 2.3 imbitable pareil ! */
3630 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3631 }
3632 break;
3633 }
3634 case XML_SCHEMA_TYPE_COMPLEX: {
3635 if (typeDecl->subtypes == NULL) {
3636 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3637 } else {
3638 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3639 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3640 else {
3641 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003642 if (typeDecl->subtypes != NULL)
3643 typeDecl->contentType =
3644 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003645 }
3646 }
3647 break;
3648 }
3649 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3650 if (typeDecl->subtypes == NULL) {
3651 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3652 } else {
3653 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3654 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3655 else {
3656 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003657 if (typeDecl->subtypes != NULL)
3658 typeDecl->contentType =
3659 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003660 }
3661 }
3662 break;
3663 }
3664 case XML_SCHEMA_TYPE_SEQUENCE:
3665 case XML_SCHEMA_TYPE_GROUP:
3666 case XML_SCHEMA_TYPE_ALL:
3667 case XML_SCHEMA_TYPE_CHOICE:
3668 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3669 break;
3670 case XML_SCHEMA_TYPE_BASIC:
3671 case XML_SCHEMA_TYPE_ANY:
3672 case XML_SCHEMA_TYPE_FACET:
3673 case XML_SCHEMA_TYPE_SIMPLE:
3674 case XML_SCHEMA_TYPE_UR:
3675 case XML_SCHEMA_TYPE_ELEMENT:
3676 case XML_SCHEMA_TYPE_ATTRIBUTE:
Daniel Veillard118aed72002-09-24 14:13:13 +00003677 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
Daniel Veillard4255d502002-04-16 15:50:10 +00003678 case XML_SCHEMA_TYPE_NOTATION:
3679 case XML_SCHEMA_TYPE_LIST:
3680 case XML_SCHEMA_TYPE_UNION:
3681 case XML_SCHEMA_FACET_MININCLUSIVE:
3682 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3683 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3684 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3685 case XML_SCHEMA_FACET_TOTALDIGITS:
3686 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3687 case XML_SCHEMA_FACET_PATTERN:
3688 case XML_SCHEMA_FACET_ENUMERATION:
3689 case XML_SCHEMA_FACET_WHITESPACE:
3690 case XML_SCHEMA_FACET_LENGTH:
3691 case XML_SCHEMA_FACET_MAXLENGTH:
3692 case XML_SCHEMA_FACET_MINLENGTH:
3693 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3694 break;
3695 }
3696 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003697#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003698 if (typeDecl->node != NULL) {
3699 xmlGenericError(xmlGenericErrorContext,
3700 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3701 xmlGetLineNo(typeDecl->node));
3702 } else {
3703 xmlGenericError(xmlGenericErrorContext,
3704 "Type of %s :", name);
3705 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003706 switch (typeDecl->contentType) {
3707 case XML_SCHEMA_CONTENT_SIMPLE:
3708 xmlGenericError(xmlGenericErrorContext,
3709 "simple\n"); break;
3710 case XML_SCHEMA_CONTENT_ELEMENTS:
3711 xmlGenericError(xmlGenericErrorContext,
3712 "elements\n"); break;
3713 case XML_SCHEMA_CONTENT_UNKNOWN:
3714 xmlGenericError(xmlGenericErrorContext,
3715 "unknown !!!\n"); break;
3716 case XML_SCHEMA_CONTENT_EMPTY:
3717 xmlGenericError(xmlGenericErrorContext,
3718 "empty\n"); break;
3719 case XML_SCHEMA_CONTENT_MIXED:
3720 xmlGenericError(xmlGenericErrorContext,
3721 "mixed\n"); break;
3722 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3723 xmlGenericError(xmlGenericErrorContext,
3724 "mixed or elems\n"); break;
3725 case XML_SCHEMA_CONTENT_BASIC:
3726 xmlGenericError(xmlGenericErrorContext,
3727 "basic\n"); break;
3728 default:
3729 xmlGenericError(xmlGenericErrorContext,
3730 "not registered !!!\n"); break;
3731 }
3732#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003733}
3734
3735/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003736 * xmlSchemaCheckFacet:
3737 * @facet: the facet
3738 * @typeDecl: the schema type definition
3739 * @ctxt: the schema parser context or NULL
3740 * @name: name of the type
3741 *
3742 * Checks the default values types, especially for facets
3743 *
3744 * Returns 0 if okay or -1 in cae of error
3745 */
3746int
3747xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
3748 xmlSchemaTypePtr typeDecl,
3749 xmlSchemaParserCtxtPtr ctxt,
3750 const xmlChar *name)
3751{
3752 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3753 int ret = 0;
3754
3755 if (nonNegativeIntegerType == NULL) {
3756 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3757 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3758 }
3759 switch (facet->type) {
3760 case XML_SCHEMA_FACET_MININCLUSIVE:
3761 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3762 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3763 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3764 /*
3765 * Okay we need to validate the value
3766 * at that point.
3767 */
3768 xmlSchemaValidCtxtPtr vctxt;
3769
3770 vctxt = xmlSchemaNewValidCtxt(NULL);
3771 if (vctxt == NULL)
3772 break;
3773 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3774 facet->value);
3775 facet->val = vctxt->value;
3776 vctxt->value = NULL;
3777 if (facet->val == NULL) {
3778 /* error code */
3779 if (ctxt != NULL) {
3780 xmlSchemaErrorContext(ctxt, NULL,
3781 facet->node, NULL);
3782 ctxt->error(ctxt->userData,
3783 "Schemas: type %s facet value %s invalid\n",
3784 name, facet->value);
3785 }
3786 ret = -1;
3787 }
3788 xmlSchemaFreeValidCtxt(vctxt);
3789 break;
3790 }
3791 case XML_SCHEMA_FACET_ENUMERATION: {
3792 /*
3793 * Okay we need to validate the value
3794 * at that point.
3795 */
3796 xmlSchemaValidCtxtPtr vctxt;
3797 int tmp;
3798
3799 vctxt = xmlSchemaNewValidCtxt(NULL);
3800 if (vctxt == NULL)
3801 break;
3802 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3803 facet->value);
3804 if (tmp != 0) {
3805 if (ctxt != NULL) {
3806 xmlSchemaErrorContext(ctxt, NULL,
3807 facet->node, NULL);
3808 ctxt->error(ctxt->userData,
3809 "Schemas: type %s enumeration value %s invalid\n",
3810 name, facet->value);
3811 }
3812 ret = -1;
3813 }
3814 xmlSchemaFreeValidCtxt(vctxt);
3815 break;
3816 }
3817 case XML_SCHEMA_FACET_PATTERN:
3818 facet->regexp = xmlRegexpCompile(facet->value);
3819 if (facet->regexp == NULL) {
3820 /* error code */
3821 if (ctxt != NULL) {
3822 ctxt->error(ctxt->userData,
3823 "Schemas: type %s facet regexp %s invalid\n",
3824 name, facet->value);
3825 }
3826 ret = -1;
3827 }
3828 break;
3829 case XML_SCHEMA_FACET_TOTALDIGITS:
3830 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3831 case XML_SCHEMA_FACET_LENGTH:
3832 case XML_SCHEMA_FACET_MAXLENGTH:
3833 case XML_SCHEMA_FACET_MINLENGTH: {
3834 int tmp;
3835
3836 tmp = xmlSchemaValidatePredefinedType(
3837 nonNegativeIntegerType, facet->value,
3838 &facet->val);
3839 if (tmp != 0) {
3840 /* error code */
3841 if (ctxt != NULL) {
3842 xmlSchemaErrorContext(ctxt, NULL,
3843 facet->node, NULL);
3844 ctxt->error(ctxt->userData,
3845 "Schemas: type %s facet value %s invalid\n",
3846 name, facet->value);
3847 }
3848 ret = -1;
3849 }
3850 break;
3851 }
3852 case XML_SCHEMA_FACET_WHITESPACE: {
3853 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
3854 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
3855 } else if (xmlStrEqual(facet->value,
3856 BAD_CAST"replace")) {
3857 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
3858 } else if (xmlStrEqual(facet->value,
3859 BAD_CAST"collapse")) {
3860 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
3861 } else {
3862 if (ctxt != NULL) {
3863 xmlSchemaErrorContext(ctxt, NULL,
3864 facet->node, NULL);
3865 ctxt->error(ctxt->userData,
3866 "Schemas: type %s whiteSpace value %s invalid\n",
3867 name, facet->value);
3868 }
3869 ret = -1;
3870 }
3871 }
3872 default:
3873 break;
3874 }
3875 return(ret);
3876}
3877
3878/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003879 * xmlSchemaCheckDefaults:
3880 * @typeDecl: the schema type definition
3881 * @ctxt: the schema parser context
3882 *
3883 * Checks the default values types, especially for facets
3884 */
3885static void
3886xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
3887 xmlSchemaParserCtxtPtr ctxt,
3888 const xmlChar *name)
3889{
Daniel Veillard4255d502002-04-16 15:50:10 +00003890 if (name == NULL)
3891 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00003892 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
3893 if (typeDecl->facets != NULL) {
3894 xmlSchemaFacetPtr facet = typeDecl->facets;
3895 while (facet != NULL) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003896 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00003897 facet = facet->next;
3898 }
3899 }
3900 }
3901}
3902
3903/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00003904 * xmlSchemaAttrGrpFixup:
3905 * @attrgrpDecl: the schema attribute definition
3906 * @ctxt: the schema parser context
3907 * @name: the attribute name
3908 *
3909 * Fixes finish doing the computations on the attributes definitions
3910 */
3911static void
3912xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
3913 xmlSchemaParserCtxtPtr ctxt,
3914 const xmlChar *name)
3915{
3916 if (name == NULL)
3917 name = attrgrpDecl->name;
3918 if (attrgrpDecl->attributes != NULL)
3919 return;
3920 if (attrgrpDecl->ref != NULL) {
3921 xmlSchemaAttributeGroupPtr ref;
3922
3923 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
3924 attrgrpDecl->refNs);
3925 if (ref == NULL) {
3926 if ((ctxt != NULL) && (ctxt->error != NULL))
3927 ctxt->error(ctxt->userData,
3928 "Schemas: attribute group %s reference %s not found\n",
3929 name, attrgrpDecl->ref);
3930 return;
3931 }
3932 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
3933 attrgrpDecl->attributes = ref->attributes;
3934 } else {
3935 if ((ctxt != NULL) && (ctxt->error != NULL))
3936 ctxt->error(ctxt->userData,
3937 "Schemas: attribute %s has no attributes nor reference\n",
3938 name);
3939 }
3940}
3941
3942/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003943 * xmlSchemaAttrFixup:
3944 * @attrDecl: the schema attribute definition
3945 * @ctxt: the schema parser context
3946 * @name: the attribute name
3947 *
3948 * Fixes finish doing the computations on the attributes definitions
3949 */
3950static void
3951xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
3952 xmlSchemaParserCtxtPtr ctxt,
3953 const xmlChar *name)
3954{
3955 if (name == NULL)
3956 name = attrDecl->name;
3957 if (attrDecl->subtypes != NULL)
3958 return;
3959 if (attrDecl->typeName != NULL) {
3960 xmlSchemaTypePtr type;
3961
3962 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
3963 attrDecl->typeNs);
3964 if (type == NULL) {
3965 if ((ctxt != NULL) && (ctxt->error != NULL))
3966 ctxt->error(ctxt->userData,
3967 "Schemas: attribute %s type %s not found\n",
3968 name, attrDecl->typeName);
3969 }
3970 attrDecl->subtypes = type;
3971 } else if (attrDecl->ref != NULL) {
3972 xmlSchemaAttributePtr ref;
3973
3974 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
3975 attrDecl->refNs);
3976 if (ref == NULL) {
3977 if ((ctxt != NULL) && (ctxt->error != NULL))
3978 ctxt->error(ctxt->userData,
3979 "Schemas: attribute %s reference %s not found\n",
3980 name, attrDecl->ref);
3981 return;
3982 }
3983 xmlSchemaAttrFixup(ref, ctxt, NULL);
3984 attrDecl->subtypes = ref->subtypes;
3985 } else {
3986 if ((ctxt != NULL) && (ctxt->error != NULL))
3987 ctxt->error(ctxt->userData,
3988 "Schemas: attribute %s has no type nor reference\n",
3989 name);
3990 }
3991}
3992
3993/**
3994 * xmlSchemaParse:
3995 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00003996 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00003997 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00003998 * XML Shema struture which can be used to validate instances.
3999 * *WARNING* this interface is highly subject to change
4000 *
4001 * Returns the internal XML Schema structure built from the resource or
4002 * NULL in case of error
4003 */
4004xmlSchemaPtr
4005xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4006{
4007 xmlSchemaPtr ret = NULL;
4008 xmlDocPtr doc;
4009 xmlNodePtr root, cur, delete;
4010
4011 xmlSchemaInitTypes();
4012
Daniel Veillard6045c902002-10-09 21:13:59 +00004013 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004014 return (NULL);
4015
4016 ctxt->counter = 0;
4017 ctxt->container = NULL;
4018
4019 /*
4020 * First step is to parse the input document into an DOM/Infoset
4021 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004022 if (ctxt->URL != NULL) {
4023 doc = xmlParseFile((const char *) ctxt->URL);
4024 if (doc == NULL) {
4025 if (ctxt->error != NULL)
4026 ctxt->error(ctxt->userData,
4027 "xmlSchemaParse: could not load %s\n", ctxt->URL);
4028 return (NULL);
4029 }
4030 } else if (ctxt->buffer != NULL) {
4031 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
4032 if (doc == NULL) {
4033 if (ctxt->error != NULL)
4034 ctxt->error(ctxt->userData,
4035 "xmlSchemaParse: could not parse schemas\n");
4036 return (NULL);
4037 }
4038 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4039 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4040 } else {
4041 if (ctxt->error != NULL)
4042 ctxt->error(ctxt->userData,
4043 "xmlSchemaParse: nothing to parse\n");
4044 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004045 }
4046
4047 /*
4048 * Then extract the root and Schema parse it
4049 */
4050 root = xmlDocGetRootElement(doc);
4051 if (root == NULL) {
4052 if (ctxt->error != NULL)
4053 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
4054 ctxt->URL);
4055 return (NULL);
4056 }
4057
4058 /*
4059 * Remove all the blank text nodes
4060 */
4061 delete = NULL;
4062 cur = root;
4063 while (cur != NULL) {
4064 if (delete != NULL) {
4065 xmlUnlinkNode(delete);
4066 xmlFreeNode(delete);
4067 delete = NULL;
4068 }
4069 if (cur->type == XML_TEXT_NODE) {
4070 if (IS_BLANK_NODE(cur)) {
4071 if (xmlNodeGetSpacePreserve(cur) != 1) {
4072 delete = cur;
4073 }
4074 }
4075 } else if ((cur->type != XML_ELEMENT_NODE) &&
4076 (cur->type != XML_CDATA_SECTION_NODE)) {
4077 delete = cur;
4078 goto skip_children;
4079 }
4080
4081 /*
4082 * Skip to next node
4083 */
4084 if (cur->children != NULL) {
4085 if ((cur->children->type != XML_ENTITY_DECL) &&
4086 (cur->children->type != XML_ENTITY_REF_NODE) &&
4087 (cur->children->type != XML_ENTITY_NODE)) {
4088 cur = cur->children;
4089 continue;
4090 }
4091 }
4092skip_children:
4093 if (cur->next != NULL) {
4094 cur = cur->next;
4095 continue;
4096 }
4097
4098 do {
4099 cur = cur->parent;
4100 if (cur == NULL)
4101 break;
4102 if (cur == root) {
4103 cur = NULL;
4104 break;
4105 }
4106 if (cur->next != NULL) {
4107 cur = cur->next;
4108 break;
4109 }
4110 } while (cur != NULL);
4111 }
4112 if (delete != NULL) {
4113 xmlUnlinkNode(delete);
4114 xmlFreeNode(delete);
4115 delete = NULL;
4116 }
4117
4118 /*
4119 * Then do the parsing for good
4120 */
4121 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00004122 if (ret == NULL)
4123 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004124 ret->doc = doc;
4125
4126 /*
4127 * Then fix all the references.
4128 */
4129 ctxt->schema = ret;
4130 xmlHashScanFull(ret->elemDecl,
4131 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
4132
4133 /*
4134 * Then fixup all types properties
4135 */
4136 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
4137
4138 /*
4139 * Then build the content model for all elements
4140 */
4141 xmlHashScan(ret->elemDecl,
4142 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
4143
4144 /*
4145 * Then check the defaults part of the type like facets values
4146 */
4147 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
4148
4149 /*
4150 * Then fixup all attributes declarations
4151 */
4152 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4153
Daniel Veillard13e04c62002-04-23 17:51:29 +00004154 /*
4155 * Then fixup all attributes group declarations
4156 */
4157 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
4158
Daniel Veillard4255d502002-04-16 15:50:10 +00004159 return (ret);
4160}
4161
4162/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004163 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00004164 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00004165 * @err: the error callback
4166 * @warn: the warning callback
4167 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00004168 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004169 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004170 */
4171void
4172xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
4173 xmlSchemaValidityErrorFunc err,
4174 xmlSchemaValidityWarningFunc warn, void *ctx) {
4175 if (ctxt == NULL)
4176 return;
4177 ctxt->error = err;
4178 ctxt->warning = warn;
4179 ctxt->userData = ctx;
4180}
4181
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004182/**
4183 * xmlSchemaFacetTypeToString:
4184 * @type: the facet type
4185 *
4186 * Convert the xmlSchemaTypeType to a char string.
4187 *
4188 * Returns the char string representation of the facet type if the
4189 * type is a facet and an "Internal Error" string otherwise.
4190 */
4191static const char *
4192xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
4193{
4194 switch (type) {
4195 case XML_SCHEMA_FACET_PATTERN:
4196 return ("pattern");
4197 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4198 return ("maxExclusive");
4199 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4200 return ("maxInclusive");
4201 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4202 return ("minExclusive");
4203 case XML_SCHEMA_FACET_MININCLUSIVE:
4204 return ("minInclusive");
4205 case XML_SCHEMA_FACET_WHITESPACE:
4206 return ("whiteSpace");
4207 case XML_SCHEMA_FACET_ENUMERATION:
4208 return ("enumeration");
4209 case XML_SCHEMA_FACET_LENGTH:
4210 return ("length");
4211 case XML_SCHEMA_FACET_MAXLENGTH:
4212 return ("maxLength");
4213 case XML_SCHEMA_FACET_MINLENGTH:
4214 return ("minLength");
4215 case XML_SCHEMA_FACET_TOTALDIGITS:
4216 return ("totalDigits");
4217 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4218 return ("fractionDigits");
4219 default:
4220 break;
4221 }
4222 return ("Internal Error");
4223}
4224
4225/**
4226 * xmlSchemaValidateFacets:
4227 * @ctxt: a schema validation context
4228 * @base: the base type
4229 * @facets: the list of facets to check
4230 * @value: the lexical repr of the value to validate
4231 * @val: the precomputed value
4232 *
4233 * Check a value against all facet conditions
4234 *
4235 * Returns 0 if the element is schemas valid, a positive error code
4236 * number otherwise and -1 in case of internal or API error.
4237 */
4238static int
4239xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
4240 xmlSchemaTypePtr base,
4241 xmlSchemaFacetPtr facets,
4242 xmlChar *value) {
4243 int ret = 0;
4244 int tmp = 0;
4245 xmlSchemaTypeType type;
4246 xmlSchemaFacetPtr facet = facets;
4247
4248 while (facet != NULL) {
4249 type = facet->type;
4250 if (type == XML_SCHEMA_FACET_ENUMERATION) {
4251 tmp = 1;
4252
4253 while (facet != NULL) {
4254 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4255 if (tmp == 0) {
4256 return 0;
4257 }
4258 facet = facet->next;
4259 }
4260 } else
4261 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4262
4263 if (tmp != 0) {
4264 ret = tmp;
4265 if (ctxt->error != NULL)
4266 ctxt->error(ctxt->userData,
4267 "Failed to validate type with facet %s\n",
4268 xmlSchemaFacetTypeToString(type));
4269 ctxt->err = XML_SCHEMAS_ERR_FACET;
4270 }
4271 if (facet != NULL)
4272 facet = facet->next;
4273 }
4274 return (ret);
4275}
4276
Daniel Veillard4255d502002-04-16 15:50:10 +00004277/************************************************************************
4278 * *
4279 * Simple type validation *
4280 * *
4281 ************************************************************************/
4282
4283/**
4284 * xmlSchemaValidateSimpleValue:
4285 * @ctxt: a schema validation context
4286 * @type: the type declaration
4287 * @value: the value to validate
4288 *
4289 * Validate a value against a simple type
4290 *
4291 * Returns 0 if the value is valid, a positive error code
4292 * number otherwise and -1 in case of internal or API error.
4293 */
4294static int
4295xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4296 xmlSchemaTypePtr type,
4297 xmlChar *value) {
4298 int ret = 0;
4299 /*
4300 * First normalize the value accordingly to Schema Datatype
4301 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4302 */
4303 /*
4304 * Then check the normalized value against the lexical space of the
4305 * type.
4306 */
4307 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4308 if (ctxt->value != NULL) {
4309 xmlSchemaFreeValue(ctxt->value);
4310 ctxt->value = NULL;
4311 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004312 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
4313 ctxt->cur);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004314 if (ret != 0) {
4315 if (ctxt->error != NULL)
4316 ctxt->error(ctxt->userData,
4317 "Failed to validate basic type %s\n", type->name);
4318 ctxt->err = XML_SCHEMAS_ERR_VALUE;
4319 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004320 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4321 xmlSchemaTypePtr base;
4322 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00004323
4324 base = type->baseType;
4325 if (base != NULL) {
4326 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4327 } else if (type->subtypes != NULL) {
4328
4329 }
4330 /*
4331 * Do not validate facets when working on building the Schemas
4332 */
4333 if (ctxt->schema != NULL) {
4334 if (ret == 0) {
4335 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004336 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004337 }
4338 }
4339 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4340 xmlSchemaTypePtr base;
4341
4342 base = type->subtypes;
4343 if (base != NULL) {
4344 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4345 } else {
4346 TODO
4347 }
4348 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4349 xmlSchemaTypePtr base;
4350 xmlChar *cur, *end, tmp;
4351 int ret2;
4352
4353 base = type->subtypes;
4354 if (base == NULL) {
4355 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4356 if (ctxt->error != NULL) {
4357 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4358 ctxt->error(ctxt->userData,
4359 "Internal: List type %s has no base type\n",
4360 type->name);
4361 }
4362 return(-1);
4363 }
4364 cur = value;
4365 do {
4366 while (IS_BLANK(*cur)) cur++;
4367 end = cur;
4368 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4369 if (end == cur)
4370 break;
4371 tmp = *end;
4372 *end = 0;
4373 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4374 if (ret2 != 0)
4375 ret = 1;
4376 *end = tmp;
4377 cur = end;
4378 } while (*cur != 0);
4379 } else {
4380 TODO
4381 }
4382 return(ret);
4383}
4384
4385/************************************************************************
4386 * *
4387 * DOM Validation code *
4388 * *
4389 ************************************************************************/
4390
4391static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4392 xmlNodePtr node);
4393static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4394 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4395static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4396 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4397
4398/**
4399 * xmlSchemaRegisterAttributes:
4400 * @ctxt: a schema validation context
4401 * @attrs: a list of attributes
4402 *
4403 * Register the list of attributes as the set to be validated on that element
4404 *
4405 * Returns -1 in case of error, 0 otherwise
4406 */
4407static int
4408xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4409 xmlAttrPtr attrs) {
4410 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004411 if ((attrs->ns != NULL) &&
4412 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4413 attrs = attrs->next;
4414 continue;
4415 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004416 if (ctxt->attrNr >= ctxt->attrMax) {
4417 xmlSchemaAttrStatePtr tmp;
4418
4419 ctxt->attrMax *= 2;
4420 tmp = (xmlSchemaAttrStatePtr)
4421 xmlRealloc(ctxt->attr, ctxt->attrMax *
4422 sizeof(xmlSchemaAttrState));
4423 if (tmp == NULL) {
4424 ctxt->attrMax /= 2;
4425 return(-1);
4426 }
4427 ctxt->attr = tmp;
4428 }
4429 ctxt->attr[ctxt->attrNr].attr = attrs;
4430 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4431 ctxt->attrNr++;
4432 attrs = attrs->next;
4433 }
4434 return(0);
4435}
4436
4437/**
4438 * xmlSchemaCheckAttributes:
4439 * @ctxt: a schema validation context
4440 * @node: the node carrying it.
4441 *
4442 * Check that the registered set of attributes on the current node
4443 * has been properly validated.
4444 *
4445 * Returns 0 if validity constraints are met, 1 otherwise.
4446 */
4447static int
4448xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4449 int ret = 0;
4450 int i;
4451
4452 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4453 if (ctxt->attr[i].attr == NULL)
4454 break;
4455 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4456 ret = 1;
4457 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
4458 if (ctxt->error != NULL)
4459 ctxt->error(ctxt->userData,
4460 "Attribute %s on %s is unknown\n",
4461 ctxt->attr[i].attr->name,
4462 node->name);
4463 }
4464 }
4465 return(ret);
4466}
4467
4468/**
4469 * xmlSchemaValidateSimpleContent:
4470 * @ctxt: a schema validation context
4471 * @elem: an element
4472 * @type: the type declaration
4473 *
4474 * Validate the content of an element expected to be a simple type
4475 *
4476 * Returns 0 if the element is schemas valid, a positive error code
4477 * number otherwise and -1 in case of internal or API error.
4478 */
4479static int
4480xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004481 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004482 xmlNodePtr child;
4483 xmlSchemaTypePtr type, base;
4484 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004485 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004486
4487 child = ctxt->node;
4488 type = ctxt->type;
4489
4490 /*
4491 * Validation Rule: Element Locally Valid (Type): 3.1.3
4492 */
4493 value = xmlNodeGetContent(child);
4494 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4495 switch (type->type) {
4496 case XML_SCHEMA_TYPE_RESTRICTION: {
4497 xmlSchemaFacetPtr facet;
4498
4499 base = type->baseType;
4500 if (base != NULL) {
4501 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4502 } else {
4503 TODO
4504 }
4505 if (ret == 0) {
4506 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004507 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004508 }
4509 break;
4510 }
4511 default:
4512 TODO
4513 }
4514 if (value != NULL)
4515 xmlFree(value);
4516
4517 return(ret);
4518}
4519
4520/**
4521 * xmlSchemaValidateCheckNodeList
4522 * @nodelist: the list of nodes
4523 *
4524 * Check the node list is only made of text nodes and entities pointing
4525 * to text nodes
4526 *
4527 * Returns 1 if true, 0 if false and -1 in case of error
4528 */
4529static int
4530xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4531 while (nodelist != NULL) {
4532 if (nodelist->type == XML_ENTITY_REF_NODE) {
4533 TODO /* implement recursion in the entity content */
4534 }
4535 if ((nodelist->type != XML_TEXT_NODE) &&
4536 (nodelist->type != XML_COMMENT_NODE) &&
4537 (nodelist->type != XML_PI_NODE) &&
4538 (nodelist->type != XML_PI_NODE)) {
4539 return(0);
4540 }
4541 nodelist = nodelist->next;
4542 }
4543 return(1);
4544}
4545
4546/**
4547 * xmlSchemaSkipIgnored:
4548 * @ctxt: a schema validation context
4549 * @type: the current type context
4550 * @node: the top node.
4551 *
4552 * Skip ignorable nodes in that context
4553 *
4554 * Returns the new sibling
4555 * number otherwise and -1 in case of internal or API error.
4556 */
4557static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004558xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004559 xmlSchemaTypePtr type,
4560 xmlNodePtr node) {
4561 int mixed = 0;
4562 /*
4563 * TODO complete and handle entities
4564 */
4565 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4566 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4567 while ((node != NULL) &&
4568 ((node->type == XML_COMMENT_NODE) ||
4569 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4570 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4571 (node->type == XML_TEXT_NODE) &&
4572 (IS_BLANK_NODE(node)))))) {
4573 node = node->next;
4574 }
4575 return(node);
4576}
4577
4578/**
4579 * xmlSchemaValidateCallback:
4580 * @ctxt: a schema validation context
4581 * @name: the name of the element detected (might be NULL)
4582 * @type: the type
4583 *
4584 * A transition has been made in the automata associated to an element
4585 * content model
4586 */
4587static void
4588xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004589 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004590 xmlSchemaTypePtr type,
4591 xmlNodePtr node) {
4592 xmlSchemaTypePtr oldtype = ctxt->type;
4593 xmlNodePtr oldnode = ctxt->node;
4594#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004595 xmlGenericError(xmlGenericErrorContext,
4596 "xmlSchemaValidateCallback: %s, %s, %s\n",
4597 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004598#endif
4599 ctxt->type = type;
4600 ctxt->node = node;
4601 xmlSchemaValidateContent(ctxt, node);
4602 ctxt->type = oldtype;
4603 ctxt->node = oldnode;
4604}
4605
4606
4607#if 0
4608/**
4609 * xmlSchemaValidateSimpleRestrictionType:
4610 * @ctxt: a schema validation context
4611 * @node: the top node.
4612 *
4613 * Validate the content of a restriction type.
4614 *
4615 * Returns 0 if the element is schemas valid, a positive error code
4616 * number otherwise and -1 in case of internal or API error.
4617 */
4618static int
4619xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4620 xmlNodePtr node)
4621{
4622 xmlNodePtr child;
4623 xmlSchemaTypePtr type;
4624 int ret;
4625
4626 child = ctxt->node;
4627 type = ctxt->type;
4628
4629 if ((ctxt == NULL) || (type == NULL)) {
4630 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4631 if (ctxt->error != NULL)
4632 ctxt->error(ctxt->userData,
4633 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4634 node->name);
4635 return (-1);
4636 }
4637 /*
4638 * Only text and text based entities references shall be found there
4639 */
4640 ret = xmlSchemaValidateCheckNodeList(child);
4641 if (ret < 0) {
4642 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4643 if (ctxt->error != NULL)
4644 ctxt->error(ctxt->userData,
4645 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4646 node->name);
4647 return (-1);
4648 } else if (ret == 0) {
4649 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4650 if (ctxt->error != NULL)
4651 ctxt->error(ctxt->userData,
4652 "Element %s content is not a simple type\n",
4653 node->name);
4654 return (-1);
4655 }
4656 ctxt->type = type->subtypes;
4657 xmlSchemaValidateContent(ctxt, node);
4658 ctxt->type = type;
4659 return (ret);
4660}
4661#endif
4662
4663/**
4664 * xmlSchemaValidateSimpleType:
4665 * @ctxt: a schema validation context
4666 * @node: the top node.
4667 *
4668 * Validate the content of an simple type.
4669 *
4670 * Returns 0 if the element is schemas valid, a positive error code
4671 * number otherwise and -1 in case of internal or API error.
4672 */
4673static int
4674xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4675 xmlNodePtr child;
4676 xmlSchemaTypePtr type;
4677 xmlAttrPtr attr;
4678 int ret;
4679
4680 child = ctxt->node;
4681 type = ctxt->type;
4682
4683 if ((ctxt == NULL) || (type == NULL)) {
4684 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4685 if (ctxt->error != NULL)
4686 ctxt->error(ctxt->userData,
4687 "Internal error: xmlSchemaValidateSimpleType %s\n",
4688 node->name);
4689 return(-1);
4690 }
4691 /*
4692 * Only text and text based entities references shall be found there
4693 */
4694 ret = xmlSchemaValidateCheckNodeList(child);
4695 if (ret < 0) {
4696 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4697 if (ctxt->error != NULL)
4698 ctxt->error(ctxt->userData,
4699 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4700 node->name);
4701 return(-1);
4702 } else if (ret == 0) {
4703 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4704 if (ctxt->error != NULL)
4705 ctxt->error(ctxt->userData,
4706 "Element %s content is not a simple type\n",
4707 node->name);
4708 return(-1);
4709 }
4710 /*
4711 * Validation Rule: Element Locally Valid (Type): 3.1.1
4712 */
4713 attr = node->properties;
4714 while (attr != NULL) {
4715 if ((attr->ns == NULL) ||
4716 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4717 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4718 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4719 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4720 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4721 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4722 if (ctxt->error != NULL)
4723 ctxt->error(ctxt->userData,
4724 "Element %s: attribute %s should not be present\n",
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004725 node->name, attr->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004726 return(ctxt->err);
4727 }
4728 }
4729
4730 ctxt->type = type->subtypes;
4731 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4732 ctxt->type = type;
4733 return(ret);
4734}
4735
4736/**
4737 * xmlSchemaValidateElementType:
4738 * @ctxt: a schema validation context
4739 * @node: the top node.
4740 *
4741 * Validate the content of an element type.
4742 * Validation Rule: Element Locally Valid (Complex Type)
4743 *
4744 * Returns 0 if the element is schemas valid, a positive error code
4745 * number otherwise and -1 in case of internal or API error.
4746 */
4747static int
4748xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4749 xmlNodePtr child;
4750 xmlSchemaTypePtr type;
4751 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4752 xmlSchemaElementPtr decl;
4753 int ret, attrBase;
4754
4755 oldregexp = ctxt->regexp;
4756
4757 child = ctxt->node;
4758 type = ctxt->type;
4759
4760 if ((ctxt == NULL) || (type == NULL)) {
4761 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4762 if (ctxt->error != NULL)
4763 ctxt->error(ctxt->userData,
4764 "Internal error: xmlSchemaValidateElementType\n",
4765 node->name);
4766 return(-1);
4767 }
4768 if (child == NULL) {
4769 if (type->minOccurs > 0) {
4770 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4771 if (ctxt->error != NULL)
4772 ctxt->error(ctxt->userData,
4773 "Element %s: missing child %s\n",
4774 node->name, type->name);
4775 }
4776 return(ctxt->err);
4777 }
4778
4779 /*
4780 * Verify the element matches
4781 */
4782 if (!xmlStrEqual(child->name, type->name)) {
4783 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4784 if (ctxt->error != NULL)
4785 ctxt->error(ctxt->userData,
4786 "Element %s: missing child %s found %s\n",
4787 node->name, type->name, child->name);
4788 return(ctxt->err);
4789 }
4790 /*
4791 * Verify the attributes
4792 */
4793 attrBase = ctxt->attrBase;
4794 ctxt->attrBase = ctxt->attrNr;
4795 xmlSchemaRegisterAttributes(ctxt, child->properties);
4796 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4797 /*
4798 * Verify the element content recursively
4799 */
4800 decl = (xmlSchemaElementPtr) type;
4801 oldregexp = ctxt->regexp;
4802 if (decl->contModel != NULL) {
4803 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4804 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4805 ctxt);
4806#ifdef DEBUG_AUTOMATA
4807 xmlGenericError(xmlGenericErrorContext,
4808 "====> %s\n", node->name);
4809#endif
4810 }
4811 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4812 type->subtypes);
4813
4814 if (decl->contModel != NULL) {
4815 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4816#ifdef DEBUG_AUTOMATA
4817 xmlGenericError(xmlGenericErrorContext,
4818 "====> %s : %d\n", node->name, ret);
4819#endif
4820 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004821 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004822 if (ctxt->error != NULL)
4823 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4824 node->name);
4825 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004826 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004827 if (ctxt->error != NULL)
4828 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4829 node->name);
4830#ifdef DEBUG_CONTENT
4831 } else {
4832 xmlGenericError(xmlGenericErrorContext,
4833 "Element %s content check succeeded\n", node->name);
4834
4835#endif
4836 }
4837 xmlRegFreeExecCtxt(ctxt->regexp);
4838 }
4839 /*
4840 * Verify that all attributes were Schemas-validated
4841 */
4842 xmlSchemaCheckAttributes(ctxt, node);
4843 ctxt->attrNr = ctxt->attrBase;
4844 ctxt->attrBase = attrBase;
4845
4846 ctxt->regexp = oldregexp;
4847
4848 ctxt->node = child;
4849 ctxt->type = type;
4850 return(ctxt->err);
4851}
4852
4853/**
4854 * xmlSchemaValidateBasicType:
4855 * @ctxt: a schema validation context
4856 * @node: the top node.
4857 *
4858 * Validate the content of an element expected to be a basic type type
4859 *
4860 * Returns 0 if the element is schemas valid, a positive error code
4861 * number otherwise and -1 in case of internal or API error.
4862 */
4863static int
4864xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4865 int ret;
4866 xmlNodePtr child, cur;
4867 xmlSchemaTypePtr type;
4868 xmlChar *value; /* lexical representation */
4869
4870 child = ctxt->node;
4871 type = ctxt->type;
4872
4873 if ((ctxt == NULL) || (type == NULL)) {
4874 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4875 if (ctxt->error != NULL)
4876 ctxt->error(ctxt->userData,
4877 "Internal error: xmlSchemaValidateBasicType\n",
4878 node->name);
4879 return(-1);
4880 }
4881 /*
4882 * First check the content model of the node.
4883 */
4884 cur = child;
4885 while (cur != NULL) {
4886 switch (cur->type) {
4887 case XML_TEXT_NODE:
4888 case XML_CDATA_SECTION_NODE:
4889 case XML_PI_NODE:
4890 case XML_COMMENT_NODE:
4891 case XML_XINCLUDE_START:
4892 case XML_XINCLUDE_END:
4893 break;
4894 case XML_ENTITY_REF_NODE:
4895 case XML_ENTITY_NODE:
4896 TODO
4897 break;
4898 case XML_ELEMENT_NODE:
4899 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4900 if (ctxt->error != NULL)
4901 ctxt->error(ctxt->userData,
4902 "Element %s: child %s should not be present\n",
4903 node->name, cur->name);
4904 return(ctxt->err);
4905 case XML_ATTRIBUTE_NODE:
4906 case XML_DOCUMENT_NODE:
4907 case XML_DOCUMENT_TYPE_NODE:
4908 case XML_DOCUMENT_FRAG_NODE:
4909 case XML_NOTATION_NODE:
4910 case XML_HTML_DOCUMENT_NODE:
4911 case XML_DTD_NODE:
4912 case XML_ELEMENT_DECL:
4913 case XML_ATTRIBUTE_DECL:
4914 case XML_ENTITY_DECL:
4915 case XML_NAMESPACE_DECL:
4916#ifdef LIBXML_DOCB_ENABLED
4917 case XML_DOCB_DOCUMENT_NODE:
4918#endif
4919 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4920 if (ctxt->error != NULL)
4921 ctxt->error(ctxt->userData,
4922 "Element %s: node type %d unexpected here\n",
4923 node->name, cur->type);
4924 return(ctxt->err);
4925 }
4926 cur = cur->next;
4927 }
4928 if (child == NULL)
4929 value = NULL;
4930 else
4931 value = xmlNodeGetContent(child->parent);
4932
4933 if (ctxt->value != NULL) {
4934 xmlSchemaFreeValue(ctxt->value);
4935 ctxt->value = NULL;
4936 }
4937 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4938 if (value != NULL)
4939 xmlFree(value);
4940 if (ret != 0) {
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004941 if (ctxt->error != NULL)
4942 ctxt->error(ctxt->userData,
4943 "Element %s: failed to validate basic type %s\n",
4944 node->name, type->name);
Daniel Veillard91a13252003-03-27 23:44:43 +00004945 ctxt->err = XML_SCHEMAS_ERR_VALUE;
Daniel Veillard4255d502002-04-16 15:50:10 +00004946 }
4947 return(ret);
4948}
4949
4950/**
4951 * xmlSchemaValidateComplexType:
4952 * @ctxt: a schema validation context
4953 * @node: the top node.
4954 *
4955 * Validate the content of an element expected to be a complex type type
4956 * xmlschema-1.html#cvc-complex-type
4957 * Validation Rule: Element Locally Valid (Complex Type)
4958 *
4959 * Returns 0 if the element is schemas valid, a positive error code
4960 * number otherwise and -1 in case of internal or API error.
4961 */
4962static int
4963xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4964 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004965 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004966 int ret;
4967
4968 child = ctxt->node;
4969 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004970 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00004971
Daniel Veillard4255d502002-04-16 15:50:10 +00004972 switch (type->contentType) {
4973 case XML_SCHEMA_CONTENT_EMPTY:
4974 if (child != NULL) {
4975 if (ctxt->error != NULL)
4976 ctxt->error(ctxt->userData,
4977 "Element %s is supposed to be empty\n",
4978 node->name);
4979 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00004980 if (type->attributes != NULL) {
4981 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4982 }
4983 subtype = type->subtypes;
4984 while (subtype != NULL) {
4985 ctxt->type = subtype;
4986 xmlSchemaValidateComplexType(ctxt, node);
4987 subtype = subtype->next;
4988 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004989 break;
4990 case XML_SCHEMA_CONTENT_ELEMENTS:
4991 case XML_SCHEMA_CONTENT_MIXED:
4992 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4993 /*
4994 * Skip ignorable nodes in that context
4995 */
4996 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00004997 while (child != NULL) {
4998 if (child->type == XML_ELEMENT_NODE) {
4999 ret = xmlRegExecPushString(ctxt->regexp,
5000 child->name, child);
5001#ifdef DEBUG_AUTOMATA
5002 if (ret < 0)
5003 xmlGenericError(xmlGenericErrorContext,
5004 " --> %s Error\n", child->name);
5005 else
5006 xmlGenericError(xmlGenericErrorContext,
5007 " --> %s\n", child->name);
5008#endif
5009 }
5010 child = child->next;
5011 /*
5012 * Skip ignorable nodes in that context
5013 */
5014 child = xmlSchemaSkipIgnored(ctxt, type, child);
5015 }
5016 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005017 case XML_SCHEMA_CONTENT_BASIC: {
5018 if (type->subtypes != NULL) {
5019 ctxt->type = type->subtypes;
5020 xmlSchemaValidateComplexType(ctxt, node);
5021 }
5022 if (type->baseType != NULL) {
5023 ctxt->type = type->baseType;
5024 xmlSchemaValidateBasicType(ctxt, node);
5025 }
5026 if (type->attributes != NULL) {
5027 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5028 }
5029 ctxt->type = type;
5030 break;
5031 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005032 default:
5033 TODO
5034 xmlGenericError(xmlGenericErrorContext,
5035 "unimplemented content type %d\n",
5036 type->contentType);
5037 }
5038 return(ctxt->err);
5039}
5040
5041/**
5042 * xmlSchemaValidateContent:
5043 * @ctxt: a schema validation context
5044 * @elem: an element
5045 * @type: the type declaration
5046 *
5047 * Validate the content of an element against the type.
5048 *
5049 * Returns 0 if the element is schemas valid, a positive error code
5050 * number otherwise and -1 in case of internal or API error.
5051 */
5052static int
5053xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5054 xmlNodePtr child;
5055 xmlSchemaTypePtr type;
5056
5057 child = ctxt->node;
5058 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005059 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005060
Daniel Veillarde19fc232002-04-22 16:01:24 +00005061 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005062 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00005063
Daniel Veillard4255d502002-04-16 15:50:10 +00005064 switch (type->type) {
5065 case XML_SCHEMA_TYPE_ANY:
5066 /* Any type will do it, fine */
5067 TODO /* handle recursivity */
5068 break;
5069 case XML_SCHEMA_TYPE_COMPLEX:
5070 xmlSchemaValidateComplexType(ctxt, node);
5071 break;
5072 case XML_SCHEMA_TYPE_ELEMENT: {
5073 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
5074 /*
5075 * Handle element reference here
5076 */
5077 if (decl->ref != NULL) {
5078 if (decl->refDecl == NULL) {
5079 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5080 if (ctxt->error != NULL)
5081 ctxt->error(ctxt->userData,
5082 "Internal error: element reference %s not resolved\n",
5083 decl->ref);
5084 return(-1);
5085 }
5086 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
5087 decl = decl->refDecl;
5088 }
5089 xmlSchemaValidateElementType(ctxt, node);
5090 ctxt->type = type;
5091 break;
5092 }
5093 case XML_SCHEMA_TYPE_BASIC:
5094 xmlSchemaValidateBasicType(ctxt, node);
5095 break;
5096 case XML_SCHEMA_TYPE_FACET:
5097 TODO
5098 break;
5099 case XML_SCHEMA_TYPE_SIMPLE:
5100 xmlSchemaValidateSimpleType(ctxt, node);
5101 break;
5102 case XML_SCHEMA_TYPE_SEQUENCE:
5103 TODO
5104 break;
5105 case XML_SCHEMA_TYPE_CHOICE:
5106 TODO
5107 break;
5108 case XML_SCHEMA_TYPE_ALL:
5109 TODO
5110 break;
5111 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5112 TODO
5113 break;
5114 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5115 TODO
5116 break;
5117 case XML_SCHEMA_TYPE_UR:
5118 TODO
5119 break;
5120 case XML_SCHEMA_TYPE_RESTRICTION:
5121 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5122 TODO
5123 break;
5124 case XML_SCHEMA_TYPE_EXTENSION:
5125 TODO
5126 break;
5127 case XML_SCHEMA_TYPE_ATTRIBUTE:
5128 TODO
5129 break;
5130 case XML_SCHEMA_TYPE_GROUP:
5131 TODO
5132 break;
5133 case XML_SCHEMA_TYPE_NOTATION:
5134 TODO
5135 break;
5136 case XML_SCHEMA_TYPE_LIST:
5137 TODO
5138 break;
5139 case XML_SCHEMA_TYPE_UNION:
5140 TODO
5141 break;
5142 case XML_SCHEMA_FACET_MININCLUSIVE:
5143 TODO
5144 break;
5145 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5146 TODO
5147 break;
5148 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5149 TODO
5150 break;
5151 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5152 TODO
5153 break;
5154 case XML_SCHEMA_FACET_TOTALDIGITS:
5155 TODO
5156 break;
5157 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5158 TODO
5159 break;
5160 case XML_SCHEMA_FACET_PATTERN:
5161 TODO
5162 break;
5163 case XML_SCHEMA_FACET_ENUMERATION:
5164 TODO
5165 break;
5166 case XML_SCHEMA_FACET_WHITESPACE:
5167 TODO
5168 break;
5169 case XML_SCHEMA_FACET_LENGTH:
5170 TODO
5171 break;
5172 case XML_SCHEMA_FACET_MAXLENGTH:
5173 TODO
5174 break;
5175 case XML_SCHEMA_FACET_MINLENGTH:
5176 TODO
5177 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00005178 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5179 TODO
5180 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005181 }
5182 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5183
5184 if (ctxt->node == NULL)
5185 return(ctxt->err);
5186 ctxt->node = ctxt->node->next;
5187 ctxt->type = type->next;
5188 return(ctxt->err);
5189}
5190
5191/**
5192 * xmlSchemaValidateType:
5193 * @ctxt: a schema validation context
5194 * @elem: an element
5195 * @type: the list of type declarations
5196 *
5197 * Validate the content of an element against the types.
5198 *
5199 * Returns 0 if the element is schemas valid, a positive error code
5200 * number otherwise and -1 in case of internal or API error.
5201 */
5202static int
5203xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5204 xmlSchemaElementPtr elemDecl,
5205 xmlSchemaTypePtr type) {
5206 xmlChar *nil;
5207
5208 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
5209 return(0);
5210 /*
5211 * 3.3.4 : 2
5212 */
5213 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
5214 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
5215 if (ctxt->error != NULL)
5216 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
5217 return(ctxt->err);
5218 }
5219 /*
5220 * 3.3.4: 3
5221 */
5222 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5223 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
5224 /* 3.3.4: 3.2 */
5225 if (xmlStrEqual(nil, BAD_CAST "true")) {
5226 if (elem->children != NULL) {
5227 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
5228 if (ctxt->error != NULL)
5229 ctxt->error(ctxt->userData, "Element %s is not empty\n",
5230 elem->name);
5231 return(ctxt->err);
5232 }
5233 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5234 (elemDecl->value != NULL)) {
5235 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
5236 if (ctxt->error != NULL)
5237 ctxt->error(ctxt->userData,
5238 "Empty element %s cannot get a fixed value\n",
5239 elem->name);
5240 return(ctxt->err);
5241 }
5242 }
5243 } else {
5244 /* 3.3.4: 3.1 */
5245 if (nil != NULL) {
5246 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
5247 if (ctxt->error != NULL)
5248 ctxt->error(ctxt->userData,
5249 "Element %s with xs:nil but not nillable\n",
5250 elem->name);
5251 xmlFree(nil);
5252 return(ctxt->err);
5253 }
5254 }
5255
5256 /* TODO 3.3.4: 4 if the element carries xs:type*/
5257
5258 ctxt->type = elemDecl->subtypes;
5259 ctxt->node = elem->children;
5260 xmlSchemaValidateContent(ctxt, elem);
5261 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5262
5263 return(ctxt->err);
5264}
5265
5266
5267/**
5268 * xmlSchemaValidateAttributes:
5269 * @ctxt: a schema validation context
5270 * @elem: an element
5271 * @attributes: the list of attribute declarations
5272 *
5273 * Validate the attributes of an element.
5274 *
5275 * Returns 0 if the element is schemas valid, a positive error code
5276 * number otherwise and -1 in case of internal or API error.
5277 */
5278static int
5279xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5280 xmlSchemaAttributePtr attributes) {
5281 int i, ret;
5282 xmlAttrPtr attr;
5283 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005284 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005285
5286 if (attributes == NULL)
5287 return(0);
5288 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005289 /*
5290 * Handle attribute groups
5291 */
5292 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5293 group = (xmlSchemaAttributeGroupPtr) attributes;
5294 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5295 attributes = group->next;
5296 continue;
5297 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005298 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5299 attr = ctxt->attr[i].attr;
5300 if (attr == NULL)
5301 continue;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005302 if (attributes->ref != NULL) {
5303 if (!xmlStrEqual(attr->name, attributes->ref))
5304 continue;
5305 if (attr->ns != NULL) {
5306 if ((attributes->refNs == NULL) ||
5307 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
5308 continue;
5309 } else if (attributes->refNs != NULL) {
5310 continue;
5311 }
5312 } else {
5313 if (!xmlStrEqual(attr->name, attributes->name))
5314 continue;
5315 /*
5316 * TODO: handle the mess about namespaces here.
5317 */
5318 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5319 TODO
5320 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005321 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005322 ctxt->cur = (xmlNodePtr) attributes;
Daniel Veillard4255d502002-04-16 15:50:10 +00005323 if (attributes->subtypes == NULL) {
5324 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5325 if (ctxt->error != NULL)
5326 ctxt->error(ctxt->userData,
5327 "Internal error: attribute %s type not resolved\n",
5328 attr->name);
5329 continue;
5330 }
5331 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5332 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005333 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005334 if (ret != 0) {
5335 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5336 if (ctxt->error != NULL)
5337 ctxt->error(ctxt->userData,
5338 "attribute %s on %s does not match type\n",
5339 attr->name, elem->name);
5340 } else {
5341 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5342 }
5343 if (value != NULL) {
5344 xmlFree(value);
5345 }
5346 }
5347 attributes = attributes->next;
5348 }
5349 return(ctxt->err);
5350}
5351
5352/**
5353 * xmlSchemaValidateElement:
5354 * @ctxt: a schema validation context
5355 * @elem: an element
5356 *
5357 * Validate an element in a tree
5358 *
5359 * Returns 0 if the element is schemas valid, a positive error code
5360 * number otherwise and -1 in case of internal or API error.
5361 */
5362static int
5363xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5364 xmlSchemaElementPtr elemDecl;
5365 int ret, attrBase;
5366
5367 if (elem->ns != NULL)
5368 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5369 elem->name, elem->ns->href, NULL);
5370 else
5371 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5372 elem->name, NULL, NULL);
5373 /*
5374 * 3.3.4 : 1
5375 */
5376 if (elemDecl == NULL) {
5377 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5378 if (ctxt->error != NULL)
5379 ctxt->error(ctxt->userData, "Element %s not declared\n",
5380 elem->name);
5381 return(ctxt->err);
5382 }
5383 if (elemDecl->subtypes == NULL) {
5384 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5385 if (ctxt->error != NULL)
5386 ctxt->error(ctxt->userData, "Element %s has no type\n",
5387 elem->name);
5388 return(ctxt->err);
5389 }
5390 /*
5391 * Verify the attributes
5392 */
5393 attrBase = ctxt->attrBase;
5394 ctxt->attrBase = ctxt->attrNr;
5395 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5396 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5397 /*
5398 * Verify the element content recursively
5399 */
5400 if (elemDecl->contModel != NULL) {
5401 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5402 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5403 ctxt);
5404#ifdef DEBUG_AUTOMATA
5405 xmlGenericError(xmlGenericErrorContext,
5406 "====> %s\n", elem->name);
5407#endif
5408 }
5409 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005410 if (elemDecl->contModel != NULL) {
5411 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005412#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005413 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005414 "====> %s : %d\n", elem->name, ret);
5415#endif
5416 if (ret == 0) {
5417 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5418 if (ctxt->error != NULL)
5419 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5420 elem->name);
5421 } else if (ret < 0) {
5422 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5423 if (ctxt->error != NULL)
5424 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5425 elem->name);
5426#ifdef DEBUG_CONTENT
5427 } else {
5428 xmlGenericError(xmlGenericErrorContext,
5429 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005430
5431#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005432 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005433 xmlRegFreeExecCtxt(ctxt->regexp);
5434 }
5435 /*
5436 * Verify that all attributes were Schemas-validated
5437 */
5438 xmlSchemaCheckAttributes(ctxt, elem);
5439 ctxt->attrNr = ctxt->attrBase;
5440 ctxt->attrBase = attrBase;
5441
5442 return(ctxt->err);
5443}
5444
5445/**
5446 * xmlSchemaValidateDocument:
5447 * @ctxt: a schema validation context
5448 * @doc: a parsed document tree
5449 *
5450 * Validate a document tree in memory.
5451 *
5452 * Returns 0 if the document is schemas valid, a positive error code
5453 * number otherwise and -1 in case of internal or API error.
5454 */
5455static int
5456xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5457 xmlNodePtr root;
5458 xmlSchemaElementPtr elemDecl;
5459
5460 root = xmlDocGetRootElement(doc);
5461 if (root == NULL) {
5462 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
5463 if (ctxt->error != NULL)
5464 ctxt->error(ctxt->userData, "document has no root\n");
5465 return(ctxt->err);
5466 }
5467 if (root->ns != NULL)
5468 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5469 root->name, root->ns->href, NULL);
5470 else
5471 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5472 root->name, NULL, NULL);
5473 if (elemDecl == NULL) {
5474 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5475 if (ctxt->error != NULL)
5476 ctxt->error(ctxt->userData, "Element %s not declared\n",
5477 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005478 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005479 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
5480 if (ctxt->error != NULL)
5481 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5482 root->name);
5483 }
5484 /*
5485 * Okay, start the recursive validation
5486 */
5487 xmlSchemaValidateElement(ctxt, root);
5488
5489 return(ctxt->err);
5490}
5491
5492/************************************************************************
5493 * *
5494 * SAX Validation code *
5495 * *
5496 ************************************************************************/
5497
5498/************************************************************************
5499 * *
5500 * Validation interfaces *
5501 * *
5502 ************************************************************************/
5503
5504/**
5505 * xmlSchemaNewValidCtxt:
5506 * @schema: a precompiled XML Schemas
5507 *
5508 * Create an XML Schemas validation context based on the given schema
5509 *
5510 * Returns the validation context or NULL in case of error
5511 */
5512xmlSchemaValidCtxtPtr
5513xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5514 xmlSchemaValidCtxtPtr ret;
5515
5516 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5517 if (ret == NULL) {
5518 xmlGenericError(xmlGenericErrorContext,
5519 "Failed to allocate new schama validation context\n");
5520 return (NULL);
5521 }
5522 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5523 ret->schema = schema;
5524 ret->attrNr = 0;
5525 ret->attrMax = 10;
5526 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5527 sizeof(xmlSchemaAttrState));
5528 if (ret->attr == NULL) {
5529 free(ret);
5530 return(NULL);
5531 }
5532 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5533 return (ret);
5534}
5535
5536/**
5537 * xmlSchemaFreeValidCtxt:
5538 * @ctxt: the schema validation context
5539 *
5540 * Free the resources associated to the schema validation context
5541 */
5542void
5543xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5544 if (ctxt == NULL)
5545 return;
5546 if (ctxt->attr != NULL)
5547 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005548 if (ctxt->value != NULL)
5549 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005550 xmlFree(ctxt);
5551}
5552
5553/**
5554 * xmlSchemaSetValidErrors:
5555 * @ctxt: a schema validation context
5556 * @err: the error function
5557 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00005558 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00005559 *
5560 * Set the error and warning callback informations
5561 */
5562void
5563xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5564 xmlSchemaValidityErrorFunc err,
5565 xmlSchemaValidityWarningFunc warn, void *ctx) {
5566 if (ctxt == NULL)
5567 return;
5568 ctxt->error = err;
5569 ctxt->warning = warn;
5570 ctxt->userData = ctx;
5571}
5572
5573/**
5574 * xmlSchemaValidateDoc:
5575 * @ctxt: a schema validation context
5576 * @doc: a parsed document tree
5577 *
5578 * Validate a document tree in memory.
5579 *
5580 * Returns 0 if the document is schemas valid, a positive error code
5581 * number otherwise and -1 in case of internal or API error.
5582 */
5583int
5584xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5585 int ret;
5586
5587 if ((ctxt == NULL) || (doc == NULL))
5588 return(-1);
5589
5590 ctxt->doc = doc;
5591 ret = xmlSchemaValidateDocument(ctxt, doc);
5592 return(ret);
5593}
5594
5595/**
5596 * xmlSchemaValidateStream:
5597 * @ctxt: a schema validation context
5598 * @input: the input to use for reading the data
5599 * @enc: an optional encoding information
5600 * @sax: a SAX handler for the resulting events
5601 * @user_data: the context to provide to the SAX handler.
5602 *
5603 * Validate a document tree in memory.
5604 *
5605 * Returns 0 if the document is schemas valid, a positive error code
5606 * number otherwise and -1 in case of internal or API error.
5607 */
5608int
5609xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5610 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5611 xmlSAXHandlerPtr sax, void *user_data) {
5612 if ((ctxt == NULL) || (input == NULL))
5613 return(-1);
5614 ctxt->input = input;
5615 ctxt->enc = enc;
5616 ctxt->sax = sax;
5617 ctxt->user_data = user_data;
5618 TODO
5619 return(0);
5620}
5621
5622#endif /* LIBXML_SCHEMAS_ENABLED */