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