blob: 7a2dfbe152251522e5c9bfa838dce0404b673156 [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 Veillarda84c0b32003-06-02 16:58:46 +000028/* #define DEBUG 1 */
Daniel Veillard82bbbd42003-05-11 20:16:09 +000029/* #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);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000409 if (schema->groupDecl != NULL)
410 xmlHashFree(schema->groupDecl,
411 (xmlHashDeallocator) xmlSchemaFreeType);
Daniel Veillard4255d502002-04-16 15:50:10 +0000412 if (schema->annot != NULL)
413 xmlSchemaFreeAnnot(schema->annot);
414 if (schema->doc != NULL)
415 xmlFreeDoc(schema->doc);
416
417 xmlFree(schema);
418}
419
420/************************************************************************
421 * *
422 * Error functions *
423 * *
424 ************************************************************************/
425
426/**
427 * xmlSchemaErrorContext:
428 * @ctxt: the parsing context
429 * @schema: the schema being built
430 * @node: the node being processed
431 * @child: the child being processed
432 *
433 * Dump a SchemaType structure
434 */
435static void
436xmlSchemaErrorContext(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
437 xmlNodePtr node, xmlNodePtr child)
438{
439 int line = 0;
440 const xmlChar *file = NULL;
441 const xmlChar *name = NULL;
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000442 const xmlChar *prefix = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +0000443 const char *type = "error";
444
445 if ((ctxt == NULL) || (ctxt->error == NULL))
446 return;
447
448 if (child != NULL)
449 node = child;
450
451 if (node != NULL) {
452 if ((node->type == XML_DOCUMENT_NODE) ||
453 (node->type == XML_HTML_DOCUMENT_NODE)) {
454 xmlDocPtr doc = (xmlDocPtr) node;
455
456 file = doc->URL;
457 } else {
458 /*
459 * Try to find contextual informations to report
460 */
461 if (node->type == XML_ELEMENT_NODE) {
462 line = (int) node->content;
463 } else if ((node->prev != NULL) &&
464 (node->prev->type == XML_ELEMENT_NODE)) {
465 line = (int) node->prev->content;
466 } else if ((node->parent != NULL) &&
467 (node->parent->type == XML_ELEMENT_NODE)) {
468 line = (int) node->parent->content;
469 }
470 if ((node->doc != NULL) && (node->doc->URL != NULL))
471 file = node->doc->URL;
472 if (node->name != NULL)
473 name = node->name;
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000474 if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL) &&
475 (node->ns->prefix != NULL))
476 prefix = node->ns->prefix;
Daniel Veillard4255d502002-04-16 15:50:10 +0000477 }
478 }
479
480 if (ctxt != NULL)
481 type = "compilation error";
482 else if (schema != NULL)
483 type = "runtime error";
484
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000485 if ((file != NULL) && (line != 0) && (name != NULL) && (prefix != NULL))
486 ctxt->error(ctxt->userData, "%s: file %s line %d element %s:%s\n",
487 type, file, line, prefix, name);
488 else if ((file != NULL) && (line != 0) && (name != NULL))
Daniel Veillard4255d502002-04-16 15:50:10 +0000489 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
490 type, file, line, name);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000491 else if ((file != NULL) && (name != NULL) && (prefix != NULL))
492 ctxt->error(ctxt->userData, "%s: file %s element %s:%s\n",
493 type, file, prefix, name);
Daniel Veillard4255d502002-04-16 15:50:10 +0000494 else if ((file != NULL) && (name != NULL))
495 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
496 type, file, name);
497 else if ((file != NULL) && (line != 0))
498 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
499 else if (file != NULL)
500 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000501 else if ((name != NULL) && (prefix != NULL))
502 ctxt->error(ctxt->userData, "%s: element %s:%s\n", type, prefix, name);
Daniel Veillard4255d502002-04-16 15:50:10 +0000503 else if (name != NULL)
504 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
505 else
506 ctxt->error(ctxt->userData, "%s\n", type);
507}
508
509/************************************************************************
510 * *
511 * Debug functions *
512 * *
513 ************************************************************************/
514
515/**
516 * xmlSchemaElementDump:
517 * @elem: an element
518 * @output: the file output
519 *
520 * Dump the element
521 */
522static void
523xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000524 const xmlChar *name ATTRIBUTE_UNUSED,
525 const xmlChar *context ATTRIBUTE_UNUSED,
526 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +0000527{
528 if (elem == NULL)
529 return;
530
531 fprintf(output, "Element ");
532 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
533 fprintf(output, "toplevel ");
534 fprintf(output, ": %s ", elem->name);
535 if (namespace != NULL)
536 fprintf(output, "namespace '%s' ", namespace);
537
538 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
539 fprintf(output, "nillable ");
540 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
541 fprintf(output, "global ");
542 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
543 fprintf(output, "default ");
544 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
545 fprintf(output, "fixed ");
546 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
547 fprintf(output, "abstract ");
548 if (elem->flags & XML_SCHEMAS_ELEM_REF)
549 fprintf(output, "ref '%s' ", elem->ref);
550 if (elem->id != NULL)
551 fprintf(output, "id '%s' ", elem->id);
552 fprintf(output, "\n");
553 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
554 fprintf(output, " ");
555 if (elem->minOccurs != 1)
556 fprintf(output, "min: %d ", elem->minOccurs);
557 if (elem->maxOccurs >= UNBOUNDED)
558 fprintf(output, "max: unbounded\n");
559 else if (elem->maxOccurs != 1)
560 fprintf(output, "max: %d\n", elem->maxOccurs);
561 else
562 fprintf(output, "\n");
563 }
564 if (elem->namedType != NULL) {
565 fprintf(output, " type: %s", elem->namedType);
566 if (elem->namedTypeNs != NULL)
567 fprintf(output, " ns %s\n", elem->namedTypeNs);
568 else
569 fprintf(output, "\n");
570 }
571 if (elem->substGroup != NULL) {
572 fprintf(output, " substitutionGroup: %s", elem->substGroup);
573 if (elem->substGroupNs != NULL)
574 fprintf(output, " ns %s\n", elem->substGroupNs);
575 else
576 fprintf(output, "\n");
577 }
578 if (elem->value != NULL)
579 fprintf(output, " default: %s", elem->value);
580}
581
582/**
583 * xmlSchemaAnnotDump:
584 * @output: the file output
585 * @annot: a annotation
586 *
587 * Dump the annotation
588 */
589static void
590xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
591{
592 xmlChar *content;
593
594 if (annot == NULL)
595 return;
596
597 content = xmlNodeGetContent(annot->content);
598 if (content != NULL) {
599 fprintf(output, " Annot: %s\n", content);
600 xmlFree(content);
601 } else
602 fprintf(output, " Annot: empty\n");
603}
604
605/**
606 * xmlSchemaTypeDump:
607 * @output: the file output
608 * @type: a type structure
609 *
610 * Dump a SchemaType structure
611 */
612static void
613xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
614{
615 if (type == NULL) {
616 fprintf(output, "Type: NULL\n");
617 return;
618 }
619 fprintf(output, "Type: ");
620 if (type->name != NULL)
621 fprintf(output, "%s, ", type->name);
622 else
623 fprintf(output, "no name");
624 switch (type->type) {
625 case XML_SCHEMA_TYPE_BASIC:
626 fprintf(output, "basic ");
627 break;
628 case XML_SCHEMA_TYPE_SIMPLE:
629 fprintf(output, "simple ");
630 break;
631 case XML_SCHEMA_TYPE_COMPLEX:
632 fprintf(output, "complex ");
633 break;
634 case XML_SCHEMA_TYPE_SEQUENCE:
635 fprintf(output, "sequence ");
636 break;
637 case XML_SCHEMA_TYPE_CHOICE:
638 fprintf(output, "choice ");
639 break;
640 case XML_SCHEMA_TYPE_ALL:
641 fprintf(output, "all ");
642 break;
643 case XML_SCHEMA_TYPE_UR:
644 fprintf(output, "ur ");
645 break;
646 case XML_SCHEMA_TYPE_RESTRICTION:
647 fprintf(output, "restriction ");
648 break;
649 case XML_SCHEMA_TYPE_EXTENSION:
650 fprintf(output, "extension ");
651 break;
652 default:
653 fprintf(output, "unknowntype%d ", type->type);
654 break;
655 }
656 if (type->base != NULL) {
657 fprintf(output, "base %s, ", type->base);
658 }
659 switch (type->contentType) {
660 case XML_SCHEMA_CONTENT_UNKNOWN:
661 fprintf(output, "unknown ");
662 break;
663 case XML_SCHEMA_CONTENT_EMPTY:
664 fprintf(output, "empty ");
665 break;
666 case XML_SCHEMA_CONTENT_ELEMENTS:
667 fprintf(output, "element ");
668 break;
669 case XML_SCHEMA_CONTENT_MIXED:
670 fprintf(output, "mixed ");
671 break;
672 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
673 fprintf(output, "mixed_or_elems ");
674 break;
675 case XML_SCHEMA_CONTENT_BASIC:
676 fprintf(output, "basic ");
677 break;
678 case XML_SCHEMA_CONTENT_SIMPLE:
679 fprintf(output, "simple ");
680 break;
Daniel Veillard88c58912002-04-23 07:12:20 +0000681 case XML_SCHEMA_CONTENT_ANY:
682 fprintf(output, "any ");
683 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000684 }
685 fprintf(output, "\n");
686 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
687 fprintf(output, " ");
688 if (type->minOccurs != 1)
689 fprintf(output, "min: %d ", type->minOccurs);
690 if (type->maxOccurs >= UNBOUNDED)
691 fprintf(output, "max: unbounded\n");
692 else if (type->maxOccurs != 1)
693 fprintf(output, "max: %d\n", type->maxOccurs);
694 else
695 fprintf(output, "\n");
696 }
697 if (type->annot != NULL)
698 xmlSchemaAnnotDump(output, type->annot);
699 if (type->subtypes != NULL) {
700 xmlSchemaTypePtr sub = type->subtypes;
701
702 fprintf(output, " subtypes: ");
703 while (sub != NULL) {
704 fprintf(output, "%s ", sub->name);
705 sub = sub->next;
706 }
707 fprintf(output, "\n");
708 }
709
710}
711
712/**
713 * xmlSchemaDump:
714 * @output: the file output
715 * @schema: a schema structure
716 *
717 * Dump a Schema structure.
718 */
719void
720xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
721{
722 if (schema == NULL) {
723 fprintf(output, "Schemas: NULL\n");
724 return;
725 }
726 fprintf(output, "Schemas: ");
727 if (schema->name != NULL)
728 fprintf(output, "%s, ", schema->name);
729 else
730 fprintf(output, "no name, ");
731 if (schema->targetNamespace != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000732 fprintf(output, "%s", (const char *) schema->targetNamespace);
Daniel Veillard4255d502002-04-16 15:50:10 +0000733 else
734 fprintf(output, "no target namespace");
735 fprintf(output, "\n");
736 if (schema->annot != NULL)
737 xmlSchemaAnnotDump(output, schema->annot);
738
739 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
740 output);
741 xmlHashScanFull(schema->elemDecl,
742 (xmlHashScannerFull) xmlSchemaElementDump, output);
743}
744
745/************************************************************************
746 * *
747 * Parsing functions *
748 * *
749 ************************************************************************/
750
751/**
752 * xmlSchemaGetType:
753 * @schema: the schemas context
754 * @name: the type name
755 * @ns: the type namespace
756 *
757 * Lookup a type in the schemas or the predefined types
758 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000759 * Returns the group definition or NULL if not found.
Daniel Veillard4255d502002-04-16 15:50:10 +0000760 */
761static xmlSchemaTypePtr
762xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
763 const xmlChar * namespace) {
764 xmlSchemaTypePtr ret;
765
766 if (name == NULL)
767 return(NULL);
768 if (schema != NULL) {
769 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
770 if (ret != NULL)
771 return(ret);
772 }
773 ret = xmlSchemaGetPredefinedType(name, namespace);
774#ifdef DEBUG
775 if (ret == NULL) {
776 if (namespace == NULL)
777 fprintf(stderr, "Unable to lookup type %s", name);
778 else
779 fprintf(stderr, "Unable to lookup type %s:%s", name, namespace);
780 }
781#endif
782 return(ret);
783}
784
785/************************************************************************
786 * *
787 * Parsing functions *
788 * *
789 ************************************************************************/
790
791#define IS_BLANK_NODE(n) \
792 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
793
794/**
795 * xmlSchemaIsBlank:
796 * @str: a string
797 *
798 * Check if a string is ignorable
799 *
800 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
801 */
802static int
803xmlSchemaIsBlank(xmlChar *str) {
804 if (str == NULL)
805 return(1);
806 while (*str != 0) {
807 if (!(IS_BLANK(*str))) return(0);
808 str++;
809 }
810 return(1);
811}
812
813/**
814 * xmlSchemaAddNotation:
815 * @ctxt: a schema validation context
816 * @schema: the schema being built
817 * @name: the item name
818 *
819 * Add an XML schema Attrribute declaration
820 * *WARNING* this interface is highly subject to change
821 *
822 * Returns the new struture or NULL in case of error
823 */
824static xmlSchemaNotationPtr
825xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
826 const xmlChar * name)
827{
828 xmlSchemaNotationPtr ret = NULL;
829 int val;
830
831 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
832 return (NULL);
833
834 if (schema->notaDecl == NULL)
835 schema->notaDecl = xmlHashCreate(10);
836 if (schema->notaDecl == NULL)
837 return (NULL);
838
839 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
840 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000841 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000842 if ((ctxt != NULL) && (ctxt->error != NULL))
843 ctxt->error(ctxt->userData, "Out of memory\n");
844 return (NULL);
845 }
846 memset(ret, 0, sizeof(xmlSchemaNotation));
847 ret->name = xmlStrdup(name);
848 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
849 ret);
850 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000851 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000852 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000853 ctxt->error(ctxt->userData, "Notation %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000854 name);
855 xmlFree((char *) ret->name);
856 xmlFree(ret);
857 return (NULL);
858 }
859 return (ret);
860}
861
862
863/**
864 * xmlSchemaAddAttribute:
865 * @ctxt: a schema validation context
866 * @schema: the schema being built
867 * @name: the item name
868 * @container: the container's name
869 *
870 * Add an XML schema Attrribute declaration
871 * *WARNING* this interface is highly subject to change
872 *
873 * Returns the new struture or NULL in case of error
874 */
875static xmlSchemaAttributePtr
876xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
877 const xmlChar * name)
878{
879 xmlSchemaAttributePtr ret = NULL;
880 int val;
881
882 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
883 return (NULL);
884
885 if (schema->attrDecl == NULL)
886 schema->attrDecl = xmlHashCreate(10);
887 if (schema->attrDecl == NULL)
888 return (NULL);
889
890 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
891 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000892 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000893 if ((ctxt != NULL) && (ctxt->error != NULL))
894 ctxt->error(ctxt->userData, "Out of memory\n");
895 return (NULL);
896 }
897 memset(ret, 0, sizeof(xmlSchemaAttribute));
898 ret->name = xmlStrdup(name);
899 val = xmlHashAddEntry3(schema->attrDecl, name,
900 schema->targetNamespace, ctxt->container, ret);
901 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000902 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000903 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000904 ctxt->error(ctxt->userData, "Attribute %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000905 name);
906 xmlFree((char *) ret->name);
907 xmlFree(ret);
908 return (NULL);
909 }
910 return (ret);
911}
912
913/**
914 * xmlSchemaAddAttributeGroup:
915 * @ctxt: a schema validation context
916 * @schema: the schema being built
917 * @name: the item name
918 *
919 * Add an XML schema Attrribute Group declaration
920 *
921 * Returns the new struture or NULL in case of error
922 */
923static xmlSchemaAttributeGroupPtr
924xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
925 const xmlChar * name)
926{
927 xmlSchemaAttributeGroupPtr ret = NULL;
928 int val;
929
930 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
931 return (NULL);
932
933 if (schema->attrgrpDecl == NULL)
934 schema->attrgrpDecl = xmlHashCreate(10);
935 if (schema->attrgrpDecl == NULL)
936 return (NULL);
937
938 ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup));
939 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000940 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000941 if ((ctxt != NULL) && (ctxt->error != NULL))
942 ctxt->error(ctxt->userData, "Out of memory\n");
943 return (NULL);
944 }
945 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
946 ret->name = xmlStrdup(name);
947 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
948 schema->targetNamespace, ctxt->container, ret);
949 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000950 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000951 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000952 ctxt->error(ctxt->userData, "Attribute group %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000953 name);
954 xmlFree((char *) ret->name);
955 xmlFree(ret);
956 return (NULL);
957 }
958 return (ret);
959}
960
961/**
962 * xmlSchemaAddElement:
963 * @ctxt: a schema validation context
964 * @schema: the schema being built
965 * @name: the type name
966 * @namespace: the type namespace
967 *
968 * Add an XML schema Element declaration
969 * *WARNING* this interface is highly subject to change
970 *
971 * Returns the new struture or NULL in case of error
972 */
973static xmlSchemaElementPtr
974xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
975 const xmlChar * name, const xmlChar * namespace)
976{
977 xmlSchemaElementPtr ret = NULL;
978 int val;
979
980 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
981 return (NULL);
982
983 if (schema->elemDecl == NULL)
984 schema->elemDecl = xmlHashCreate(10);
985 if (schema->elemDecl == NULL)
986 return (NULL);
987
988 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
989 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000990 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000991 if ((ctxt != NULL) && (ctxt->error != NULL))
992 ctxt->error(ctxt->userData, "Out of memory\n");
993 return (NULL);
994 }
995 memset(ret, 0, sizeof(xmlSchemaElement));
996 ret->name = xmlStrdup(name);
997 val = xmlHashAddEntry3(schema->elemDecl, name,
998 namespace, ctxt->container, ret);
999 if (val != 0) {
1000 char buf[100];
1001
1002 snprintf(buf, 99, "privatieelem%d", ctxt->counter++ + 1);
1003 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
1004 namespace, ret);
1005 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001006 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001007 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001008 ctxt->error(ctxt->userData, "Element %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +00001009 name);
1010 xmlFree((char *) ret->name);
1011 xmlFree(ret);
1012 return (NULL);
1013 }
1014 }
1015 return (ret);
1016}
1017
1018/**
1019 * xmlSchemaAddType:
1020 * @ctxt: a schema validation context
1021 * @schema: the schema being built
1022 * @name: the item name
1023 *
1024 * Add an XML schema Simple Type definition
1025 * *WARNING* this interface is highly subject to change
1026 *
1027 * Returns the new struture or NULL in case of error
1028 */
1029static xmlSchemaTypePtr
1030xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1031 const xmlChar * name)
1032{
1033 xmlSchemaTypePtr ret = NULL;
1034 int val;
1035
1036 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1037 return (NULL);
1038
1039 if (schema->typeDecl == NULL)
1040 schema->typeDecl = xmlHashCreate(10);
1041 if (schema->typeDecl == NULL)
1042 return (NULL);
1043
1044 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1045 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001046 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001047 if ((ctxt != NULL) && (ctxt->error != NULL))
1048 ctxt->error(ctxt->userData, "Out of memory\n");
1049 return (NULL);
1050 }
1051 memset(ret, 0, sizeof(xmlSchemaType));
1052 ret->name = xmlStrdup(name);
1053 val = xmlHashAddEntry2(schema->typeDecl, name, schema->targetNamespace,
1054 ret);
1055 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001056 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001057 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001058 ctxt->error(ctxt->userData, "Type %s already defined\n", name);
1059 xmlFree((char *) ret->name);
1060 xmlFree(ret);
1061 return (NULL);
1062 }
1063 ret->minOccurs = 1;
1064 ret->maxOccurs = 1;
1065
1066 return (ret);
1067}
1068
1069/**
1070 * xmlSchemaAddGroup:
1071 * @ctxt: a schema validation context
1072 * @schema: the schema being built
1073 * @name: the group name
1074 *
1075 * Add an XML schema Group definition
1076 *
1077 * Returns the new struture or NULL in case of error
1078 */
1079static xmlSchemaTypePtr
1080xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1081 const xmlChar * name)
1082{
1083 xmlSchemaTypePtr ret = NULL;
1084 int val;
1085
1086 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1087 return (NULL);
1088
1089 if (schema->groupDecl == NULL)
1090 schema->groupDecl = xmlHashCreate(10);
1091 if (schema->groupDecl == NULL)
1092 return (NULL);
1093
1094 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1095 if (ret == NULL) {
1096 ctxt->nberrors++;
1097 if ((ctxt != NULL) && (ctxt->error != NULL))
1098 ctxt->error(ctxt->userData, "Out of memory\n");
1099 return (NULL);
1100 }
1101 memset(ret, 0, sizeof(xmlSchemaType));
1102 ret->name = xmlStrdup(name);
1103 val = xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace,
1104 ret);
1105 if (val != 0) {
1106 ctxt->nberrors++;
1107 if ((ctxt != NULL) && (ctxt->error != NULL))
1108 ctxt->error(ctxt->userData, "Group %s already defined\n", name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001109 xmlFree((char *) ret->name);
1110 xmlFree(ret);
1111 return (NULL);
1112 }
1113 ret->minOccurs = 1;
1114 ret->maxOccurs = 1;
1115
1116 return (ret);
1117}
1118
1119/************************************************************************
1120 * *
1121 * Utilities for parsing *
1122 * *
1123 ************************************************************************/
1124
1125/**
1126 * xmlGetQNameProp:
1127 * @ctxt: a schema validation context
1128 * @node: a subtree containing XML Schema informations
1129 * @name: the attribute name
1130 * @namespace: the result namespace if any
1131 *
1132 * Extract a QName Attribute value
1133 *
1134 * Returns the NCName or NULL if not found, and also update @namespace
1135 * with the namespace URI
1136 */
1137static xmlChar *
1138xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1139 const char *name,
1140 xmlChar **namespace) {
1141 xmlChar *val, *ret, *prefix;
1142 xmlNsPtr ns;
1143
1144
1145 if (namespace != NULL)
1146 *namespace = NULL;
1147 val = xmlGetProp(node, (const xmlChar *) name);
1148 if (val == NULL)
1149 return(NULL);
1150
1151 ret = xmlSplitQName2(val, &prefix);
1152 if (ret == NULL)
1153 return(val);
1154 xmlFree(val);
1155
1156 ns = xmlSearchNs(node->doc, node, prefix);
1157 if (ns == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001158 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001159 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1160 if ((ctxt != NULL) && (ctxt->error != NULL))
1161 ctxt->error(ctxt->userData,
1162 "Attribute %s: the QName prefix %s is undefined\n",
1163 name, prefix);
1164 } else {
1165 *namespace = xmlStrdup(ns->href);
1166 }
1167 xmlFree(prefix);
1168 return(ret);
1169}
1170
1171/**
1172 * xmlGetMaxOccurs:
1173 * @ctxt: a schema validation context
1174 * @node: a subtree containing XML Schema informations
1175 *
1176 * Get the maxOccurs property
1177 *
1178 * Returns the default if not found, or the value
1179 */
1180static int
1181xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1182 xmlChar *val, *cur;
1183 int ret = 0;
1184
1185 val = xmlGetProp(node, (const xmlChar *) "maxOccurs");
1186 if (val == NULL)
1187 return(1);
1188
1189 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
1190 xmlFree(val);
1191 return(UNBOUNDED); /* encoding it with -1 might be another option */
1192 }
1193
1194 cur = val;
1195 while (IS_BLANK(*cur)) cur++;
1196 while ((*cur >= '0') && (*cur <= '9')) {
1197 ret = ret * 10 + (*cur - '0');
1198 cur++;
1199 }
1200 while (IS_BLANK(*cur)) cur++;
1201 if (*cur != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001202 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001203 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1204 if ((ctxt != NULL) && (ctxt->error != NULL))
1205 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1206 val);
1207 xmlFree(val);
1208 return(1);
1209 }
1210 xmlFree(val);
1211 return(ret);
1212}
1213
1214/**
1215 * xmlGetMinOccurs:
1216 * @ctxt: a schema validation context
1217 * @node: a subtree containing XML Schema informations
1218 *
1219 * Get the minOccurs property
1220 *
1221 * Returns the default if not found, or the value
1222 */
1223static int
1224xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1225 xmlChar *val, *cur;
1226 int ret = 0;
1227
1228 val = xmlGetProp(node, (const xmlChar *) "minOccurs");
1229 if (val == NULL)
1230 return(1);
1231
1232 cur = val;
1233 while (IS_BLANK(*cur)) cur++;
1234 while ((*cur >= '0') && (*cur <= '9')) {
1235 ret = ret * 10 + (*cur - '0');
1236 cur++;
1237 }
1238 while (IS_BLANK(*cur)) cur++;
1239 if (*cur != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001240 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001241 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1242 if ((ctxt != NULL) && (ctxt->error != NULL))
1243 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1244 val);
1245 xmlFree(val);
1246 return(1);
1247 }
1248 xmlFree(val);
1249 return(ret);
1250}
1251
1252/**
1253 * xmlGetBooleanProp:
1254 * @ctxt: a schema validation context
1255 * @node: a subtree containing XML Schema informations
1256 * @name: the attribute name
1257 * @def: the default value
1258 *
1259 * Get is a bolean property is set
1260 *
1261 * Returns the default if not found, 0 if found to be false,
1262 * 1 if found to be true
1263 */
1264static int
1265xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1266 const char *name, int def) {
1267 xmlChar *val;
1268
1269 val = xmlGetProp(node, (const xmlChar *) name);
1270 if (val == NULL)
1271 return(def);
1272
1273 if (xmlStrEqual(val, BAD_CAST"true"))
1274 def = 1;
1275 else if (xmlStrEqual(val, BAD_CAST"false"))
1276 def = 0;
1277 else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001278 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001279 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1280 if ((ctxt != NULL) && (ctxt->error != NULL))
1281 ctxt->error(ctxt->userData,
1282 "Attribute %s: the value %s is not boolean\n",
1283 name, val);
1284 }
1285 xmlFree(val);
1286 return(def);
1287}
1288
1289/************************************************************************
1290 * *
1291 * Shema extraction from an Infoset *
1292 * *
1293 ************************************************************************/
1294static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1295 ctxt, xmlSchemaPtr schema,
1296 xmlNodePtr node);
1297static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt,
1298 xmlSchemaPtr schema,
1299 xmlNodePtr node);
1300static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt,
1301 xmlSchemaPtr schema,
1302 xmlNodePtr node,
1303 int simple);
1304static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1305 xmlSchemaPtr schema,
1306 xmlNodePtr node);
1307static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1308 xmlSchemaPtr schema,
1309 xmlNodePtr node);
1310static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1311 ctxt,
1312 xmlSchemaPtr schema,
1313 xmlNodePtr node);
1314static xmlSchemaAttributeGroupPtr
1315xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1316 xmlSchemaPtr schema, xmlNodePtr node);
1317static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1318 xmlSchemaPtr schema,
1319 xmlNodePtr node);
1320static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1321 xmlSchemaPtr schema,
1322 xmlNodePtr node);
1323static xmlSchemaAttributePtr
1324xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1325 xmlNodePtr node);
1326
1327/**
1328 * xmlSchemaParseAttrDecls:
1329 * @ctxt: a schema validation context
1330 * @schema: the schema being built
1331 * @node: a subtree containing XML Schema informations
1332 * @type: the hosting type
1333 *
1334 * parse a XML schema attrDecls declaration corresponding to
1335 * <!ENTITY % attrDecls
1336 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1337 */
1338static xmlNodePtr
1339xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1340 xmlNodePtr child, xmlSchemaTypePtr type)
1341{
1342 xmlSchemaAttributePtr lastattr, attr;
1343
1344 lastattr = NULL;
1345 while ((IS_SCHEMA(child, "attribute")) ||
1346 (IS_SCHEMA(child, "attributeGroup"))) {
1347 attr = NULL;
1348 if (IS_SCHEMA(child, "attribute")) {
1349 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1350 } else if (IS_SCHEMA(child, "attributeGroup")) {
1351 attr = (xmlSchemaAttributePtr)
1352 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1353 }
1354 if (attr != NULL) {
1355 if (lastattr == NULL) {
1356 type->attributes = attr;
1357 lastattr = attr
1358 ;
1359 } else {
1360 lastattr->next = attr;
1361 lastattr = attr;
1362 }
1363 }
1364 child = child->next;
1365 }
1366 if (IS_SCHEMA(child, "anyAttribute")) {
1367 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1368 if (attr != NULL) {
1369 if (lastattr == NULL) {
1370 type->attributes = attr;
1371 lastattr = attr
1372 ;
1373 } else {
1374 lastattr->next = attr;
1375 lastattr = attr;
1376 }
1377 }
1378 child = child->next;
1379 }
1380 return(child);
1381}
1382
1383/**
1384 * xmlSchemaParseAnnotation:
1385 * @ctxt: a schema validation context
1386 * @schema: the schema being built
1387 * @node: a subtree containing XML Schema informations
1388 *
1389 * parse a XML schema Attrribute declaration
1390 * *WARNING* this interface is highly subject to change
1391 *
1392 * Returns -1 in case of error, 0 if the declaration is inproper and
1393 * 1 in case of success.
1394 */
1395static xmlSchemaAnnotPtr
1396xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1397 xmlNodePtr node)
1398{
1399 xmlSchemaAnnotPtr ret;
1400
1401 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1402 return (NULL);
1403 ret = xmlSchemaNewAnnot(ctxt, node);
1404
1405 return (ret);
1406}
1407
1408/**
1409 * xmlSchemaParseFacet:
1410 * @ctxt: a schema validation context
1411 * @schema: the schema being built
1412 * @node: a subtree containing XML Schema informations
1413 *
1414 * parse a XML schema Facet declaration
1415 * *WARNING* this interface is highly subject to change
1416 *
1417 * Returns the new type structure or NULL in case of error
1418 */
1419static xmlSchemaFacetPtr
1420xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1421 xmlNodePtr node)
1422{
1423 xmlSchemaFacetPtr facet;
1424 xmlNodePtr child = NULL;
1425 xmlChar *value;
1426
1427 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1428 return (NULL);
1429
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001430 facet = xmlSchemaNewFacet();
Daniel Veillard4255d502002-04-16 15:50:10 +00001431 if (facet == NULL)
1432 return (NULL);
1433 facet->node = node;
1434 value = xmlGetProp(node, (const xmlChar *) "value");
1435 if (value == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001436 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001437 xmlSchemaErrorContext(ctxt, schema, node, child);
1438 if ((ctxt != NULL) && (ctxt->error != NULL))
1439 ctxt->error(ctxt->userData, "Facet %s has no value\n", node->name);
1440 xmlSchemaFreeFacet(facet);
1441 return (NULL);
1442 }
1443 if (IS_SCHEMA(node, "minInclusive")) {
1444 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1445 } else if (IS_SCHEMA(node, "minExclusive")) {
1446 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1447 } else if (IS_SCHEMA(node, "maxInclusive")) {
1448 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1449 } else if (IS_SCHEMA(node, "maxExclusive")) {
1450 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1451 } else if (IS_SCHEMA(node, "totalDigits")) {
1452 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1453 } else if (IS_SCHEMA(node, "fractionDigits")) {
1454 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1455 } else if (IS_SCHEMA(node, "pattern")) {
1456 facet->type = XML_SCHEMA_FACET_PATTERN;
1457 } else if (IS_SCHEMA(node, "enumeration")) {
1458 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1459 } else if (IS_SCHEMA(node, "whiteSpace")) {
1460 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1461 } else if (IS_SCHEMA(node, "length")) {
1462 facet->type = XML_SCHEMA_FACET_LENGTH;
1463 } else if (IS_SCHEMA(node, "maxLength")) {
1464 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1465 } else if (IS_SCHEMA(node, "minLength")) {
1466 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1467 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001468 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001469 xmlSchemaErrorContext(ctxt, schema, node, child);
1470 if ((ctxt != NULL) && (ctxt->error != NULL))
1471 ctxt->error(ctxt->userData, "Unknown facet type %s\n", node->name);
1472 xmlSchemaFreeFacet(facet);
1473 return(NULL);
1474 }
1475 facet->id = xmlGetProp(node, (const xmlChar *) "id");
1476 facet->value = value;
1477 child = node->children;
1478
1479 if (IS_SCHEMA(child, "annotation")) {
1480 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1481 child = child->next;
1482 }
1483 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001484 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001485 xmlSchemaErrorContext(ctxt, schema, node, child);
1486 if ((ctxt != NULL) && (ctxt->error != NULL))
1487 ctxt->error(ctxt->userData,
1488 "Facet %s has unexpected child content\n",
1489 node->name);
1490 }
1491 return (facet);
1492}
1493
1494/**
1495 * xmlSchemaParseAny:
1496 * @ctxt: a schema validation context
1497 * @schema: the schema being built
1498 * @node: a subtree containing XML Schema informations
1499 *
1500 * parse a XML schema Any declaration
1501 * *WARNING* this interface is highly subject to change
1502 *
1503 * Returns the new type structure or NULL in case of error
1504 */
1505static xmlSchemaTypePtr
1506xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1507 xmlNodePtr node)
1508{
1509 xmlSchemaTypePtr type;
1510 xmlNodePtr child = NULL;
1511 xmlChar name[30];
1512
1513 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1514 return (NULL);
1515 snprintf((char *)name, 30, "any %d", ctxt->counter++ + 1);
1516 type = xmlSchemaAddType(ctxt, schema, name);
1517 if (type == NULL)
1518 return (NULL);
1519 type->node = node;
1520 type->type = XML_SCHEMA_TYPE_ANY;
1521 child = node->children;
1522 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1523 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1524
1525 if (IS_SCHEMA(child, "annotation")) {
1526 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1527 child = child->next;
1528 }
1529 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001530 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001531 xmlSchemaErrorContext(ctxt, schema, node, child);
1532 if ((ctxt != NULL) && (ctxt->error != NULL))
1533 ctxt->error(ctxt->userData,
1534 "Sequence %s has unexpected content\n",
1535 type->name);
1536 }
1537
1538 return (type);
1539}
1540
1541/**
1542 * xmlSchemaParseNotation:
1543 * @ctxt: a schema validation context
1544 * @schema: the schema being built
1545 * @node: a subtree containing XML Schema informations
1546 *
1547 * parse a XML schema Notation declaration
1548 *
1549 * Returns the new structure or NULL in case of error
1550 */
1551static xmlSchemaNotationPtr
1552xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1553 xmlNodePtr node)
1554{
1555 xmlChar *name;
1556 xmlSchemaNotationPtr ret;
1557 xmlNodePtr child = NULL;
1558
1559 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1560 return (NULL);
1561 name = xmlGetProp(node, (const xmlChar *) "name");
1562 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001563 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001564 xmlSchemaErrorContext(ctxt, schema, node, child);
1565 if ((ctxt != NULL) && (ctxt->error != NULL))
1566 ctxt->error(ctxt->userData, "Notation has no name\n");
1567 return (NULL);
1568 }
1569 ret = xmlSchemaAddNotation(ctxt, schema, name);
1570 if (ret == NULL) {
1571 xmlFree(name);
1572 return (NULL);
1573 }
1574 child = node->children;
1575 if (IS_SCHEMA(child, "annotation")) {
1576 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1577 child = child->next;
1578 }
1579 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001580 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001581 xmlSchemaErrorContext(ctxt, schema, node, child);
1582 if ((ctxt != NULL) && (ctxt->error != NULL))
1583 ctxt->error(ctxt->userData,
1584 "notation %s has unexpected content\n",
1585 name);
1586 }
1587
1588 return (ret);
1589}
1590
1591/**
1592 * xmlSchemaParseAnyAttribute:
1593 * @ctxt: a schema validation context
1594 * @schema: the schema being built
1595 * @node: a subtree containing XML Schema informations
1596 *
1597 * parse a XML schema AnyAttrribute declaration
1598 * *WARNING* this interface is highly subject to change
1599 *
1600 * Returns an attribute def structure or NULL
1601 */
1602static xmlSchemaAttributePtr
1603xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1604 xmlNodePtr node)
1605{
1606 xmlChar *processContents;
1607 xmlSchemaAttributePtr ret;
1608 xmlNodePtr child = NULL;
1609 char name[100];
1610
1611 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1612 return (NULL);
1613
1614 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
1615 ret = xmlSchemaAddAttribute(ctxt, schema, (xmlChar *)name);
1616 if (ret == NULL) {
1617 return (NULL);
1618 }
1619 ret->id = xmlGetProp(node, (const xmlChar *) "id");
1620 processContents = xmlGetProp(node, (const xmlChar *) "processContents");
1621 if ((processContents == NULL) ||
1622 (xmlStrEqual(processContents, (const xmlChar *)"strict"))) {
1623 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1624 } else if (xmlStrEqual(processContents, (const xmlChar *)"skip")) {
1625 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1626 } else if (xmlStrEqual(processContents, (const xmlChar *)"lax")) {
1627 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
1628 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001629 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001630 xmlSchemaErrorContext(ctxt, schema, node, child);
1631 if ((ctxt != NULL) && (ctxt->error != NULL))
1632 ctxt->error(ctxt->userData,
1633 "anyAttribute has unexpected content for processContents: %s\n",
1634 processContents);
1635 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1636 }
1637 if (processContents != NULL)
1638 xmlFree(processContents);
1639
1640 child = node->children;
1641 if (IS_SCHEMA(child, "annotation")) {
1642 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1643 child = child->next;
1644 }
1645 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001646 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001647 xmlSchemaErrorContext(ctxt, schema, node, child);
1648 if ((ctxt != NULL) && (ctxt->error != NULL))
1649 ctxt->error(ctxt->userData,
1650 "anyAttribute %s has unexpected content\n",
1651 name);
1652 }
1653
1654 return (ret);
1655}
1656
1657
1658/**
1659 * xmlSchemaParseAttribute:
1660 * @ctxt: a schema validation context
1661 * @schema: the schema being built
1662 * @node: a subtree containing XML Schema informations
1663 *
1664 * parse a XML schema Attrribute declaration
1665 * *WARNING* this interface is highly subject to change
1666 *
1667 * Returns -1 in case of error, 0 if the declaration is inproper and
1668 * 1 in case of success.
1669 */
1670static xmlSchemaAttributePtr
1671xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1672 xmlNodePtr node)
1673{
1674 xmlChar *name, *refNs = NULL, *ref = NULL;
1675 xmlSchemaAttributePtr ret;
1676 xmlNodePtr child = NULL;
1677
1678 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1679 return (NULL);
1680 name = xmlGetProp(node, (const xmlChar *) "name");
1681 if (name == NULL) {
1682 char buf[100];
1683
1684 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1685 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001686 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001687 xmlSchemaErrorContext(ctxt, schema, node, child);
1688 if ((ctxt != NULL) && (ctxt->error != NULL))
1689 ctxt->error(ctxt->userData, "Attribute has no name nor ref\n");
1690 return (NULL);
1691 }
1692 snprintf(buf, 99, "anonattr%d", ctxt->counter++ + 1);
1693 name = xmlStrdup((xmlChar *) buf);
1694 }
1695 ret = xmlSchemaAddAttribute(ctxt, schema, name);
1696 if (ret == NULL) {
1697 xmlFree(name);
1698 if (ref != NULL)
1699 xmlFree(ref);
1700 return (NULL);
1701 }
1702 xmlFree(name);
1703 ret->ref = ref;
1704 ret->refNs = refNs;
1705 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001706 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001707 child = node->children;
1708 if (IS_SCHEMA(child, "annotation")) {
1709 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1710 child = child->next;
1711 }
1712 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillard88c58912002-04-23 07:12:20 +00001713 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001714 child = child->next;
1715 }
1716 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001717 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001718 xmlSchemaErrorContext(ctxt, schema, node, child);
1719 if ((ctxt != NULL) && (ctxt->error != NULL))
1720 ctxt->error(ctxt->userData,
1721 "attribute %s has unexpected content\n",
1722 name);
1723 }
1724
1725 return (ret);
1726}
1727
1728/**
1729 * xmlSchemaParseAttributeGroup:
1730 * @ctxt: a schema validation context
1731 * @schema: the schema being built
1732 * @node: a subtree containing XML Schema informations
1733 *
1734 * parse a XML schema Attribute Group declaration
1735 * *WARNING* this interface is highly subject to change
1736 *
1737 * Returns the attribute group or NULL in case of error.
1738 */
1739static xmlSchemaAttributeGroupPtr
1740xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1741 xmlNodePtr node)
1742{
1743 xmlChar *name, *refNs = NULL, *ref = NULL;
1744 xmlSchemaAttributeGroupPtr ret;
1745 xmlSchemaAttributePtr last = NULL, attr;
1746 xmlNodePtr child = NULL;
1747 xmlChar *oldcontainer;
1748
1749 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1750 return (NULL);
1751 oldcontainer = ctxt->container;
1752 name = xmlGetProp(node, (const xmlChar *) "name");
1753 if (name == NULL) {
1754 char buf[100];
1755
1756 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1757 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001758 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001759 xmlSchemaErrorContext(ctxt, schema, node, child);
1760 if ((ctxt != NULL) && (ctxt->error != NULL))
1761 ctxt->error(ctxt->userData,
1762 "AttributeGroup has no name nor ref\n");
1763 return (NULL);
1764 }
1765 snprintf(buf, 99, "anonattrgroup%d", ctxt->counter++ + 1);
1766 name = xmlStrdup((xmlChar *) buf);
Daniel Veillard91a13252003-03-27 23:44:43 +00001767 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001768 ctxt->nberrors++;
Daniel Veillard91a13252003-03-27 23:44:43 +00001769 if ((ctxt != NULL) && (ctxt->error != NULL))
1770 ctxt->error(ctxt->userData,
1771 "out of memory\n");
1772 return (NULL);
1773 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001774 }
1775 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
1776 if (ret == NULL) {
1777 xmlFree(name);
1778 if (ref != NULL)
1779 xmlFree(ref);
1780 return (NULL);
1781 }
1782 ret->ref = ref;
1783 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00001784 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001785 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001786 child = node->children;
1787 ctxt->container = name;
1788 if (IS_SCHEMA(child, "annotation")) {
1789 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1790 child = child->next;
1791 }
1792 while ((IS_SCHEMA(child, "attribute")) ||
1793 (IS_SCHEMA(child, "attributeGroup"))) {
1794 attr = NULL;
1795 if (IS_SCHEMA(child, "attribute")) {
1796 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1797 } else if (IS_SCHEMA(child, "attributeGroup")) {
1798 attr = (xmlSchemaAttributePtr)
1799 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1800 }
1801 if (attr != NULL) {
1802 if (last == NULL) {
1803 ret->attributes = attr;
1804 last = attr;
1805 } else {
1806 last->next = attr;
1807 last = attr;
1808 }
1809 }
1810 child = child->next;
1811 }
1812 if (IS_SCHEMA(child, "anyAttribute")) {
1813 TODO
1814 child = child->next;
1815 }
1816 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001817 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001818 xmlSchemaErrorContext(ctxt, schema, node, child);
1819 if ((ctxt != NULL) && (ctxt->error != NULL))
1820 ctxt->error(ctxt->userData,
1821 "attribute group %s has unexpected content\n",
1822 name);
1823 }
1824
1825 ctxt->container = oldcontainer;
Daniel Veillard91a13252003-03-27 23:44:43 +00001826 xmlFree(name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001827 return (ret);
1828}
1829
1830/**
1831 * xmlSchemaParseElement:
1832 * @ctxt: a schema validation context
1833 * @schema: the schema being built
1834 * @node: a subtree containing XML Schema informations
1835 *
1836 * parse a XML schema Element declaration
1837 * *WARNING* this interface is highly subject to change
1838 *
1839 * Returns -1 in case of error, 0 if the declaration is inproper and
1840 * 1 in case of success.
1841 */
1842static xmlSchemaElementPtr
1843xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1844 xmlNodePtr node, int toplevel)
1845{
1846 xmlChar *name, *refNs = NULL, *ref = NULL, *namespace, *fixed;
1847 xmlSchemaElementPtr ret;
1848 xmlNodePtr child = NULL;
1849 xmlChar *oldcontainer;
1850
1851 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1852 return (NULL);
1853 oldcontainer = ctxt->container;
1854 name = xmlGetProp(node, (const xmlChar *) "name");
1855 if (name == NULL) {
1856 char buf[100];
1857
1858 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1859 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001860 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001861 xmlSchemaErrorContext(ctxt, schema, node, child);
1862 if ((ctxt != NULL) && (ctxt->error != NULL))
1863 ctxt->error(ctxt->userData, "Element has no name nor ref\n");
1864 return (NULL);
1865 }
1866 snprintf(buf, 99, "anonelem%d", ctxt->counter++ + 1);
1867 name = xmlStrdup((xmlChar *) buf);
1868 }
1869 namespace = xmlGetProp(node, (const xmlChar *) "targetNamespace");
1870 if (namespace == NULL)
1871 ret =
1872 xmlSchemaAddElement(ctxt, schema, name,
1873 schema->targetNamespace);
1874 else
1875 ret = xmlSchemaAddElement(ctxt, schema, name, namespace);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001876 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001877 if (namespace != NULL)
1878 xmlFree(namespace);
1879 if (ret == NULL) {
1880 xmlFree(name);
1881 if (ref != NULL)
1882 xmlFree(ref);
1883 return (NULL);
1884 }
1885 ret->type = XML_SCHEMA_TYPE_ELEMENT;
1886 ret->ref = ref;
1887 ret->refNs = refNs;
1888 if (ref != NULL)
1889 ret->flags |= XML_SCHEMAS_ELEM_REF;
1890 if (toplevel)
1891 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
1892 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
1893 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1894 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
1895 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1896 ctxt->container = name;
1897
1898 ret->id = xmlGetProp(node, BAD_CAST "id");
1899 ret->namedType = xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
1900 ret->substGroup = xmlGetQNameProp(ctxt, node, "substitutionGroup",
1901 &(ret->substGroupNs));
1902 fixed = xmlGetProp(node, BAD_CAST "fixed");
1903 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
1904 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1905
1906 ret->value = xmlGetProp(node, BAD_CAST "default");
1907 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001908 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001909 xmlSchemaErrorContext(ctxt, schema, node, child);
1910 ctxt->error(ctxt->userData,
1911 "Element %s has both default and fixed\n",
1912 ret->name);
1913 xmlFree(fixed);
1914 } else if (fixed != NULL) {
1915 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
1916 ret->value = fixed;
1917 }
1918
1919 child = node->children;
1920 if (IS_SCHEMA(child, "annotation")) {
1921 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1922 child = child->next;
1923 }
1924 if (IS_SCHEMA(child, "complexType")) {
1925 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
1926 child = child->next;
1927 } else if (IS_SCHEMA(child, "simpleType")) {
1928 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
1929 child = child->next;
1930 }
1931 while ((IS_SCHEMA(child, "unique")) ||
1932 (IS_SCHEMA(child, "key")) ||
1933 (IS_SCHEMA(child, "keyref"))) {
1934 TODO
1935 child = child->next;
1936 }
1937 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001938 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001939 xmlSchemaErrorContext(ctxt, schema, node, child);
1940 if ((ctxt != NULL) && (ctxt->error != NULL))
1941 ctxt->error(ctxt->userData,
1942 "element %s has unexpected content\n",
1943 name);
1944 }
1945
1946 ctxt->container = oldcontainer;
1947 xmlFree(name);
1948 return (ret);
1949}
1950
1951/**
1952 * xmlSchemaParseUnion:
1953 * @ctxt: a schema validation context
1954 * @schema: the schema being built
1955 * @node: a subtree containing XML Schema informations
1956 *
1957 * parse a XML schema Union definition
1958 * *WARNING* this interface is highly subject to change
1959 *
1960 * Returns -1 in case of error, 0 if the declaration is inproper and
1961 * 1 in case of success.
1962 */
1963static xmlSchemaTypePtr
1964xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1965 xmlNodePtr node)
1966{
1967 xmlSchemaTypePtr type, subtype, last = NULL;
1968 xmlNodePtr child = NULL;
1969 xmlChar name[30];
1970
1971 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1972 return (NULL);
1973
1974
1975 snprintf((char *)name, 30, "union %d", ctxt->counter++ + 1);
1976 type = xmlSchemaAddType(ctxt, schema, name);
1977 if (type == NULL)
1978 return (NULL);
1979 type->node = node;
1980 type->type = XML_SCHEMA_TYPE_LIST;
1981 type->id = xmlGetProp(node, BAD_CAST "id");
1982 type->ref = xmlGetProp(node, BAD_CAST "memberTypes");
1983
1984 child = node->children;
1985 if (IS_SCHEMA(child, "annotation")) {
1986 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1987 child = child->next;
1988 }
1989 while (IS_SCHEMA(child, "simpleType")) {
1990 subtype = (xmlSchemaTypePtr)
1991 xmlSchemaParseSimpleType(ctxt, schema, child);
1992 if (subtype != NULL) {
1993 if (last == NULL) {
1994 type->subtypes = subtype;
1995 last = subtype;
1996 } else {
1997 last->next = subtype;
1998 last = subtype;
1999 }
2000 last->next = NULL;
2001 }
2002 child = child->next;
2003 }
2004 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002005 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002006 xmlSchemaErrorContext(ctxt, schema, node, child);
2007 if ((ctxt != NULL) && (ctxt->error != NULL))
2008 ctxt->error(ctxt->userData,
2009 "Union %s has unexpected content\n",
2010 type->name);
2011 }
2012 return (type);
2013}
2014
2015/**
2016 * xmlSchemaParseList:
2017 * @ctxt: a schema validation context
2018 * @schema: the schema being built
2019 * @node: a subtree containing XML Schema informations
2020 *
2021 * parse a XML schema List definition
2022 * *WARNING* this interface is highly subject to change
2023 *
2024 * Returns -1 in case of error, 0 if the declaration is inproper and
2025 * 1 in case of success.
2026 */
2027static xmlSchemaTypePtr
2028xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2029 xmlNodePtr node)
2030{
2031 xmlSchemaTypePtr type, subtype;
2032 xmlNodePtr child = NULL;
2033 xmlChar name[30];
2034
2035 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2036 return (NULL);
2037
2038 snprintf((char *)name, 30, "list %d", ctxt->counter++ + 1);
2039 type = xmlSchemaAddType(ctxt, schema, name);
2040 if (type == NULL)
2041 return (NULL);
2042 type->node = node;
2043 type->type = XML_SCHEMA_TYPE_LIST;
2044 type->id = xmlGetProp(node, BAD_CAST "id");
2045 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
2046
2047 child = node->children;
2048 if (IS_SCHEMA(child, "annotation")) {
2049 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2050 child = child->next;
2051 }
2052 subtype = NULL;
2053 if (IS_SCHEMA(child, "simpleType")) {
2054 subtype = (xmlSchemaTypePtr)
2055 xmlSchemaParseSimpleType(ctxt, schema, child);
2056 child = child->next;
2057 type->subtypes = subtype;
2058 }
2059 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002060 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002061 xmlSchemaErrorContext(ctxt, schema, node, child);
2062 if ((ctxt != NULL) && (ctxt->error != NULL))
2063 ctxt->error(ctxt->userData,
2064 "List %s has unexpected content\n",
2065 type->name);
2066 }
2067 return (type);
2068}
2069/**
2070 * xmlSchemaParseSimpleType:
2071 * @ctxt: a schema validation context
2072 * @schema: the schema being built
2073 * @node: a subtree containing XML Schema informations
2074 *
2075 * parse a XML schema Simple Type definition
2076 * *WARNING* this interface is highly subject to change
2077 *
2078 * Returns -1 in case of error, 0 if the declaration is inproper and
2079 * 1 in case of success.
2080 */
2081static xmlSchemaTypePtr
2082xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2083 xmlNodePtr node)
2084{
2085 xmlSchemaTypePtr type, subtype;
2086 xmlNodePtr child = NULL;
2087 xmlChar *name;
2088
2089 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2090 return (NULL);
2091
2092
2093 name = xmlGetProp(node, (const xmlChar *) "name");
2094 if (name == NULL) {
2095 char buf[100];
2096
2097 snprintf(buf, 99, "simpletype%d", ctxt->counter++ + 1);
2098 name = xmlStrdup((xmlChar *) buf);
2099 }
2100 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002101 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002102 xmlSchemaErrorContext(ctxt, schema, node, child);
2103 if ((ctxt != NULL) && (ctxt->error != NULL))
2104 ctxt->error(ctxt->userData, "simpleType has no name\n");
2105 return (NULL);
2106 }
2107 type = xmlSchemaAddType(ctxt, schema, name);
2108 xmlFree(name);
2109 if (type == NULL)
2110 return (NULL);
2111 type->node = node;
2112 type->type = XML_SCHEMA_TYPE_SIMPLE;
2113 type->id = xmlGetProp(node, BAD_CAST "id");
2114
2115 child = node->children;
2116 if (IS_SCHEMA(child, "annotation")) {
2117 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2118 child = child->next;
2119 }
2120 subtype = NULL;
2121 if (IS_SCHEMA(child, "restriction")) {
2122 subtype = (xmlSchemaTypePtr)
2123 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2124 child = child->next;
2125 } else if (IS_SCHEMA(child, "list")) {
2126 subtype = (xmlSchemaTypePtr)
2127 xmlSchemaParseList(ctxt, schema, child);
2128 child = child->next;
2129 } else if (IS_SCHEMA(child, "union")) {
2130 subtype = (xmlSchemaTypePtr)
2131 xmlSchemaParseUnion(ctxt, schema, child);
2132 child = child->next;
2133 }
2134 type->subtypes = subtype;
2135 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002136 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002137 xmlSchemaErrorContext(ctxt, schema, node, child);
2138 if ((ctxt != NULL) && (ctxt->error != NULL))
2139 ctxt->error(ctxt->userData,
2140 "SimpleType %s has unexpected content\n",
2141 type->name);
2142 }
2143
2144 return (type);
2145}
2146
2147
2148/**
2149 * xmlSchemaParseGroup:
2150 * @ctxt: a schema validation context
2151 * @schema: the schema being built
2152 * @node: a subtree containing XML Schema informations
2153 *
2154 * parse a XML schema Group definition
2155 * *WARNING* this interface is highly subject to change
2156 *
2157 * Returns -1 in case of error, 0 if the declaration is inproper and
2158 * 1 in case of success.
2159 */
2160static xmlSchemaTypePtr
2161xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2162 xmlNodePtr node)
2163{
2164 xmlSchemaTypePtr type, subtype;
2165 xmlNodePtr child = NULL;
2166 xmlChar *name, *ref = NULL, *refNs = NULL;
2167
2168 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2169 return (NULL);
2170
2171
2172 name = xmlGetProp(node, (const xmlChar *) "name");
2173 if (name == NULL) {
2174 char buf[100];
2175
2176 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2177 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002178 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002179 xmlSchemaErrorContext(ctxt, schema, node, child);
2180 if ((ctxt != NULL) && (ctxt->error != NULL))
2181 ctxt->error(ctxt->userData, "Group has no name nor ref\n");
2182 return (NULL);
2183 }
2184 snprintf(buf, 99, "anongroup%d", ctxt->counter++ + 1);
2185 name = xmlStrdup((xmlChar *) buf);
2186 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002187 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002188 if (type == NULL)
2189 return (NULL);
2190 type->node = node;
2191 type->type = XML_SCHEMA_TYPE_GROUP;
2192 type->id = xmlGetProp(node, BAD_CAST "id");
2193 type->ref = ref;
2194 type->refNs = refNs;
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 subtype = NULL;
2204 if (IS_SCHEMA(child, "all")) {
2205 subtype = (xmlSchemaTypePtr)
2206 xmlSchemaParseAll(ctxt, schema, child);
2207 child = child->next;
2208 } else if (IS_SCHEMA(child, "choice")) {
2209 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2210 child = child->next;
2211 } else if (IS_SCHEMA(child, "sequence")) {
2212 subtype = (xmlSchemaTypePtr)
2213 xmlSchemaParseSequence(ctxt, schema, child);
2214 child = child->next;
2215 }
2216 if (subtype != NULL)
2217 type->subtypes = subtype;
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 "Group %s has unexpected content\n",
2224 type->name);
2225 }
2226
2227 return (type);
2228}
2229
2230/**
2231 * xmlSchemaParseAll:
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 All 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 xmlSchemaTypePtr
2243xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2244 xmlNodePtr node)
2245{
2246 xmlSchemaTypePtr type, subtype, last = NULL;
2247 xmlNodePtr child = NULL;
2248 xmlChar name[30];
2249
2250 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2251 return (NULL);
2252
2253
2254 snprintf((char *)name, 30, "all%d", ctxt->counter++ + 1);
2255 type = xmlSchemaAddType(ctxt, schema, name);
2256 if (type == NULL)
2257 return (NULL);
2258 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002259 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002260 type->id = xmlGetProp(node, BAD_CAST "id");
2261 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2262 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2263
2264 child = node->children;
2265 if (IS_SCHEMA(child, "annotation")) {
2266 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2267 child = child->next;
2268 }
2269 while (IS_SCHEMA(child, "element")) {
2270 subtype = (xmlSchemaTypePtr)
2271 xmlSchemaParseElement(ctxt, schema, child, 0);
2272 if (subtype != NULL) {
2273 if (last == NULL) {
2274 type->subtypes = subtype;
2275 last = subtype;
2276 } else {
2277 last->next = subtype;
2278 last = subtype;
2279 }
2280 last->next = NULL;
2281 }
2282 child = child->next;
2283 }
2284 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002285 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002286 xmlSchemaErrorContext(ctxt, schema, node, child);
2287 if ((ctxt != NULL) && (ctxt->error != NULL))
2288 ctxt->error(ctxt->userData,
2289 "All %s has unexpected content\n",
2290 type->name);
2291 }
2292
2293 return (type);
2294}
2295
2296/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002297 * xmlSchemaParseImport:
2298 * @ctxt: a schema validation context
2299 * @schema: the schema being built
2300 * @node: a subtree containing XML Schema informations
2301 *
2302 * parse a XML schema Import definition
2303 * *WARNING* this interface is highly subject to change
2304 *
2305 * Returns -1 in case of error, 0 if the declaration is inproper and
2306 * 1 in case of success.
2307 */
2308static int
2309xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2310 xmlNodePtr node)
2311{
2312 xmlNodePtr child = NULL;
2313 xmlChar *namespace;
2314 xmlChar *schemaLocation;
2315 xmlChar *previous;
2316 xmlURIPtr check;
2317
2318 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2319 return (-1);
2320
2321 namespace = xmlGetProp(node, BAD_CAST "namespace");
2322 if (namespace != NULL) {
2323 check = xmlParseURI((const char *) namespace);
2324 if (check == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002325 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002326 xmlSchemaErrorContext(ctxt, schema, node, child);
2327 if ((ctxt != NULL) && (ctxt->error != NULL))
2328 ctxt->error(ctxt->userData,
2329 "Import namespace attribute is not an URI: %s\n",
2330 namespace);
2331 xmlFree(namespace);
2332 return(-1);
2333 } else {
2334 xmlFreeURI(check);
2335 }
2336 }
2337 schemaLocation = xmlGetProp(node, BAD_CAST "schemaLocation");
2338 if (schemaLocation != NULL) {
2339 check = xmlParseURI((const char *) schemaLocation);
2340 if (check == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002341 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002342 xmlSchemaErrorContext(ctxt, schema, node, child);
2343 if ((ctxt != NULL) && (ctxt->error != NULL))
2344 ctxt->error(ctxt->userData,
2345 "Import schemaLocation attribute is not an URI: %s\n",
2346 schemaLocation);
2347 if (namespace != NULL)
2348 xmlFree(namespace);
2349 xmlFree(schemaLocation);
2350 return(-1);
2351 } else {
2352 xmlFreeURI(check);
2353 }
2354 }
2355 if (schema->schemasImports == NULL) {
2356 schema->schemasImports = xmlHashCreate(10);
2357 if (schema->schemasImports == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002358 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002359 xmlSchemaErrorContext(ctxt, schema, node, child);
2360 if ((ctxt != NULL) && (ctxt->error != NULL))
2361 ctxt->error(ctxt->userData,
2362 "Internal: failed to build import table\n");
2363 if (namespace != NULL)
2364 xmlFree(namespace);
2365 if (schemaLocation != NULL)
2366 xmlFree(schemaLocation);
2367 return(-1);
2368 }
2369 }
2370 if (namespace == NULL) {
2371 previous = xmlHashLookup(schema->schemasImports,
2372 XML_SCHEMAS_DEFAULT_NAMESPACE);
2373 if (schemaLocation != NULL) {
2374 if (previous != NULL) {
2375 if (!xmlStrEqual(schemaLocation, previous)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002376 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002377 xmlSchemaErrorContext(ctxt, schema, node, child);
2378 if ((ctxt != NULL) && (ctxt->error != NULL))
2379 ctxt->error(ctxt->userData,
2380 "Redefining import for default namespace with a different URI: %s\n",
2381 schemaLocation);
2382 }
2383 } else {
2384 xmlHashAddEntry(schema->schemasImports,
2385 XML_SCHEMAS_DEFAULT_NAMESPACE, schemaLocation);
2386 }
2387 }
2388 } else {
2389 previous = xmlHashLookup(schema->schemasImports, namespace);
2390 if (schemaLocation != NULL) {
2391 if (previous != NULL) {
2392 if (!xmlStrEqual(schemaLocation, previous)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002393 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002394 xmlSchemaErrorContext(ctxt, schema, node, child);
2395 if ((ctxt != NULL) && (ctxt->error != NULL))
2396 ctxt->error(ctxt->userData,
2397 "Redefining import for namespace %s with a different URI: %s\n",
2398 namespace, schemaLocation);
2399 }
2400 } else {
2401 xmlHashAddEntry(schema->schemasImports,
2402 namespace, schemaLocation);
2403 }
2404 }
2405 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002406
2407 child = node->children;
2408 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillard7c13af42002-05-22 09:57:32 +00002409 /*
2410 * the annotations here are simply discarded ...
2411 */
Daniel Veillard5a872412002-05-22 06:40:27 +00002412 child = child->next;
2413 }
2414 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002415 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002416 xmlSchemaErrorContext(ctxt, schema, node, child);
2417 if ((ctxt != NULL) && (ctxt->error != NULL))
2418 ctxt->error(ctxt->userData,
2419 "Import has unexpected content\n");
2420 return(-1);
2421 }
2422 return(1);
2423}
2424
2425/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002426 * xmlSchemaParseChoice:
2427 * @ctxt: a schema validation context
2428 * @schema: the schema being built
2429 * @node: a subtree containing XML Schema informations
2430 *
2431 * parse a XML schema Choice definition
2432 * *WARNING* this interface is highly subject to change
2433 *
2434 * Returns -1 in case of error, 0 if the declaration is inproper and
2435 * 1 in case of success.
2436 */
2437static xmlSchemaTypePtr
2438xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2439 xmlNodePtr node)
2440{
2441 xmlSchemaTypePtr type, subtype, last = NULL;
2442 xmlNodePtr child = NULL;
2443 xmlChar name[30];
2444
2445 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2446 return (NULL);
2447
2448
2449 snprintf((char *)name, 30, "choice %d", ctxt->counter++ + 1);
2450 type = xmlSchemaAddType(ctxt, schema, name);
2451 if (type == NULL)
2452 return (NULL);
2453 type->node = node;
2454 type->type = XML_SCHEMA_TYPE_CHOICE;
2455 type->id = xmlGetProp(node, BAD_CAST "id");
2456 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2457 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2458
2459 child = node->children;
2460 if (IS_SCHEMA(child, "annotation")) {
2461 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2462 child = child->next;
2463 }
2464 while ((IS_SCHEMA(child, "element")) ||
2465 (IS_SCHEMA(child, "group")) ||
2466 (IS_SCHEMA(child, "any")) ||
2467 (IS_SCHEMA(child, "choice")) ||
2468 (IS_SCHEMA(child, "sequence"))) {
2469 subtype = NULL;
2470 if (IS_SCHEMA(child, "element")) {
2471 subtype = (xmlSchemaTypePtr)
2472 xmlSchemaParseElement(ctxt, schema, child, 0);
2473 } else if (IS_SCHEMA(child, "group")) {
2474 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2475 } else if (IS_SCHEMA(child, "any")) {
2476 subtype = xmlSchemaParseAny(ctxt, schema, child);
2477 } else if (IS_SCHEMA(child, "sequence")) {
2478 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2479 } else if (IS_SCHEMA(child, "choice")) {
2480 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2481 }
2482 if (subtype != NULL) {
2483 if (last == NULL) {
2484 type->subtypes = subtype;
2485 last = subtype;
2486 } else {
2487 last->next = subtype;
2488 last = subtype;
2489 }
2490 last->next = NULL;
2491 }
2492 child = child->next;
2493 }
2494 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002495 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002496 xmlSchemaErrorContext(ctxt, schema, node, child);
2497 if ((ctxt != NULL) && (ctxt->error != NULL))
2498 ctxt->error(ctxt->userData,
2499 "Choice %s has unexpected content\n",
2500 type->name);
2501 }
2502
2503 return (type);
2504}
2505
2506/**
2507 * xmlSchemaParseSequence:
2508 * @ctxt: a schema validation context
2509 * @schema: the schema being built
2510 * @node: a subtree containing XML Schema informations
2511 *
2512 * parse a XML schema Sequence definition
2513 * *WARNING* this interface is highly subject to change
2514 *
2515 * Returns -1 in case of error, 0 if the declaration is inproper and
2516 * 1 in case of success.
2517 */
2518static xmlSchemaTypePtr
2519xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2520 xmlNodePtr node)
2521{
2522 xmlSchemaTypePtr type, subtype, last = NULL;
2523 xmlNodePtr child = NULL;
2524 xmlChar name[30];
2525
2526 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2527 return (NULL);
2528
2529
2530 snprintf((char *)name, 30, "sequence %d", ctxt->counter++ + 1);
2531 type = xmlSchemaAddType(ctxt, schema, name);
2532 if (type == NULL)
2533 return (NULL);
2534 type->node = node;
2535 type->type = XML_SCHEMA_TYPE_SEQUENCE;
2536 type->id = xmlGetProp(node, BAD_CAST "id");
2537 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2538 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2539
2540 child = node->children;
2541 if (IS_SCHEMA(child, "annotation")) {
2542 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2543 child = child->next;
2544 }
2545 while ((IS_SCHEMA(child, "element")) ||
2546 (IS_SCHEMA(child, "group")) ||
2547 (IS_SCHEMA(child, "any")) ||
2548 (IS_SCHEMA(child, "choice")) ||
2549 (IS_SCHEMA(child, "sequence"))) {
2550 subtype = NULL;
2551 if (IS_SCHEMA(child, "element")) {
2552 subtype = (xmlSchemaTypePtr)
2553 xmlSchemaParseElement(ctxt, schema, child, 0);
2554 } else if (IS_SCHEMA(child, "group")) {
2555 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2556 } else if (IS_SCHEMA(child, "any")) {
2557 subtype = xmlSchemaParseAny(ctxt, schema, child);
2558 } else if (IS_SCHEMA(child, "choice")) {
2559 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2560 } else if (IS_SCHEMA(child, "sequence")) {
2561 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2562 }
2563 if (subtype != NULL) {
2564 if (last == NULL) {
2565 type->subtypes = subtype;
2566 last = subtype;
2567 } else {
2568 last->next = subtype;
2569 last = subtype;
2570 }
2571 last->next = NULL;
2572 }
2573 child = child->next;
2574 }
2575 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002576 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002577 xmlSchemaErrorContext(ctxt, schema, node, child);
2578 if ((ctxt != NULL) && (ctxt->error != NULL))
2579 ctxt->error(ctxt->userData,
2580 "Sequence %s has unexpected content\n",
2581 type->name);
2582 }
2583
2584 return (type);
2585}
2586
2587/**
2588 * xmlSchemaParseRestriction:
2589 * @ctxt: a schema validation context
2590 * @schema: the schema being built
2591 * @node: a subtree containing XML Schema informations
2592 * @simple: is that part of a simple type.
2593 *
2594 * parse a XML schema Restriction definition
2595 * *WARNING* this interface is highly subject to change
2596 *
2597 * Returns the type definition or NULL in case of error
2598 */
2599static xmlSchemaTypePtr
2600xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2601 xmlNodePtr node, int simple)
2602{
2603 xmlSchemaTypePtr type, subtype;
2604 xmlSchemaFacetPtr facet, lastfacet = NULL;
2605 xmlNodePtr child = NULL;
2606 xmlChar name[30];
2607 xmlChar *oldcontainer;
2608
2609 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2610 return (NULL);
2611
2612 oldcontainer = ctxt->container;
2613
2614 snprintf((char *)name, 30, "restriction %d", ctxt->counter++ + 1);
2615 type = xmlSchemaAddType(ctxt, schema, name);
2616 if (type == NULL)
2617 return (NULL);
2618 type->node = node;
2619 type->type = XML_SCHEMA_TYPE_RESTRICTION;
2620 type->id = xmlGetProp(node, BAD_CAST "id");
2621 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2622 if ((!simple) && (type->base == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002623 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002624 xmlSchemaErrorContext(ctxt, schema, node, child);
2625 if ((ctxt != NULL) && (ctxt->error != NULL))
2626 ctxt->error(ctxt->userData,
2627 "Restriction %s has no base\n",
2628 type->name);
2629 }
2630 ctxt->container = name;
2631
2632 child = node->children;
2633 if (IS_SCHEMA(child, "annotation")) {
2634 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2635 child = child->next;
2636 }
2637 subtype = NULL;
2638
2639 if (IS_SCHEMA(child, "all")) {
2640 subtype = (xmlSchemaTypePtr)
2641 xmlSchemaParseAll(ctxt, schema, child);
2642 child = child->next;
2643 type->subtypes = subtype;
2644 } else if (IS_SCHEMA(child, "choice")) {
2645 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2646 child = child->next;
2647 type->subtypes = subtype;
2648 } else if (IS_SCHEMA(child, "sequence")) {
2649 subtype = (xmlSchemaTypePtr)
2650 xmlSchemaParseSequence(ctxt, schema, child);
2651 child = child->next;
2652 type->subtypes = subtype;
2653 } else if (IS_SCHEMA(child, "group")) {
2654 subtype = (xmlSchemaTypePtr)
2655 xmlSchemaParseGroup(ctxt, schema, child);
2656 child = child->next;
2657 type->subtypes = subtype;
2658 } else {
2659 if (IS_SCHEMA(child, "simpleType")) {
2660 subtype = (xmlSchemaTypePtr)
2661 xmlSchemaParseSimpleType(ctxt, schema, child);
2662 child = child->next;
2663 type->baseType = subtype;
2664 }
2665 /*
2666 * Facets
2667 */
2668 while ((IS_SCHEMA(child, "minInclusive")) ||
2669 (IS_SCHEMA(child, "minExclusive")) ||
2670 (IS_SCHEMA(child, "maxInclusive")) ||
2671 (IS_SCHEMA(child, "maxExclusive")) ||
2672 (IS_SCHEMA(child, "totalDigits")) ||
2673 (IS_SCHEMA(child, "fractionDigits")) ||
2674 (IS_SCHEMA(child, "pattern")) ||
2675 (IS_SCHEMA(child, "enumeration")) ||
2676 (IS_SCHEMA(child, "whiteSpace")) ||
2677 (IS_SCHEMA(child, "length")) ||
2678 (IS_SCHEMA(child, "maxLength")) ||
2679 (IS_SCHEMA(child, "minLength"))) {
2680 facet = xmlSchemaParseFacet(ctxt, schema, child);
2681 if (facet != NULL) {
2682 if (lastfacet == NULL) {
2683 type->facets = facet;
2684 lastfacet = facet;
2685 } else {
2686 lastfacet->next = facet;
2687 lastfacet = facet;
2688 }
2689 lastfacet->next = NULL;
2690 }
2691 child = child->next;
2692 }
2693 }
2694 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2695 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002696 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002697 xmlSchemaErrorContext(ctxt, schema, node, child);
2698 if ((ctxt != NULL) && (ctxt->error != NULL))
2699 ctxt->error(ctxt->userData,
2700 "Restriction %s has unexpected content\n",
2701 type->name);
2702 }
2703 ctxt->container = oldcontainer;
2704 return (type);
2705}
2706
2707/**
2708 * xmlSchemaParseExtension:
2709 * @ctxt: a schema validation context
2710 * @schema: the schema being built
2711 * @node: a subtree containing XML Schema informations
2712 *
2713 * parse a XML schema Extension definition
2714 * *WARNING* this interface is highly subject to change
2715 *
2716 * Returns the type definition or NULL in case of error
2717 */
2718static xmlSchemaTypePtr
2719xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2720 xmlNodePtr node)
2721{
2722 xmlSchemaTypePtr type, subtype;
2723 xmlNodePtr child = NULL;
2724 xmlChar name[30];
2725 xmlChar *oldcontainer;
2726
2727 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2728 return (NULL);
2729
2730 oldcontainer = ctxt->container;
2731
2732 snprintf((char *)name, 30, "extension %d", ctxt->counter++ + 1);
2733 type = xmlSchemaAddType(ctxt, schema, name);
2734 if (type == NULL)
2735 return (NULL);
2736 type->node = node;
2737 type->type = XML_SCHEMA_TYPE_EXTENSION;
2738 type->id = xmlGetProp(node, BAD_CAST "id");
2739 ctxt->container = name;
2740
2741 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2742 if (type->base == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002743 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002744 xmlSchemaErrorContext(ctxt, schema, node, child);
2745 if ((ctxt != NULL) && (ctxt->error != NULL))
2746 ctxt->error(ctxt->userData,
2747 "Extension %s has no base\n",
2748 type->name);
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
2757 if (IS_SCHEMA(child, "all")) {
2758 subtype = xmlSchemaParseAll(ctxt, schema, child);
2759 child = child->next;
2760 } else if (IS_SCHEMA(child, "choice")) {
2761 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2762 child = child->next;
2763 } else if (IS_SCHEMA(child, "sequence")) {
2764 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2765 child = child->next;
2766 } else if (IS_SCHEMA(child, "group")) {
2767 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2768 child = child->next;
2769 }
2770 if (subtype != NULL)
2771 type->subtypes = subtype;
2772 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2773 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002774 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002775 xmlSchemaErrorContext(ctxt, schema, node, child);
2776 if ((ctxt != NULL) && (ctxt->error != NULL))
2777 ctxt->error(ctxt->userData,
2778 "Extension %s has unexpected content\n",
2779 type->name);
2780 }
2781 ctxt->container = oldcontainer;
2782 return (type);
2783}
2784
2785/**
2786 * xmlSchemaParseSimpleContent:
2787 * @ctxt: a schema validation context
2788 * @schema: the schema being built
2789 * @node: a subtree containing XML Schema informations
2790 *
2791 * parse a XML schema SimpleContent definition
2792 * *WARNING* this interface is highly subject to change
2793 *
2794 * Returns the type definition or NULL in case of error
2795 */
2796static xmlSchemaTypePtr
2797xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2798 xmlNodePtr node)
2799{
2800 xmlSchemaTypePtr type, subtype;
2801 xmlNodePtr child = NULL;
2802 xmlChar name[30];
2803
2804 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2805 return (NULL);
2806
2807
2808 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2809 type = xmlSchemaAddType(ctxt, schema, name);
2810 if (type == NULL)
2811 return (NULL);
2812 type->node = node;
2813 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
2814 type->id = xmlGetProp(node, BAD_CAST "id");
2815
2816 child = node->children;
2817 if (IS_SCHEMA(child, "annotation")) {
2818 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2819 child = child->next;
2820 }
2821 subtype = NULL;
2822 if (IS_SCHEMA(child, "restriction")) {
2823 subtype = (xmlSchemaTypePtr)
2824 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2825 child = child->next;
2826 } else if (IS_SCHEMA(child, "extension")) {
2827 subtype = (xmlSchemaTypePtr)
2828 xmlSchemaParseExtension(ctxt, schema, child);
2829 child = child->next;
2830 }
2831 type->subtypes = subtype;
2832 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002833 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002834 xmlSchemaErrorContext(ctxt, schema, node, child);
2835 if ((ctxt != NULL) && (ctxt->error != NULL))
2836 ctxt->error(ctxt->userData,
2837 "SimpleContent %s has unexpected content\n",
2838 type->name);
2839 }
2840 return (type);
2841}
2842
2843/**
2844 * xmlSchemaParseComplexContent:
2845 * @ctxt: a schema validation context
2846 * @schema: the schema being built
2847 * @node: a subtree containing XML Schema informations
2848 *
2849 * parse a XML schema ComplexContent definition
2850 * *WARNING* this interface is highly subject to change
2851 *
2852 * Returns the type definition or NULL in case of error
2853 */
2854static xmlSchemaTypePtr
2855xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2856 xmlNodePtr node)
2857{
2858 xmlSchemaTypePtr type, subtype;
2859 xmlNodePtr child = NULL;
2860 xmlChar name[30];
2861
2862 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2863 return (NULL);
2864
2865
2866 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2867 type = xmlSchemaAddType(ctxt, schema, name);
2868 if (type == NULL)
2869 return (NULL);
2870 type->node = node;
2871 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
2872 type->id = xmlGetProp(node, BAD_CAST "id");
2873
2874 child = node->children;
2875 if (IS_SCHEMA(child, "annotation")) {
2876 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2877 child = child->next;
2878 }
2879 subtype = NULL;
2880 if (IS_SCHEMA(child, "restriction")) {
2881 subtype = (xmlSchemaTypePtr)
2882 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2883 child = child->next;
2884 } else if (IS_SCHEMA(child, "extension")) {
2885 subtype = (xmlSchemaTypePtr)
2886 xmlSchemaParseExtension(ctxt, schema, child);
2887 child = child->next;
2888 }
2889 type->subtypes = subtype;
2890 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002891 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002892 xmlSchemaErrorContext(ctxt, schema, node, child);
2893 if ((ctxt != NULL) && (ctxt->error != NULL))
2894 ctxt->error(ctxt->userData,
2895 "ComplexContent %s has unexpected content\n",
2896 type->name);
2897 }
2898 return (type);
2899}
2900
2901/**
2902 * xmlSchemaParseComplexType:
2903 * @ctxt: a schema validation context
2904 * @schema: the schema being built
2905 * @node: a subtree containing XML Schema informations
2906 *
2907 * parse a XML schema Complex Type definition
2908 * *WARNING* this interface is highly subject to change
2909 *
2910 * Returns the type definition or NULL in case of error
2911 */
2912static xmlSchemaTypePtr
2913xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2914 xmlNodePtr node)
2915{
2916 xmlSchemaTypePtr type, subtype;
2917 xmlNodePtr child = NULL;
2918 xmlChar *name;
2919 xmlChar *oldcontainer;
2920
2921 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2922 return (NULL);
2923
2924 oldcontainer = ctxt->container;
2925 name = xmlGetProp(node, (const xmlChar *) "name");
2926 if (name == NULL) {
2927 char buf[100];
2928
2929 snprintf(buf, 99, "anontype%d", ctxt->counter++ + 1);
2930 name = xmlStrdup((xmlChar *) buf);
2931 }
2932 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002933 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002934 xmlSchemaErrorContext(ctxt, schema, node, child);
2935 if ((ctxt != NULL) && (ctxt->error != NULL))
2936 ctxt->error(ctxt->userData, "complexType has no name\n");
2937 return (NULL);
2938 }
2939 type = xmlSchemaAddType(ctxt, schema, name);
2940 if (type == NULL) {
2941 xmlFree(name);
2942 return (NULL);
2943 }
2944 type->node = node;
2945 type->type = XML_SCHEMA_TYPE_COMPLEX;
2946 type->id = xmlGetProp(node, BAD_CAST "id");
2947 ctxt->container = name;
2948
2949 child = node->children;
2950 if (IS_SCHEMA(child, "annotation")) {
2951 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2952 child = child->next;
2953 }
2954 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillarddecd64d2002-04-18 14:41:51 +00002955 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002956 child = child->next;
2957 } else if (IS_SCHEMA(child, "complexContent")) {
2958 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
2959 child = child->next;
2960 } else {
2961 subtype = NULL;
2962
2963 if (IS_SCHEMA(child, "all")) {
2964 subtype = xmlSchemaParseAll(ctxt, schema, child);
2965 child = child->next;
2966 } else if (IS_SCHEMA(child, "choice")) {
2967 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2968 child = child->next;
2969 } else if (IS_SCHEMA(child, "sequence")) {
2970 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2971 child = child->next;
2972 } else if (IS_SCHEMA(child, "group")) {
2973 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2974 child = child->next;
2975 }
2976 if (subtype != NULL)
2977 type->subtypes = subtype;
2978 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2979 }
2980 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002981 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002982 xmlSchemaErrorContext(ctxt, schema, node, child);
2983 if ((ctxt != NULL) && (ctxt->error != NULL))
2984 ctxt->error(ctxt->userData,
2985 "ComplexType %s has unexpected content\n",
2986 type->name);
2987 }
2988 ctxt->container = oldcontainer;
2989 xmlFree(name);
2990 return (type);
2991}
2992
2993
2994/**
2995 * xmlSchemaParseSchema:
2996 * @ctxt: a schema validation context
2997 * @node: a subtree containing XML Schema informations
2998 *
2999 * parse a XML schema definition from a node set
3000 * *WARNING* this interface is highly subject to change
3001 *
3002 * Returns the internal XML Schema structure built from the resource or
3003 * NULL in case of error
3004 */
3005static xmlSchemaPtr
3006xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3007{
3008 xmlSchemaPtr schema = NULL;
3009 xmlSchemaAnnotPtr annot;
3010 xmlNodePtr child = NULL;
3011 xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003012 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003013
3014 if ((ctxt == NULL) || (node == NULL))
3015 return (NULL);
3016
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003017 nberrors = ctxt->nberrors;
3018 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003019 if (IS_SCHEMA(node, "schema")) {
3020 schema = xmlSchemaNewSchema(ctxt);
3021 if (schema == NULL)
3022 return(NULL);
3023 schema->targetNamespace = xmlGetProp(node, BAD_CAST "targetNamespace");
3024 schema->id = xmlGetProp(node, BAD_CAST "id");
3025 schema->version = xmlGetProp(node, BAD_CAST "version");
3026 val = xmlGetProp(node, BAD_CAST "elementFormDefault");
3027 if (val != NULL) {
3028 if (xmlStrEqual(val, BAD_CAST "qualified"))
3029 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3030 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003031 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003032 xmlSchemaErrorContext(ctxt, schema, node, child);
3033 if ((ctxt != NULL) && (ctxt->error != NULL)) {
3034 ctxt->error(ctxt->userData,
3035 "Invalid value %s for elementFormDefault\n",
3036 val);
3037 }
3038 }
3039 xmlFree(val);
3040 }
3041 val = xmlGetProp(node, BAD_CAST "attributeFormDefault");
3042 if (val != NULL) {
3043 if (xmlStrEqual(val, BAD_CAST "qualified"))
3044 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3045 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003046 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003047 xmlSchemaErrorContext(ctxt, schema, node, child);
3048 if ((ctxt != NULL) && (ctxt->error != NULL)) {
3049 ctxt->error(ctxt->userData,
3050 "Invalid value %s for elementFormDefault\n",
3051 val);
3052 }
3053 }
3054 xmlFree(val);
3055 }
3056
3057 child = node->children;
3058 while ((IS_SCHEMA(child, "include")) ||
3059 (IS_SCHEMA(child, "import")) ||
3060 (IS_SCHEMA(child, "redefine")) ||
3061 (IS_SCHEMA(child, "annotation"))) {
3062 if (IS_SCHEMA(child, "annotation")) {
3063 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3064 if (schema->annot == NULL)
3065 schema->annot = annot;
3066 else
3067 xmlSchemaFreeAnnot(annot);
3068 } else if (IS_SCHEMA(child, "include")) {
3069 TODO
3070 } else if (IS_SCHEMA(child, "import")) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003071 xmlSchemaParseImport(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00003072 } else if (IS_SCHEMA(child, "redefine")) {
3073 TODO
3074 }
3075 child = child->next;
3076 }
3077 while (child != NULL) {
3078 if (IS_SCHEMA(child, "complexType")) {
3079 xmlSchemaParseComplexType(ctxt, schema, child);
3080 child = child->next;
3081 } else if (IS_SCHEMA(child, "simpleType")) {
3082 xmlSchemaParseSimpleType(ctxt, schema, child);
3083 child = child->next;
3084 } else if (IS_SCHEMA(child, "element")) {
3085 xmlSchemaParseElement(ctxt, schema, child, 1);
3086 child = child->next;
3087 } else if (IS_SCHEMA(child, "attribute")) {
3088 xmlSchemaParseAttribute(ctxt, schema, child);
3089 child = child->next;
3090 } else if (IS_SCHEMA(child, "attributeGroup")) {
3091 xmlSchemaParseAttributeGroup(ctxt, schema, child);
3092 child = child->next;
3093 } else if (IS_SCHEMA(child, "group")) {
3094 xmlSchemaParseGroup(ctxt, schema, child);
3095 child = child->next;
3096 } else if (IS_SCHEMA(child, "notation")) {
3097 xmlSchemaParseNotation(ctxt, schema, child);
3098 child = child->next;
3099 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003100 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003101 xmlSchemaErrorContext(ctxt, schema, node, child);
3102 if ((ctxt != NULL) && (ctxt->error != NULL))
3103 ctxt->error(ctxt->userData,
3104 "Schemas: unexpected element %s here \n",
3105 child->name);
3106 child = child->next;
3107 }
3108 while (IS_SCHEMA(child, "annotation")) {
3109 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3110 if (schema->annot == NULL)
3111 schema->annot = annot;
3112 else
3113 xmlSchemaFreeAnnot(annot);
3114 child = child->next;
3115 }
3116 }
3117 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003118 if (ctxt->nberrors != 0) {
3119 if (schema != NULL) {
3120 xmlSchemaFree(schema);
3121 schema = NULL;
3122 }
3123 }
3124 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003125#ifdef DEBUG
3126 if (schema == NULL)
3127 xmlGenericError(xmlGenericErrorContext,
3128 "xmlSchemaParse() failed\n");
3129#endif
3130
3131 return (schema);
3132}
3133
3134/************************************************************************
3135 * *
3136 * Validating using Schemas *
3137 * *
3138 ************************************************************************/
3139
3140/************************************************************************
3141 * *
3142 * Reading/Writing Schemas *
3143 * *
3144 ************************************************************************/
3145
3146/**
3147 * xmlSchemaNewParserCtxt:
3148 * @URL: the location of the schema
3149 *
3150 * Create an XML Schemas parse context for that file/resource expected
3151 * to contain an XML Schemas file.
3152 *
3153 * Returns the parser context or NULL in case of error
3154 */
3155xmlSchemaParserCtxtPtr
3156xmlSchemaNewParserCtxt(const char *URL) {
3157 xmlSchemaParserCtxtPtr ret;
3158
3159 if (URL == NULL)
3160 return(NULL);
3161
3162 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3163 if (ret == NULL) {
3164 xmlGenericError(xmlGenericErrorContext,
3165 "Failed to allocate new schama parser context for %s\n", URL);
3166 return (NULL);
3167 }
3168 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3169 ret->URL = xmlStrdup((const xmlChar *)URL);
3170 return (ret);
3171}
3172
3173/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003174 * xmlSchemaNewMemParserCtxt:
3175 * @buffer: a pointer to a char array containing the schemas
3176 * @size: the size of the array
3177 *
3178 * Create an XML Schemas parse context for that memory buffer expected
3179 * to contain an XML Schemas file.
3180 *
3181 * Returns the parser context or NULL in case of error
3182 */
3183xmlSchemaParserCtxtPtr
3184xmlSchemaNewMemParserCtxt(const char *buffer, int size) {
3185 xmlSchemaParserCtxtPtr ret;
3186
3187 if ((buffer == NULL) || (size <= 0))
3188 return(NULL);
3189
3190 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3191 if (ret == NULL) {
3192 xmlGenericError(xmlGenericErrorContext,
3193 "Failed to allocate new schama parser context\n");
3194 return (NULL);
3195 }
3196 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3197 ret->buffer = buffer;
3198 ret->size = size;
3199 return (ret);
3200}
3201
3202/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003203 * xmlSchemaFreeParserCtxt:
3204 * @ctxt: the schema parser context
3205 *
3206 * Free the resources associated to the schema parser context
3207 */
3208void
3209xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) {
3210 if (ctxt == NULL)
3211 return;
3212 if (ctxt->URL != NULL)
3213 xmlFree(ctxt->URL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003214 if (ctxt->doc != NULL)
3215 xmlFreeDoc(ctxt->doc);
Daniel Veillard4255d502002-04-16 15:50:10 +00003216 xmlFree(ctxt);
3217}
3218
3219/************************************************************************
3220 * *
3221 * Building the content models *
3222 * *
3223 ************************************************************************/
3224/**
3225 * xmlSchemaBuildAContentModel:
3226 * @type: the schema type definition
3227 * @ctxt: the schema parser context
3228 * @name: the element name whose content is being built
3229 *
3230 * Generate the automata sequence needed for that type
3231 */
3232static void
3233xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
3234 xmlSchemaParserCtxtPtr ctxt,
3235 const xmlChar *name) {
3236 if (type == NULL) {
3237 xmlGenericError(xmlGenericErrorContext,
3238 "Found unexpected type = NULL in %s content model\n",
3239 name);
3240 return;
3241 }
3242 switch (type->type) {
3243 case XML_SCHEMA_TYPE_ANY:
3244 /* TODO : handle the namespace too */
3245 /* TODO : make that a specific transition type */
3246 TODO
3247 ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state,
3248 NULL, BAD_CAST "*", NULL);
3249 break;
3250 case XML_SCHEMA_TYPE_ELEMENT: {
3251 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
3252 /* TODO : handle the namespace too */
3253 xmlAutomataStatePtr oldstate = ctxt->state;
3254 if (elem->maxOccurs >= UNBOUNDED) {
Daniel Veillard32370232002-10-16 14:08:14 +00003255 if (elem->minOccurs > 1) {
3256 xmlAutomataStatePtr tmp;
3257 int counter;
3258
3259 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3260 oldstate, NULL);
3261 oldstate = ctxt->state;
3262
3263 counter = xmlAutomataNewCounter(ctxt->am,
3264 elem->minOccurs - 1, UNBOUNDED);
3265
3266 if (elem->refDecl != NULL) {
3267 xmlSchemaBuildAContentModel(
3268 (xmlSchemaTypePtr) elem->refDecl,
3269 ctxt, elem->refDecl->name);
3270 } else {
3271 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3272 ctxt->state, NULL, elem->name, type);
3273 }
3274 tmp = ctxt->state;
3275 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3276 counter);
3277 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3278 NULL, counter);
3279
3280 } else {
3281 if (elem->refDecl != NULL) {
3282 xmlSchemaBuildAContentModel(
3283 (xmlSchemaTypePtr) elem->refDecl,
3284 ctxt, elem->refDecl->name);
3285 } else {
3286 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3287 ctxt->state, NULL, elem->name, type);
3288 }
3289 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3290 if (elem->minOccurs == 0) {
3291 /* basically an elem* */
3292 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3293 }
3294 }
3295 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3296 xmlAutomataStatePtr tmp;
3297 int counter;
3298
3299 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3300 oldstate, NULL);
3301 oldstate = ctxt->state;
3302
3303 counter = xmlAutomataNewCounter(ctxt->am,
3304 elem->minOccurs - 1, elem->maxOccurs - 1);
3305
Daniel Veillard4255d502002-04-16 15:50:10 +00003306 if (elem->refDecl != NULL) {
3307 xmlSchemaBuildAContentModel(
3308 (xmlSchemaTypePtr) elem->refDecl,
3309 ctxt, elem->refDecl->name);
3310 } else {
3311 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3312 ctxt->state, NULL, elem->name, type);
3313 }
Daniel Veillard32370232002-10-16 14:08:14 +00003314 tmp = ctxt->state;
3315 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3316 counter);
3317 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3318 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00003319 if (elem->minOccurs == 0) {
3320 /* basically an elem? */
3321 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3322 }
Daniel Veillard32370232002-10-16 14:08:14 +00003323
Daniel Veillard4255d502002-04-16 15:50:10 +00003324 } else {
3325 if (elem->refDecl != NULL) {
3326 xmlSchemaBuildAContentModel(
3327 (xmlSchemaTypePtr) elem->refDecl,
3328 ctxt, elem->refDecl->name);
3329 } else {
3330 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3331 ctxt->state, NULL, elem->name, type);
3332 }
3333 if (elem->minOccurs == 0) {
3334 /* basically an elem? */
3335 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3336 }
3337 }
3338 break;
3339 }
3340 case XML_SCHEMA_TYPE_SEQUENCE: {
3341 xmlSchemaTypePtr subtypes;
3342
3343 /*
Daniel Veillardb39bc392002-10-26 19:29:51 +00003344 * If max and min occurances are default (1) then
3345 * simply iterate over the subtypes
Daniel Veillard4255d502002-04-16 15:50:10 +00003346 */
Daniel Veillardb39bc392002-10-26 19:29:51 +00003347 if ((type->minOccurs == 1 ) && (type->maxOccurs == 1)) {
3348 subtypes = type->subtypes;
3349 while (subtypes != NULL) {
3350 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3351 subtypes = subtypes->next;
3352 }
3353 } else {
3354 xmlAutomataStatePtr oldstate = ctxt->state;
3355 if (type->maxOccurs >= UNBOUNDED) {
3356 if (type->minOccurs > 1) {
3357 xmlAutomataStatePtr tmp;
3358 int counter;
3359
3360 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3361 oldstate, NULL);
3362 oldstate = ctxt->state;
3363
3364 counter = xmlAutomataNewCounter(ctxt->am,
3365 type->minOccurs - 1, UNBOUNDED);
3366
3367 subtypes = type->subtypes;
3368 while (subtypes != NULL) {
3369 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3370 subtypes = subtypes->next;
3371 }
3372 tmp = ctxt->state;
3373 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3374 counter);
3375 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3376 NULL, counter);
3377
3378 } else {
3379 subtypes = type->subtypes;
3380 while (subtypes != NULL) {
3381 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3382 subtypes = subtypes->next;
3383 }
3384 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3385 if (type->minOccurs == 0) {
3386 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3387 ctxt->state);
3388 }
3389 }
3390 } else if ((type->maxOccurs > 1) || (type->minOccurs > 1)) {
3391 xmlAutomataStatePtr tmp;
3392 int counter;
3393
3394 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3395 oldstate, NULL);
3396 oldstate = ctxt->state;
3397
3398 counter = xmlAutomataNewCounter(ctxt->am,
3399 type->minOccurs - 1, type->maxOccurs - 1);
3400
3401 subtypes = type->subtypes;
3402 while (subtypes != NULL) {
3403 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3404 subtypes = subtypes->next;
3405 }
3406 tmp = ctxt->state;
3407 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3408 counter);
3409 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3410 NULL, counter);
3411 if (type->minOccurs == 0) {
3412 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3413 }
3414
3415 } else {
3416 subtypes = type->subtypes;
3417 while (subtypes != NULL) {
3418 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3419 subtypes = subtypes->next;
3420 }
3421 if (type->minOccurs == 0) {
3422 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3423 }
3424 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003425 }
3426 break;
3427 }
3428 case XML_SCHEMA_TYPE_CHOICE: {
3429 xmlSchemaTypePtr subtypes;
3430 xmlAutomataStatePtr start, end;
3431
3432 start = ctxt->state;
3433 end = xmlAutomataNewState(ctxt->am);
3434
3435 /*
3436 * iterate over the subtypes and remerge the end with an
3437 * epsilon transition
3438 */
Daniel Veillardb509f152002-04-17 16:28:10 +00003439 if (type->maxOccurs == 1) {
3440 subtypes = type->subtypes;
3441 while (subtypes != NULL) {
3442 ctxt->state = start;
3443 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3444 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3445 subtypes = subtypes->next;
3446 }
3447 } else {
3448 int counter;
3449 xmlAutomataStatePtr hop;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003450 int maxOccurs = type->maxOccurs == UNBOUNDED ?
3451 UNBOUNDED : type->maxOccurs - 1;
3452 int minOccurs = type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillardb509f152002-04-17 16:28:10 +00003453
3454 /*
3455 * use a counter to keep track of the number of transtions
3456 * which went through the choice.
3457 */
Daniel Veillardb39bc392002-10-26 19:29:51 +00003458 counter = xmlAutomataNewCounter(ctxt->am, minOccurs, maxOccurs);
Daniel Veillardb509f152002-04-17 16:28:10 +00003459 hop = xmlAutomataNewState(ctxt->am);
3460
3461 subtypes = type->subtypes;
3462 while (subtypes != NULL) {
3463 ctxt->state = start;
3464 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3465 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3466 subtypes = subtypes->next;
3467 }
3468 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3469 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3470 }
3471 if (type->minOccurs == 0) {
3472 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003473 }
3474 ctxt->state = end;
3475 break;
3476 }
3477 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003478 xmlAutomataStatePtr start;
3479 xmlSchemaTypePtr subtypes;
3480 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard441bc322002-04-20 17:38:48 +00003481 int lax;
Daniel Veillard7646b182002-04-20 06:41:40 +00003482
3483 subtypes = type->subtypes;
3484 if (subtypes == NULL)
3485 break;
3486 start = ctxt->state;
3487 while (subtypes != NULL) {
3488 ctxt->state = start;
3489 elem = (xmlSchemaElementPtr) subtypes;
3490
3491 /* TODO : handle the namespace too */
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003492 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
3493 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3494 elem->name, 1, 1, subtypes);
3495 } else {
3496 xmlAutomataNewCountTrans(ctxt->am, ctxt->state, ctxt->state,
3497 elem->name, elem->minOccurs,
3498 elem->maxOccurs, subtypes);
3499 }
Daniel Veillard7646b182002-04-20 06:41:40 +00003500 subtypes = subtypes->next;
3501 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003502 lax = type->minOccurs == 0;
3503 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3504 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003505 break;
3506 }
3507 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003508 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003509 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3510 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003511 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003512 if (type->baseType != NULL) {
3513 xmlSchemaTypePtr subtypes;
3514
3515 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3516 subtypes = type->subtypes;
3517 while (subtypes != NULL) {
3518 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3519 subtypes = subtypes->next;
3520 }
3521 } else if (type->subtypes != NULL)
3522 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3523 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003524 case XML_SCHEMA_TYPE_GROUP:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003525 if (type->subtypes == NULL) {
3526 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003527 case XML_SCHEMA_TYPE_COMPLEX:
3528 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3529 if (type->subtypes != NULL)
3530 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3531 break;
3532 default:
3533 xmlGenericError(xmlGenericErrorContext,
3534 "Found unexpected type %d in %s content model\n",
3535 type->type, name);
3536 return;
3537 }
3538}
3539/**
3540 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003541 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00003542 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003543 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00003544 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003545 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00003546 */
3547static void
3548xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3549 xmlSchemaParserCtxtPtr ctxt,
3550 const xmlChar *name) {
3551 xmlAutomataStatePtr start;
3552
Daniel Veillard4255d502002-04-16 15:50:10 +00003553 if (elem->contModel != NULL)
3554 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003555 if (elem->subtypes == NULL) {
3556 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003557 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003558 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003559 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3560 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003561 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3562 return;
3563
3564#ifdef DEBUG_CONTENT
3565 xmlGenericError(xmlGenericErrorContext,
3566 "Building content model for %s\n", name);
3567#endif
3568
Daniel Veillard4255d502002-04-16 15:50:10 +00003569 ctxt->am = xmlNewAutomata();
3570 if (ctxt->am == NULL) {
3571 xmlGenericError(xmlGenericErrorContext,
3572 "Cannot create automata for elem %s\n", name);
3573 return;
3574 }
3575 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3576 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3577 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003578 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003579 if (elem->contModel == NULL) {
3580 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3581 if ((ctxt != NULL) && (ctxt->error != NULL))
3582 ctxt->error(ctxt->userData,
3583 "failed to compile %s content model\n",
3584 name);
3585 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
3586 ctxt->nberrors++;
3587 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
3588 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3589 if ((ctxt != NULL) && (ctxt->error != NULL))
3590 ctxt->error(ctxt->userData,
Daniel Veillarde19fc232002-04-22 16:01:24 +00003591 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003592 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003593 ctxt->nberrors++;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003594 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00003595#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillarde19fc232002-04-22 16:01:24 +00003596 xmlGenericError(xmlGenericErrorContext,
3597 "Content model of %s:\n", name);
3598 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003599#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00003600 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003601 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003602 xmlFreeAutomata(ctxt->am);
3603 ctxt->am = NULL;
3604}
3605
3606/**
3607 * xmlSchemaRefFixupCallback:
3608 * @elem: the schema element context
3609 * @ctxt: the schema parser context
3610 *
3611 * Free the resources associated to the schema parser context
3612 */
3613static void
3614xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3615 xmlSchemaParserCtxtPtr ctxt,
3616 const xmlChar *name,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003617 const xmlChar *context ATTRIBUTE_UNUSED,
3618 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00003619{
3620 if ((ctxt == NULL) || (elem == NULL))
3621 return;
3622 if (elem->ref != NULL) {
3623 xmlSchemaElementPtr elemDecl;
3624
3625 if (elem->subtypes != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003626 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003627 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3628 if ((ctxt != NULL) && (ctxt->error != NULL))
3629 ctxt->error(ctxt->userData,
3630 "Schemas: element %s have both ref and subtype\n",
3631 name);
3632 return;
3633 }
3634 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3635 elem->ref, elem->refNs);
3636
3637 if (elemDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003638 ctxt->nberrors++;
3639 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003640 if ((ctxt != NULL) && (ctxt->error != NULL))
3641 ctxt->error(ctxt->userData,
3642 "Schemas: element %s ref to %s not found\n",
3643 name, elem->ref);
3644 return;
3645 }
3646 elem->refDecl = elemDecl;
3647 } else if (elem->namedType != NULL) {
3648 xmlSchemaTypePtr typeDecl;
3649
3650 if (elem->subtypes != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003651 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003652 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3653 if ((ctxt != NULL) && (ctxt->error != NULL))
3654 ctxt->error(ctxt->userData,
3655 "Schemas: element %s have both type and subtype\n",
3656 name);
3657 return;
3658 }
3659 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3660 elem->namedTypeNs);
3661
3662 if (typeDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003663 ctxt->nberrors++;
3664 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003665 if ((ctxt != NULL) && (ctxt->error != NULL))
3666 ctxt->error(ctxt->userData,
3667 "Schemas: element %s type %s not found\n",
3668 name, elem->namedType);
3669 return;
3670 }
3671 elem->subtypes = typeDecl;
3672 }
3673}
3674
3675/**
3676 * xmlSchemaTypeFixup:
3677 * @typeDecl: the schema type definition
3678 * @ctxt: the schema parser context
3679 *
3680 * Fixes the content model of the type.
3681 */
3682static void
3683xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3684 xmlSchemaParserCtxtPtr ctxt,
3685 const xmlChar *name)
3686{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003687 if (typeDecl == NULL)
3688 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003689 if (name == NULL)
3690 name = typeDecl->name;
3691 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3692 switch (typeDecl->type) {
3693 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3694 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003695 if (typeDecl->subtypes != NULL)
3696 typeDecl->contentType = typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003697 break;
3698 }
3699 case XML_SCHEMA_TYPE_RESTRICTION: {
3700 if (typeDecl->subtypes != NULL)
3701 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3702
3703 if (typeDecl->base != NULL) {
3704 xmlSchemaTypePtr baseType;
3705
3706 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3707 typeDecl->baseNs);
3708 if (baseType == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003709 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003710 if ((ctxt != NULL) && (ctxt->error != NULL))
3711 ctxt->error(ctxt->userData,
3712 "Schemas: type %s base type %s not found\n",
3713 name, typeDecl->base);
3714 }
3715 typeDecl->baseType = baseType;
3716 }
3717 if (typeDecl->subtypes == NULL)
3718 /* 1.1.1 */
3719 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3720 else if ((typeDecl->subtypes->subtypes == NULL) &&
3721 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3722 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3723 /* 1.1.2 */
3724 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3725 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3726 (typeDecl->subtypes->subtypes == NULL))
3727 /* 1.1.3 */
3728 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3729 else {
3730 /* 1.2 and 2.X are applied at the other layer */
3731 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3732 }
3733 break;
3734 }
3735 case XML_SCHEMA_TYPE_EXTENSION: {
3736 xmlSchemaContentType explicitContentType;
3737 xmlSchemaTypePtr base;
3738
3739 if (typeDecl->base != NULL) {
3740 xmlSchemaTypePtr baseType;
3741
3742 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3743 typeDecl->baseNs);
3744 if (baseType == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003745 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003746 if ((ctxt != NULL) && (ctxt->error != NULL))
3747 ctxt->error(ctxt->userData,
3748 "Schemas: type %s base type %s not found\n",
3749 name, typeDecl->base);
3750 }
3751 typeDecl->baseType = baseType;
3752 }
3753 if (typeDecl->subtypes != NULL)
3754 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3755
Daniel Veillard8651f532002-04-17 09:06:27 +00003756 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003757 if (typeDecl->subtypes == NULL)
3758 /* 1.1.1 */
3759 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3760 else if ((typeDecl->subtypes->subtypes == NULL) &&
3761 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3762 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3763 /* 1.1.2 */
3764 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3765 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3766 (typeDecl->subtypes->subtypes == NULL))
3767 /* 1.1.3 */
3768 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3769
3770 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3771 typeDecl->baseNs);
3772 if (base == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003773 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003774 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3775 if ((ctxt != NULL) && (ctxt->error != NULL))
3776 ctxt->error(ctxt->userData,
3777 "Schemas: base type %s of type %s not found\n",
3778 typeDecl->base, name);
3779 return;
3780 }
3781 xmlSchemaTypeFixup(base, ctxt, NULL);
3782 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3783 /* 2.1 */
3784 typeDecl->contentType = base->contentType;
3785 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3786 /* 2.2 imbitable ! */
3787 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3788 } else {
3789 /* 2.3 imbitable pareil ! */
3790 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3791 }
3792 break;
3793 }
3794 case XML_SCHEMA_TYPE_COMPLEX: {
3795 if (typeDecl->subtypes == NULL) {
3796 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3797 } else {
3798 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3799 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3800 else {
3801 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003802 if (typeDecl->subtypes != NULL)
3803 typeDecl->contentType =
3804 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003805 }
3806 }
3807 break;
3808 }
3809 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3810 if (typeDecl->subtypes == NULL) {
3811 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3812 } else {
3813 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3814 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3815 else {
3816 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003817 if (typeDecl->subtypes != NULL)
3818 typeDecl->contentType =
3819 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003820 }
3821 }
3822 break;
3823 }
3824 case XML_SCHEMA_TYPE_SEQUENCE:
3825 case XML_SCHEMA_TYPE_GROUP:
3826 case XML_SCHEMA_TYPE_ALL:
3827 case XML_SCHEMA_TYPE_CHOICE:
3828 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3829 break;
3830 case XML_SCHEMA_TYPE_BASIC:
3831 case XML_SCHEMA_TYPE_ANY:
3832 case XML_SCHEMA_TYPE_FACET:
3833 case XML_SCHEMA_TYPE_SIMPLE:
3834 case XML_SCHEMA_TYPE_UR:
3835 case XML_SCHEMA_TYPE_ELEMENT:
3836 case XML_SCHEMA_TYPE_ATTRIBUTE:
Daniel Veillard118aed72002-09-24 14:13:13 +00003837 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
Daniel Veillard4255d502002-04-16 15:50:10 +00003838 case XML_SCHEMA_TYPE_NOTATION:
3839 case XML_SCHEMA_TYPE_LIST:
3840 case XML_SCHEMA_TYPE_UNION:
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 case XML_SCHEMA_FACET_TOTALDIGITS:
3846 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3847 case XML_SCHEMA_FACET_PATTERN:
3848 case XML_SCHEMA_FACET_ENUMERATION:
3849 case XML_SCHEMA_FACET_WHITESPACE:
3850 case XML_SCHEMA_FACET_LENGTH:
3851 case XML_SCHEMA_FACET_MAXLENGTH:
3852 case XML_SCHEMA_FACET_MINLENGTH:
3853 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3854 break;
3855 }
3856 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003857#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003858 if (typeDecl->node != NULL) {
3859 xmlGenericError(xmlGenericErrorContext,
3860 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3861 xmlGetLineNo(typeDecl->node));
3862 } else {
3863 xmlGenericError(xmlGenericErrorContext,
3864 "Type of %s :", name);
3865 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003866 switch (typeDecl->contentType) {
3867 case XML_SCHEMA_CONTENT_SIMPLE:
3868 xmlGenericError(xmlGenericErrorContext,
3869 "simple\n"); break;
3870 case XML_SCHEMA_CONTENT_ELEMENTS:
3871 xmlGenericError(xmlGenericErrorContext,
3872 "elements\n"); break;
3873 case XML_SCHEMA_CONTENT_UNKNOWN:
3874 xmlGenericError(xmlGenericErrorContext,
3875 "unknown !!!\n"); break;
3876 case XML_SCHEMA_CONTENT_EMPTY:
3877 xmlGenericError(xmlGenericErrorContext,
3878 "empty\n"); break;
3879 case XML_SCHEMA_CONTENT_MIXED:
3880 xmlGenericError(xmlGenericErrorContext,
3881 "mixed\n"); break;
3882 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3883 xmlGenericError(xmlGenericErrorContext,
3884 "mixed or elems\n"); break;
3885 case XML_SCHEMA_CONTENT_BASIC:
3886 xmlGenericError(xmlGenericErrorContext,
3887 "basic\n"); break;
3888 default:
3889 xmlGenericError(xmlGenericErrorContext,
3890 "not registered !!!\n"); break;
3891 }
3892#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003893}
3894
3895/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003896 * xmlSchemaCheckFacet:
3897 * @facet: the facet
3898 * @typeDecl: the schema type definition
3899 * @ctxt: the schema parser context or NULL
3900 * @name: name of the type
3901 *
3902 * Checks the default values types, especially for facets
3903 *
3904 * Returns 0 if okay or -1 in cae of error
3905 */
3906int
3907xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
3908 xmlSchemaTypePtr typeDecl,
3909 xmlSchemaParserCtxtPtr ctxt,
3910 const xmlChar *name)
3911{
3912 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3913 int ret = 0;
3914
3915 if (nonNegativeIntegerType == NULL) {
3916 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3917 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3918 }
3919 switch (facet->type) {
3920 case XML_SCHEMA_FACET_MININCLUSIVE:
3921 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3922 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3923 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3924 /*
3925 * Okay we need to validate the value
3926 * at that point.
3927 */
3928 xmlSchemaValidCtxtPtr vctxt;
3929
3930 vctxt = xmlSchemaNewValidCtxt(NULL);
3931 if (vctxt == NULL)
3932 break;
3933 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3934 facet->value);
3935 facet->val = vctxt->value;
3936 vctxt->value = NULL;
3937 if (facet->val == NULL) {
3938 /* error code */
3939 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003940 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003941 xmlSchemaErrorContext(ctxt, NULL,
3942 facet->node, NULL);
3943 ctxt->error(ctxt->userData,
3944 "Schemas: type %s facet value %s invalid\n",
3945 name, facet->value);
3946 }
3947 ret = -1;
3948 }
3949 xmlSchemaFreeValidCtxt(vctxt);
3950 break;
3951 }
3952 case XML_SCHEMA_FACET_ENUMERATION: {
3953 /*
3954 * Okay we need to validate the value
3955 * at that point.
3956 */
3957 xmlSchemaValidCtxtPtr vctxt;
3958 int tmp;
3959
3960 vctxt = xmlSchemaNewValidCtxt(NULL);
3961 if (vctxt == NULL)
3962 break;
3963 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3964 facet->value);
3965 if (tmp != 0) {
3966 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003967 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003968 xmlSchemaErrorContext(ctxt, NULL,
3969 facet->node, NULL);
3970 ctxt->error(ctxt->userData,
3971 "Schemas: type %s enumeration value %s invalid\n",
3972 name, facet->value);
3973 }
3974 ret = -1;
3975 }
3976 xmlSchemaFreeValidCtxt(vctxt);
3977 break;
3978 }
3979 case XML_SCHEMA_FACET_PATTERN:
3980 facet->regexp = xmlRegexpCompile(facet->value);
3981 if (facet->regexp == NULL) {
3982 /* error code */
3983 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003984 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003985 ctxt->error(ctxt->userData,
3986 "Schemas: type %s facet regexp %s invalid\n",
3987 name, facet->value);
3988 }
3989 ret = -1;
3990 }
3991 break;
3992 case XML_SCHEMA_FACET_TOTALDIGITS:
3993 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3994 case XML_SCHEMA_FACET_LENGTH:
3995 case XML_SCHEMA_FACET_MAXLENGTH:
3996 case XML_SCHEMA_FACET_MINLENGTH: {
3997 int tmp;
3998
3999 tmp = xmlSchemaValidatePredefinedType(
4000 nonNegativeIntegerType, facet->value,
4001 &facet->val);
4002 if (tmp != 0) {
4003 /* error code */
4004 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004005 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004006 xmlSchemaErrorContext(ctxt, NULL,
4007 facet->node, NULL);
4008 ctxt->error(ctxt->userData,
4009 "Schemas: type %s facet value %s invalid\n",
4010 name, facet->value);
4011 }
4012 ret = -1;
4013 }
4014 break;
4015 }
4016 case XML_SCHEMA_FACET_WHITESPACE: {
4017 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
4018 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4019 } else if (xmlStrEqual(facet->value,
4020 BAD_CAST"replace")) {
4021 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4022 } else if (xmlStrEqual(facet->value,
4023 BAD_CAST"collapse")) {
4024 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4025 } else {
4026 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004027 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004028 xmlSchemaErrorContext(ctxt, NULL,
4029 facet->node, NULL);
4030 ctxt->error(ctxt->userData,
4031 "Schemas: type %s whiteSpace value %s invalid\n",
4032 name, facet->value);
4033 }
4034 ret = -1;
4035 }
4036 }
4037 default:
4038 break;
4039 }
4040 return(ret);
4041}
4042
4043/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004044 * xmlSchemaCheckDefaults:
4045 * @typeDecl: the schema type definition
4046 * @ctxt: the schema parser context
4047 *
4048 * Checks the default values types, especially for facets
4049 */
4050static void
4051xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
4052 xmlSchemaParserCtxtPtr ctxt,
4053 const xmlChar *name)
4054{
Daniel Veillard4255d502002-04-16 15:50:10 +00004055 if (name == NULL)
4056 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004057 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
4058 if (typeDecl->facets != NULL) {
4059 xmlSchemaFacetPtr facet = typeDecl->facets;
4060 while (facet != NULL) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004061 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004062 facet = facet->next;
4063 }
4064 }
4065 }
4066}
4067
4068/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004069 * xmlSchemaAttrGrpFixup:
4070 * @attrgrpDecl: the schema attribute definition
4071 * @ctxt: the schema parser context
4072 * @name: the attribute name
4073 *
4074 * Fixes finish doing the computations on the attributes definitions
4075 */
4076static void
4077xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
4078 xmlSchemaParserCtxtPtr ctxt,
4079 const xmlChar *name)
4080{
4081 if (name == NULL)
4082 name = attrgrpDecl->name;
4083 if (attrgrpDecl->attributes != NULL)
4084 return;
4085 if (attrgrpDecl->ref != NULL) {
4086 xmlSchemaAttributeGroupPtr ref;
4087
4088 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4089 attrgrpDecl->refNs);
4090 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004091 ctxt->nberrors++;
4092 xmlSchemaErrorContext(ctxt, NULL, attrgrpDecl->node, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004093 if ((ctxt != NULL) && (ctxt->error != NULL))
4094 ctxt->error(ctxt->userData,
4095 "Schemas: attribute group %s reference %s not found\n",
4096 name, attrgrpDecl->ref);
4097 return;
4098 }
4099 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4100 attrgrpDecl->attributes = ref->attributes;
4101 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004102 ctxt->nberrors++;
4103 xmlSchemaErrorContext(ctxt, NULL, attrgrpDecl->node, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004104 if ((ctxt != NULL) && (ctxt->error != NULL))
4105 ctxt->error(ctxt->userData,
4106 "Schemas: attribute %s has no attributes nor reference\n",
4107 name);
4108 }
4109}
4110
4111/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004112 * xmlSchemaAttrFixup:
4113 * @attrDecl: the schema attribute definition
4114 * @ctxt: the schema parser context
4115 * @name: the attribute name
4116 *
4117 * Fixes finish doing the computations on the attributes definitions
4118 */
4119static void
4120xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
4121 xmlSchemaParserCtxtPtr ctxt,
4122 const xmlChar *name)
4123{
4124 if (name == NULL)
4125 name = attrDecl->name;
4126 if (attrDecl->subtypes != NULL)
4127 return;
4128 if (attrDecl->typeName != NULL) {
4129 xmlSchemaTypePtr type;
4130
4131 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4132 attrDecl->typeNs);
4133 if (type == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004134 ctxt->nberrors++;
4135 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004136 if ((ctxt != NULL) && (ctxt->error != NULL))
4137 ctxt->error(ctxt->userData,
4138 "Schemas: attribute %s type %s not found\n",
4139 name, attrDecl->typeName);
4140 }
4141 attrDecl->subtypes = type;
4142 } else if (attrDecl->ref != NULL) {
4143 xmlSchemaAttributePtr ref;
4144
4145 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4146 attrDecl->refNs);
4147 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004148 ctxt->nberrors++;
4149 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004150 if ((ctxt != NULL) && (ctxt->error != NULL))
4151 ctxt->error(ctxt->userData,
4152 "Schemas: attribute %s reference %s not found\n",
4153 name, attrDecl->ref);
4154 return;
4155 }
4156 xmlSchemaAttrFixup(ref, ctxt, NULL);
4157 attrDecl->subtypes = ref->subtypes;
4158 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004159 ctxt->nberrors++;
4160 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004161 if ((ctxt != NULL) && (ctxt->error != NULL))
4162 ctxt->error(ctxt->userData,
4163 "Schemas: attribute %s has no type nor reference\n",
4164 name);
4165 }
4166}
4167
4168/**
4169 * xmlSchemaParse:
4170 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004171 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004172 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004173 * XML Shema struture which can be used to validate instances.
4174 * *WARNING* this interface is highly subject to change
4175 *
4176 * Returns the internal XML Schema structure built from the resource or
4177 * NULL in case of error
4178 */
4179xmlSchemaPtr
4180xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4181{
4182 xmlSchemaPtr ret = NULL;
4183 xmlDocPtr doc;
4184 xmlNodePtr root, cur, delete;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004185 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00004186
4187 xmlSchemaInitTypes();
4188
Daniel Veillard6045c902002-10-09 21:13:59 +00004189 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004190 return (NULL);
4191
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004192 nberrors = ctxt->nberrors;
4193 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004194 ctxt->counter = 0;
4195 ctxt->container = NULL;
4196
4197 /*
4198 * First step is to parse the input document into an DOM/Infoset
4199 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004200 if (ctxt->URL != NULL) {
4201 doc = xmlParseFile((const char *) ctxt->URL);
4202 if (doc == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004203 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004204 if (ctxt->error != NULL)
4205 ctxt->error(ctxt->userData,
4206 "xmlSchemaParse: could not load %s\n", ctxt->URL);
4207 return (NULL);
4208 }
4209 } else if (ctxt->buffer != NULL) {
4210 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
4211 if (doc == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004212 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004213 if (ctxt->error != NULL)
4214 ctxt->error(ctxt->userData,
4215 "xmlSchemaParse: could not parse schemas\n");
4216 return (NULL);
4217 }
4218 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4219 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4220 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004221 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004222 if (ctxt->error != NULL)
4223 ctxt->error(ctxt->userData,
4224 "xmlSchemaParse: nothing to parse\n");
4225 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004226 }
4227
4228 /*
4229 * Then extract the root and Schema parse it
4230 */
4231 root = xmlDocGetRootElement(doc);
4232 if (root == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004233 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004234 if (ctxt->error != NULL)
4235 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
4236 ctxt->URL);
4237 return (NULL);
4238 }
4239
4240 /*
4241 * Remove all the blank text nodes
4242 */
4243 delete = NULL;
4244 cur = root;
4245 while (cur != NULL) {
4246 if (delete != NULL) {
4247 xmlUnlinkNode(delete);
4248 xmlFreeNode(delete);
4249 delete = NULL;
4250 }
4251 if (cur->type == XML_TEXT_NODE) {
4252 if (IS_BLANK_NODE(cur)) {
4253 if (xmlNodeGetSpacePreserve(cur) != 1) {
4254 delete = cur;
4255 }
4256 }
4257 } else if ((cur->type != XML_ELEMENT_NODE) &&
4258 (cur->type != XML_CDATA_SECTION_NODE)) {
4259 delete = cur;
4260 goto skip_children;
4261 }
4262
4263 /*
4264 * Skip to next node
4265 */
4266 if (cur->children != NULL) {
4267 if ((cur->children->type != XML_ENTITY_DECL) &&
4268 (cur->children->type != XML_ENTITY_REF_NODE) &&
4269 (cur->children->type != XML_ENTITY_NODE)) {
4270 cur = cur->children;
4271 continue;
4272 }
4273 }
4274skip_children:
4275 if (cur->next != NULL) {
4276 cur = cur->next;
4277 continue;
4278 }
4279
4280 do {
4281 cur = cur->parent;
4282 if (cur == NULL)
4283 break;
4284 if (cur == root) {
4285 cur = NULL;
4286 break;
4287 }
4288 if (cur->next != NULL) {
4289 cur = cur->next;
4290 break;
4291 }
4292 } while (cur != NULL);
4293 }
4294 if (delete != NULL) {
4295 xmlUnlinkNode(delete);
4296 xmlFreeNode(delete);
4297 delete = NULL;
4298 }
4299
4300 /*
4301 * Then do the parsing for good
4302 */
4303 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00004304 if (ret == NULL)
4305 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004306 ret->doc = doc;
4307
4308 /*
4309 * Then fix all the references.
4310 */
4311 ctxt->schema = ret;
4312 xmlHashScanFull(ret->elemDecl,
4313 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
4314
4315 /*
4316 * Then fixup all types properties
4317 */
4318 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
4319
4320 /*
4321 * Then build the content model for all elements
4322 */
4323 xmlHashScan(ret->elemDecl,
4324 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
4325
4326 /*
4327 * Then check the defaults part of the type like facets values
4328 */
4329 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
4330
4331 /*
4332 * Then fixup all attributes declarations
4333 */
4334 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4335
Daniel Veillard13e04c62002-04-23 17:51:29 +00004336 /*
4337 * Then fixup all attributes group declarations
4338 */
4339 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
4340
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004341 if (ctxt->nberrors != 0) {
4342 xmlSchemaFree(ret);
4343 ret = NULL;
4344 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004345 return (ret);
4346}
4347
4348/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004349 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00004350 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00004351 * @err: the error callback
4352 * @warn: the warning callback
4353 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00004354 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004355 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004356 */
4357void
4358xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
4359 xmlSchemaValidityErrorFunc err,
4360 xmlSchemaValidityWarningFunc warn, void *ctx) {
4361 if (ctxt == NULL)
4362 return;
4363 ctxt->error = err;
4364 ctxt->warning = warn;
4365 ctxt->userData = ctx;
4366}
4367
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004368/**
4369 * xmlSchemaFacetTypeToString:
4370 * @type: the facet type
4371 *
4372 * Convert the xmlSchemaTypeType to a char string.
4373 *
4374 * Returns the char string representation of the facet type if the
4375 * type is a facet and an "Internal Error" string otherwise.
4376 */
4377static const char *
4378xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
4379{
4380 switch (type) {
4381 case XML_SCHEMA_FACET_PATTERN:
4382 return ("pattern");
4383 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4384 return ("maxExclusive");
4385 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4386 return ("maxInclusive");
4387 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4388 return ("minExclusive");
4389 case XML_SCHEMA_FACET_MININCLUSIVE:
4390 return ("minInclusive");
4391 case XML_SCHEMA_FACET_WHITESPACE:
4392 return ("whiteSpace");
4393 case XML_SCHEMA_FACET_ENUMERATION:
4394 return ("enumeration");
4395 case XML_SCHEMA_FACET_LENGTH:
4396 return ("length");
4397 case XML_SCHEMA_FACET_MAXLENGTH:
4398 return ("maxLength");
4399 case XML_SCHEMA_FACET_MINLENGTH:
4400 return ("minLength");
4401 case XML_SCHEMA_FACET_TOTALDIGITS:
4402 return ("totalDigits");
4403 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4404 return ("fractionDigits");
4405 default:
4406 break;
4407 }
4408 return ("Internal Error");
4409}
4410
4411/**
4412 * xmlSchemaValidateFacets:
4413 * @ctxt: a schema validation context
4414 * @base: the base type
4415 * @facets: the list of facets to check
4416 * @value: the lexical repr of the value to validate
4417 * @val: the precomputed value
4418 *
4419 * Check a value against all facet conditions
4420 *
4421 * Returns 0 if the element is schemas valid, a positive error code
4422 * number otherwise and -1 in case of internal or API error.
4423 */
4424static int
4425xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
4426 xmlSchemaTypePtr base,
4427 xmlSchemaFacetPtr facets,
4428 xmlChar *value) {
4429 int ret = 0;
4430 int tmp = 0;
4431 xmlSchemaTypeType type;
4432 xmlSchemaFacetPtr facet = facets;
4433
4434 while (facet != NULL) {
4435 type = facet->type;
4436 if (type == XML_SCHEMA_FACET_ENUMERATION) {
4437 tmp = 1;
4438
4439 while (facet != NULL) {
4440 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4441 if (tmp == 0) {
4442 return 0;
4443 }
4444 facet = facet->next;
4445 }
4446 } else
4447 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4448
4449 if (tmp != 0) {
4450 ret = tmp;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004451 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004452 if (ctxt->error != NULL)
4453 ctxt->error(ctxt->userData,
4454 "Failed to validate type with facet %s\n",
4455 xmlSchemaFacetTypeToString(type));
4456 ctxt->err = XML_SCHEMAS_ERR_FACET;
4457 }
4458 if (facet != NULL)
4459 facet = facet->next;
4460 }
4461 return (ret);
4462}
4463
Daniel Veillard4255d502002-04-16 15:50:10 +00004464/************************************************************************
4465 * *
4466 * Simple type validation *
4467 * *
4468 ************************************************************************/
4469
4470/**
4471 * xmlSchemaValidateSimpleValue:
4472 * @ctxt: a schema validation context
4473 * @type: the type declaration
4474 * @value: the value to validate
4475 *
4476 * Validate a value against a simple type
4477 *
4478 * Returns 0 if the value is valid, a positive error code
4479 * number otherwise and -1 in case of internal or API error.
4480 */
4481static int
4482xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4483 xmlSchemaTypePtr type,
4484 xmlChar *value) {
4485 int ret = 0;
4486 /*
4487 * First normalize the value accordingly to Schema Datatype
4488 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4489 */
4490 /*
4491 * Then check the normalized value against the lexical space of the
4492 * type.
4493 */
4494 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4495 if (ctxt->value != NULL) {
4496 xmlSchemaFreeValue(ctxt->value);
4497 ctxt->value = NULL;
4498 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004499 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
4500 ctxt->cur);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004501 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004502 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004503 if (ctxt->error != NULL)
4504 ctxt->error(ctxt->userData,
4505 "Failed to validate basic type %s\n", type->name);
4506 ctxt->err = XML_SCHEMAS_ERR_VALUE;
4507 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004508 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4509 xmlSchemaTypePtr base;
4510 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00004511
4512 base = type->baseType;
4513 if (base != NULL) {
4514 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4515 } else if (type->subtypes != NULL) {
4516
4517 }
4518 /*
4519 * Do not validate facets when working on building the Schemas
4520 */
4521 if (ctxt->schema != NULL) {
4522 if (ret == 0) {
4523 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004524 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004525 }
4526 }
4527 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4528 xmlSchemaTypePtr base;
4529
4530 base = type->subtypes;
4531 if (base != NULL) {
4532 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4533 } else {
4534 TODO
4535 }
4536 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4537 xmlSchemaTypePtr base;
4538 xmlChar *cur, *end, tmp;
4539 int ret2;
4540
4541 base = type->subtypes;
4542 if (base == NULL) {
4543 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004544 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004545 if (ctxt->error != NULL) {
4546 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4547 ctxt->error(ctxt->userData,
4548 "Internal: List type %s has no base type\n",
4549 type->name);
4550 }
4551 return(-1);
4552 }
4553 cur = value;
4554 do {
4555 while (IS_BLANK(*cur)) cur++;
4556 end = cur;
4557 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4558 if (end == cur)
4559 break;
4560 tmp = *end;
4561 *end = 0;
4562 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4563 if (ret2 != 0)
4564 ret = 1;
4565 *end = tmp;
4566 cur = end;
4567 } while (*cur != 0);
4568 } else {
4569 TODO
4570 }
4571 return(ret);
4572}
4573
4574/************************************************************************
4575 * *
4576 * DOM Validation code *
4577 * *
4578 ************************************************************************/
4579
4580static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4581 xmlNodePtr node);
4582static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4583 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4584static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4585 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4586
4587/**
4588 * xmlSchemaRegisterAttributes:
4589 * @ctxt: a schema validation context
4590 * @attrs: a list of attributes
4591 *
4592 * Register the list of attributes as the set to be validated on that element
4593 *
4594 * Returns -1 in case of error, 0 otherwise
4595 */
4596static int
4597xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4598 xmlAttrPtr attrs) {
4599 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004600 if ((attrs->ns != NULL) &&
4601 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4602 attrs = attrs->next;
4603 continue;
4604 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004605 if (ctxt->attrNr >= ctxt->attrMax) {
4606 xmlSchemaAttrStatePtr tmp;
4607
4608 ctxt->attrMax *= 2;
4609 tmp = (xmlSchemaAttrStatePtr)
4610 xmlRealloc(ctxt->attr, ctxt->attrMax *
4611 sizeof(xmlSchemaAttrState));
4612 if (tmp == NULL) {
4613 ctxt->attrMax /= 2;
4614 return(-1);
4615 }
4616 ctxt->attr = tmp;
4617 }
4618 ctxt->attr[ctxt->attrNr].attr = attrs;
4619 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4620 ctxt->attrNr++;
4621 attrs = attrs->next;
4622 }
4623 return(0);
4624}
4625
4626/**
4627 * xmlSchemaCheckAttributes:
4628 * @ctxt: a schema validation context
4629 * @node: the node carrying it.
4630 *
4631 * Check that the registered set of attributes on the current node
4632 * has been properly validated.
4633 *
4634 * Returns 0 if validity constraints are met, 1 otherwise.
4635 */
4636static int
4637xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4638 int ret = 0;
4639 int i;
4640
4641 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4642 if (ctxt->attr[i].attr == NULL)
4643 break;
4644 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4645 ret = 1;
4646 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004647 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004648 if (ctxt->error != NULL)
4649 ctxt->error(ctxt->userData,
4650 "Attribute %s on %s is unknown\n",
4651 ctxt->attr[i].attr->name,
4652 node->name);
4653 }
4654 }
4655 return(ret);
4656}
4657
4658/**
4659 * xmlSchemaValidateSimpleContent:
4660 * @ctxt: a schema validation context
4661 * @elem: an element
4662 * @type: the type declaration
4663 *
4664 * Validate the content of an element expected to be a simple type
4665 *
4666 * Returns 0 if the element is schemas valid, a positive error code
4667 * number otherwise and -1 in case of internal or API error.
4668 */
4669static int
4670xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004671 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004672 xmlNodePtr child;
4673 xmlSchemaTypePtr type, base;
4674 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004675 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004676
4677 child = ctxt->node;
4678 type = ctxt->type;
4679
4680 /*
4681 * Validation Rule: Element Locally Valid (Type): 3.1.3
4682 */
4683 value = xmlNodeGetContent(child);
4684 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4685 switch (type->type) {
4686 case XML_SCHEMA_TYPE_RESTRICTION: {
4687 xmlSchemaFacetPtr facet;
4688
4689 base = type->baseType;
4690 if (base != NULL) {
4691 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4692 } else {
4693 TODO
4694 }
4695 if (ret == 0) {
4696 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004697 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004698 }
4699 break;
4700 }
4701 default:
4702 TODO
4703 }
4704 if (value != NULL)
4705 xmlFree(value);
4706
4707 return(ret);
4708}
4709
4710/**
4711 * xmlSchemaValidateCheckNodeList
4712 * @nodelist: the list of nodes
4713 *
4714 * Check the node list is only made of text nodes and entities pointing
4715 * to text nodes
4716 *
4717 * Returns 1 if true, 0 if false and -1 in case of error
4718 */
4719static int
4720xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4721 while (nodelist != NULL) {
4722 if (nodelist->type == XML_ENTITY_REF_NODE) {
4723 TODO /* implement recursion in the entity content */
4724 }
4725 if ((nodelist->type != XML_TEXT_NODE) &&
4726 (nodelist->type != XML_COMMENT_NODE) &&
4727 (nodelist->type != XML_PI_NODE) &&
4728 (nodelist->type != XML_PI_NODE)) {
4729 return(0);
4730 }
4731 nodelist = nodelist->next;
4732 }
4733 return(1);
4734}
4735
4736/**
4737 * xmlSchemaSkipIgnored:
4738 * @ctxt: a schema validation context
4739 * @type: the current type context
4740 * @node: the top node.
4741 *
4742 * Skip ignorable nodes in that context
4743 *
4744 * Returns the new sibling
4745 * number otherwise and -1 in case of internal or API error.
4746 */
4747static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004748xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004749 xmlSchemaTypePtr type,
4750 xmlNodePtr node) {
4751 int mixed = 0;
4752 /*
4753 * TODO complete and handle entities
4754 */
4755 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4756 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4757 while ((node != NULL) &&
4758 ((node->type == XML_COMMENT_NODE) ||
4759 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4760 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4761 (node->type == XML_TEXT_NODE) &&
4762 (IS_BLANK_NODE(node)))))) {
4763 node = node->next;
4764 }
4765 return(node);
4766}
4767
4768/**
4769 * xmlSchemaValidateCallback:
4770 * @ctxt: a schema validation context
4771 * @name: the name of the element detected (might be NULL)
4772 * @type: the type
4773 *
4774 * A transition has been made in the automata associated to an element
4775 * content model
4776 */
4777static void
4778xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004779 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004780 xmlSchemaTypePtr type,
4781 xmlNodePtr node) {
4782 xmlSchemaTypePtr oldtype = ctxt->type;
4783 xmlNodePtr oldnode = ctxt->node;
4784#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004785 xmlGenericError(xmlGenericErrorContext,
4786 "xmlSchemaValidateCallback: %s, %s, %s\n",
4787 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004788#endif
4789 ctxt->type = type;
4790 ctxt->node = node;
4791 xmlSchemaValidateContent(ctxt, node);
4792 ctxt->type = oldtype;
4793 ctxt->node = oldnode;
4794}
4795
4796
4797#if 0
4798/**
4799 * xmlSchemaValidateSimpleRestrictionType:
4800 * @ctxt: a schema validation context
4801 * @node: the top node.
4802 *
4803 * Validate the content of a restriction type.
4804 *
4805 * Returns 0 if the element is schemas valid, a positive error code
4806 * number otherwise and -1 in case of internal or API error.
4807 */
4808static int
4809xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4810 xmlNodePtr node)
4811{
4812 xmlNodePtr child;
4813 xmlSchemaTypePtr type;
4814 int ret;
4815
4816 child = ctxt->node;
4817 type = ctxt->type;
4818
4819 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004820 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004821 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4822 if (ctxt->error != NULL)
4823 ctxt->error(ctxt->userData,
4824 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4825 node->name);
4826 return (-1);
4827 }
4828 /*
4829 * Only text and text based entities references shall be found there
4830 */
4831 ret = xmlSchemaValidateCheckNodeList(child);
4832 if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004833 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004834 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4835 if (ctxt->error != NULL)
4836 ctxt->error(ctxt->userData,
4837 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4838 node->name);
4839 return (-1);
4840 } else if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004841 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004842 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4843 if (ctxt->error != NULL)
4844 ctxt->error(ctxt->userData,
4845 "Element %s content is not a simple type\n",
4846 node->name);
4847 return (-1);
4848 }
4849 ctxt->type = type->subtypes;
4850 xmlSchemaValidateContent(ctxt, node);
4851 ctxt->type = type;
4852 return (ret);
4853}
4854#endif
4855
4856/**
4857 * xmlSchemaValidateSimpleType:
4858 * @ctxt: a schema validation context
4859 * @node: the top node.
4860 *
4861 * Validate the content of an simple type.
4862 *
4863 * Returns 0 if the element is schemas valid, a positive error code
4864 * number otherwise and -1 in case of internal or API error.
4865 */
4866static int
4867xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4868 xmlNodePtr child;
4869 xmlSchemaTypePtr type;
4870 xmlAttrPtr attr;
4871 int ret;
4872
4873 child = ctxt->node;
4874 type = ctxt->type;
4875
4876 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004877 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004878 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4879 if (ctxt->error != NULL)
4880 ctxt->error(ctxt->userData,
4881 "Internal error: xmlSchemaValidateSimpleType %s\n",
4882 node->name);
4883 return(-1);
4884 }
4885 /*
4886 * Only text and text based entities references shall be found there
4887 */
4888 ret = xmlSchemaValidateCheckNodeList(child);
4889 if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004890 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004891 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4892 if (ctxt->error != NULL)
4893 ctxt->error(ctxt->userData,
4894 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4895 node->name);
4896 return(-1);
4897 } else if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004898 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004899 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4900 if (ctxt->error != NULL)
4901 ctxt->error(ctxt->userData,
4902 "Element %s content is not a simple type\n",
4903 node->name);
4904 return(-1);
4905 }
4906 /*
4907 * Validation Rule: Element Locally Valid (Type): 3.1.1
4908 */
4909 attr = node->properties;
4910 while (attr != NULL) {
4911 if ((attr->ns == NULL) ||
4912 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4913 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4914 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4915 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4916 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4917 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004918 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004919 if (ctxt->error != NULL)
4920 ctxt->error(ctxt->userData,
4921 "Element %s: attribute %s should not be present\n",
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004922 node->name, attr->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004923 return(ctxt->err);
4924 }
4925 }
4926
4927 ctxt->type = type->subtypes;
4928 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4929 ctxt->type = type;
4930 return(ret);
4931}
4932
4933/**
4934 * xmlSchemaValidateElementType:
4935 * @ctxt: a schema validation context
4936 * @node: the top node.
4937 *
4938 * Validate the content of an element type.
4939 * Validation Rule: Element Locally Valid (Complex Type)
4940 *
4941 * Returns 0 if the element is schemas valid, a positive error code
4942 * number otherwise and -1 in case of internal or API error.
4943 */
4944static int
4945xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4946 xmlNodePtr child;
4947 xmlSchemaTypePtr type;
4948 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4949 xmlSchemaElementPtr decl;
4950 int ret, attrBase;
4951
4952 oldregexp = ctxt->regexp;
4953
4954 child = ctxt->node;
4955 type = ctxt->type;
4956
4957 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004958 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004959 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4960 if (ctxt->error != NULL)
4961 ctxt->error(ctxt->userData,
4962 "Internal error: xmlSchemaValidateElementType\n",
4963 node->name);
4964 return(-1);
4965 }
4966 if (child == NULL) {
4967 if (type->minOccurs > 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004968 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004969 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4970 if (ctxt->error != NULL)
4971 ctxt->error(ctxt->userData,
4972 "Element %s: missing child %s\n",
4973 node->name, type->name);
4974 }
4975 return(ctxt->err);
4976 }
4977
4978 /*
4979 * Verify the element matches
4980 */
4981 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004982 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004983 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4984 if (ctxt->error != NULL)
4985 ctxt->error(ctxt->userData,
4986 "Element %s: missing child %s found %s\n",
4987 node->name, type->name, child->name);
4988 return(ctxt->err);
4989 }
4990 /*
4991 * Verify the attributes
4992 */
4993 attrBase = ctxt->attrBase;
4994 ctxt->attrBase = ctxt->attrNr;
4995 xmlSchemaRegisterAttributes(ctxt, child->properties);
4996 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4997 /*
4998 * Verify the element content recursively
4999 */
5000 decl = (xmlSchemaElementPtr) type;
5001 oldregexp = ctxt->regexp;
5002 if (decl->contModel != NULL) {
5003 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5004 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5005 ctxt);
5006#ifdef DEBUG_AUTOMATA
5007 xmlGenericError(xmlGenericErrorContext,
5008 "====> %s\n", node->name);
5009#endif
5010 }
5011 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
5012 type->subtypes);
5013
5014 if (decl->contModel != NULL) {
5015 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
5016#ifdef DEBUG_AUTOMATA
5017 xmlGenericError(xmlGenericErrorContext,
5018 "====> %s : %d\n", node->name, ret);
5019#endif
5020 if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005021 ctxt->nberrors++;
Daniel Veillard8651f532002-04-17 09:06:27 +00005022 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00005023 if (ctxt->error != NULL)
5024 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5025 node->name);
5026 } else if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005027 ctxt->nberrors++;
Daniel Veillard8651f532002-04-17 09:06:27 +00005028 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00005029 if (ctxt->error != NULL)
5030 ctxt->error(ctxt->userData, "Element %s content check failure\n",
5031 node->name);
5032#ifdef DEBUG_CONTENT
5033 } else {
5034 xmlGenericError(xmlGenericErrorContext,
5035 "Element %s content check succeeded\n", node->name);
5036
5037#endif
5038 }
5039 xmlRegFreeExecCtxt(ctxt->regexp);
5040 }
5041 /*
5042 * Verify that all attributes were Schemas-validated
5043 */
5044 xmlSchemaCheckAttributes(ctxt, node);
5045 ctxt->attrNr = ctxt->attrBase;
5046 ctxt->attrBase = attrBase;
5047
5048 ctxt->regexp = oldregexp;
5049
5050 ctxt->node = child;
5051 ctxt->type = type;
5052 return(ctxt->err);
5053}
5054
5055/**
5056 * xmlSchemaValidateBasicType:
5057 * @ctxt: a schema validation context
5058 * @node: the top node.
5059 *
5060 * Validate the content of an element expected to be a basic type type
5061 *
5062 * Returns 0 if the element is schemas valid, a positive error code
5063 * number otherwise and -1 in case of internal or API error.
5064 */
5065static int
5066xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5067 int ret;
5068 xmlNodePtr child, cur;
5069 xmlSchemaTypePtr type;
5070 xmlChar *value; /* lexical representation */
5071
5072 child = ctxt->node;
5073 type = ctxt->type;
5074
5075 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005076 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005077 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5078 if (ctxt->error != NULL)
5079 ctxt->error(ctxt->userData,
5080 "Internal error: xmlSchemaValidateBasicType\n",
5081 node->name);
5082 return(-1);
5083 }
5084 /*
5085 * First check the content model of the node.
5086 */
5087 cur = child;
5088 while (cur != NULL) {
5089 switch (cur->type) {
5090 case XML_TEXT_NODE:
5091 case XML_CDATA_SECTION_NODE:
5092 case XML_PI_NODE:
5093 case XML_COMMENT_NODE:
5094 case XML_XINCLUDE_START:
5095 case XML_XINCLUDE_END:
5096 break;
5097 case XML_ENTITY_REF_NODE:
5098 case XML_ENTITY_NODE:
5099 TODO
5100 break;
5101 case XML_ELEMENT_NODE:
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005102 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005103 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
5104 if (ctxt->error != NULL)
5105 ctxt->error(ctxt->userData,
5106 "Element %s: child %s should not be present\n",
5107 node->name, cur->name);
5108 return(ctxt->err);
5109 case XML_ATTRIBUTE_NODE:
5110 case XML_DOCUMENT_NODE:
5111 case XML_DOCUMENT_TYPE_NODE:
5112 case XML_DOCUMENT_FRAG_NODE:
5113 case XML_NOTATION_NODE:
5114 case XML_HTML_DOCUMENT_NODE:
5115 case XML_DTD_NODE:
5116 case XML_ELEMENT_DECL:
5117 case XML_ATTRIBUTE_DECL:
5118 case XML_ENTITY_DECL:
5119 case XML_NAMESPACE_DECL:
5120#ifdef LIBXML_DOCB_ENABLED
5121 case XML_DOCB_DOCUMENT_NODE:
5122#endif
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005123 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005124 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
5125 if (ctxt->error != NULL)
5126 ctxt->error(ctxt->userData,
5127 "Element %s: node type %d unexpected here\n",
5128 node->name, cur->type);
5129 return(ctxt->err);
5130 }
5131 cur = cur->next;
5132 }
5133 if (child == NULL)
5134 value = NULL;
5135 else
5136 value = xmlNodeGetContent(child->parent);
5137
5138 if (ctxt->value != NULL) {
5139 xmlSchemaFreeValue(ctxt->value);
5140 ctxt->value = NULL;
5141 }
5142 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5143 if (value != NULL)
5144 xmlFree(value);
5145 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005146 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005147 if (ctxt->error != NULL)
5148 ctxt->error(ctxt->userData,
5149 "Element %s: failed to validate basic type %s\n",
5150 node->name, type->name);
Daniel Veillard91a13252003-03-27 23:44:43 +00005151 ctxt->err = XML_SCHEMAS_ERR_VALUE;
Daniel Veillard4255d502002-04-16 15:50:10 +00005152 }
5153 return(ret);
5154}
5155
5156/**
5157 * xmlSchemaValidateComplexType:
5158 * @ctxt: a schema validation context
5159 * @node: the top node.
5160 *
5161 * Validate the content of an element expected to be a complex type type
5162 * xmlschema-1.html#cvc-complex-type
5163 * Validation Rule: Element Locally Valid (Complex Type)
5164 *
5165 * Returns 0 if the element is schemas valid, a positive error code
5166 * number otherwise and -1 in case of internal or API error.
5167 */
5168static int
5169xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5170 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005171 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005172 int ret;
5173
5174 child = ctxt->node;
5175 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005176 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005177
Daniel Veillard4255d502002-04-16 15:50:10 +00005178 switch (type->contentType) {
5179 case XML_SCHEMA_CONTENT_EMPTY:
5180 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005181 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005182 if (ctxt->error != NULL)
5183 ctxt->error(ctxt->userData,
5184 "Element %s is supposed to be empty\n",
5185 node->name);
5186 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00005187 if (type->attributes != NULL) {
5188 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5189 }
5190 subtype = type->subtypes;
5191 while (subtype != NULL) {
5192 ctxt->type = subtype;
5193 xmlSchemaValidateComplexType(ctxt, node);
5194 subtype = subtype->next;
5195 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005196 break;
5197 case XML_SCHEMA_CONTENT_ELEMENTS:
5198 case XML_SCHEMA_CONTENT_MIXED:
5199 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5200 /*
5201 * Skip ignorable nodes in that context
5202 */
5203 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005204 while (child != NULL) {
5205 if (child->type == XML_ELEMENT_NODE) {
5206 ret = xmlRegExecPushString(ctxt->regexp,
5207 child->name, child);
5208#ifdef DEBUG_AUTOMATA
5209 if (ret < 0)
5210 xmlGenericError(xmlGenericErrorContext,
5211 " --> %s Error\n", child->name);
5212 else
5213 xmlGenericError(xmlGenericErrorContext,
5214 " --> %s\n", child->name);
5215#endif
5216 }
5217 child = child->next;
5218 /*
5219 * Skip ignorable nodes in that context
5220 */
5221 child = xmlSchemaSkipIgnored(ctxt, type, child);
5222 }
5223 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005224 case XML_SCHEMA_CONTENT_BASIC: {
5225 if (type->subtypes != NULL) {
5226 ctxt->type = type->subtypes;
5227 xmlSchemaValidateComplexType(ctxt, node);
5228 }
5229 if (type->baseType != NULL) {
5230 ctxt->type = type->baseType;
5231 xmlSchemaValidateBasicType(ctxt, node);
5232 }
5233 if (type->attributes != NULL) {
5234 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5235 }
5236 ctxt->type = type;
5237 break;
5238 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005239 default:
5240 TODO
5241 xmlGenericError(xmlGenericErrorContext,
5242 "unimplemented content type %d\n",
5243 type->contentType);
5244 }
5245 return(ctxt->err);
5246}
5247
5248/**
5249 * xmlSchemaValidateContent:
5250 * @ctxt: a schema validation context
5251 * @elem: an element
5252 * @type: the type declaration
5253 *
5254 * Validate the content of an element against the type.
5255 *
5256 * Returns 0 if the element is schemas valid, a positive error code
5257 * number otherwise and -1 in case of internal or API error.
5258 */
5259static int
5260xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5261 xmlNodePtr child;
5262 xmlSchemaTypePtr type;
5263
5264 child = ctxt->node;
5265 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005266 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005267
Daniel Veillarde19fc232002-04-22 16:01:24 +00005268 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005269 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00005270
Daniel Veillard4255d502002-04-16 15:50:10 +00005271 switch (type->type) {
5272 case XML_SCHEMA_TYPE_ANY:
5273 /* Any type will do it, fine */
5274 TODO /* handle recursivity */
5275 break;
5276 case XML_SCHEMA_TYPE_COMPLEX:
5277 xmlSchemaValidateComplexType(ctxt, node);
5278 break;
5279 case XML_SCHEMA_TYPE_ELEMENT: {
5280 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
5281 /*
5282 * Handle element reference here
5283 */
5284 if (decl->ref != NULL) {
5285 if (decl->refDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005286 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005287 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5288 if (ctxt->error != NULL)
5289 ctxt->error(ctxt->userData,
5290 "Internal error: element reference %s not resolved\n",
5291 decl->ref);
5292 return(-1);
5293 }
5294 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
5295 decl = decl->refDecl;
5296 }
5297 xmlSchemaValidateElementType(ctxt, node);
5298 ctxt->type = type;
5299 break;
5300 }
5301 case XML_SCHEMA_TYPE_BASIC:
5302 xmlSchemaValidateBasicType(ctxt, node);
5303 break;
5304 case XML_SCHEMA_TYPE_FACET:
5305 TODO
5306 break;
5307 case XML_SCHEMA_TYPE_SIMPLE:
5308 xmlSchemaValidateSimpleType(ctxt, node);
5309 break;
5310 case XML_SCHEMA_TYPE_SEQUENCE:
5311 TODO
5312 break;
5313 case XML_SCHEMA_TYPE_CHOICE:
5314 TODO
5315 break;
5316 case XML_SCHEMA_TYPE_ALL:
5317 TODO
5318 break;
5319 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5320 TODO
5321 break;
5322 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5323 TODO
5324 break;
5325 case XML_SCHEMA_TYPE_UR:
5326 TODO
5327 break;
5328 case XML_SCHEMA_TYPE_RESTRICTION:
5329 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5330 TODO
5331 break;
5332 case XML_SCHEMA_TYPE_EXTENSION:
5333 TODO
5334 break;
5335 case XML_SCHEMA_TYPE_ATTRIBUTE:
5336 TODO
5337 break;
5338 case XML_SCHEMA_TYPE_GROUP:
5339 TODO
5340 break;
5341 case XML_SCHEMA_TYPE_NOTATION:
5342 TODO
5343 break;
5344 case XML_SCHEMA_TYPE_LIST:
5345 TODO
5346 break;
5347 case XML_SCHEMA_TYPE_UNION:
5348 TODO
5349 break;
5350 case XML_SCHEMA_FACET_MININCLUSIVE:
5351 TODO
5352 break;
5353 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5354 TODO
5355 break;
5356 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5357 TODO
5358 break;
5359 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5360 TODO
5361 break;
5362 case XML_SCHEMA_FACET_TOTALDIGITS:
5363 TODO
5364 break;
5365 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5366 TODO
5367 break;
5368 case XML_SCHEMA_FACET_PATTERN:
5369 TODO
5370 break;
5371 case XML_SCHEMA_FACET_ENUMERATION:
5372 TODO
5373 break;
5374 case XML_SCHEMA_FACET_WHITESPACE:
5375 TODO
5376 break;
5377 case XML_SCHEMA_FACET_LENGTH:
5378 TODO
5379 break;
5380 case XML_SCHEMA_FACET_MAXLENGTH:
5381 TODO
5382 break;
5383 case XML_SCHEMA_FACET_MINLENGTH:
5384 TODO
5385 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00005386 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5387 TODO
5388 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005389 }
5390 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5391
5392 if (ctxt->node == NULL)
5393 return(ctxt->err);
5394 ctxt->node = ctxt->node->next;
5395 ctxt->type = type->next;
5396 return(ctxt->err);
5397}
5398
5399/**
5400 * xmlSchemaValidateType:
5401 * @ctxt: a schema validation context
5402 * @elem: an element
5403 * @type: the list of type declarations
5404 *
5405 * Validate the content of an element against the types.
5406 *
5407 * Returns 0 if the element is schemas valid, a positive error code
5408 * number otherwise and -1 in case of internal or API error.
5409 */
5410static int
5411xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5412 xmlSchemaElementPtr elemDecl,
5413 xmlSchemaTypePtr type) {
5414 xmlChar *nil;
5415
Daniel Veillard2db8c122003-07-08 12:16:59 +00005416 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillard4255d502002-04-16 15:50:10 +00005417 return(0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00005418
Daniel Veillard4255d502002-04-16 15:50:10 +00005419 /*
5420 * 3.3.4 : 2
5421 */
5422 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005423 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005424 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
5425 if (ctxt->error != NULL)
5426 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
5427 return(ctxt->err);
5428 }
5429 /*
5430 * 3.3.4: 3
5431 */
5432 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5433 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
5434 /* 3.3.4: 3.2 */
5435 if (xmlStrEqual(nil, BAD_CAST "true")) {
5436 if (elem->children != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005437 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005438 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
5439 if (ctxt->error != NULL)
5440 ctxt->error(ctxt->userData, "Element %s is not empty\n",
5441 elem->name);
5442 return(ctxt->err);
5443 }
5444 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5445 (elemDecl->value != NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005446 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005447 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
5448 if (ctxt->error != NULL)
5449 ctxt->error(ctxt->userData,
5450 "Empty element %s cannot get a fixed value\n",
5451 elem->name);
5452 return(ctxt->err);
5453 }
5454 }
5455 } else {
5456 /* 3.3.4: 3.1 */
5457 if (nil != NULL) {
5458 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005459 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005460 if (ctxt->error != NULL)
5461 ctxt->error(ctxt->userData,
5462 "Element %s with xs:nil but not nillable\n",
5463 elem->name);
5464 xmlFree(nil);
5465 return(ctxt->err);
5466 }
5467 }
5468
5469 /* TODO 3.3.4: 4 if the element carries xs:type*/
5470
5471 ctxt->type = elemDecl->subtypes;
5472 ctxt->node = elem->children;
5473 xmlSchemaValidateContent(ctxt, elem);
5474 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5475
5476 return(ctxt->err);
5477}
5478
5479
5480/**
5481 * xmlSchemaValidateAttributes:
5482 * @ctxt: a schema validation context
5483 * @elem: an element
5484 * @attributes: the list of attribute declarations
5485 *
5486 * Validate the attributes of an element.
5487 *
5488 * Returns 0 if the element is schemas valid, a positive error code
5489 * number otherwise and -1 in case of internal or API error.
5490 */
5491static int
5492xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5493 xmlSchemaAttributePtr attributes) {
5494 int i, ret;
5495 xmlAttrPtr attr;
5496 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005497 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005498
5499 if (attributes == NULL)
5500 return(0);
5501 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005502 /*
5503 * Handle attribute groups
5504 */
5505 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5506 group = (xmlSchemaAttributeGroupPtr) attributes;
5507 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5508 attributes = group->next;
5509 continue;
5510 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005511 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5512 attr = ctxt->attr[i].attr;
5513 if (attr == NULL)
5514 continue;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005515 if (attributes->ref != NULL) {
5516 if (!xmlStrEqual(attr->name, attributes->ref))
5517 continue;
5518 if (attr->ns != NULL) {
5519 if ((attributes->refNs == NULL) ||
5520 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
5521 continue;
5522 } else if (attributes->refNs != NULL) {
5523 continue;
5524 }
5525 } else {
5526 if (!xmlStrEqual(attr->name, attributes->name))
5527 continue;
5528 /*
5529 * TODO: handle the mess about namespaces here.
5530 */
5531 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5532 TODO
5533 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005534 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005535 ctxt->cur = (xmlNodePtr) attributes;
Daniel Veillard4255d502002-04-16 15:50:10 +00005536 if (attributes->subtypes == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005537 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005538 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5539 if (ctxt->error != NULL)
5540 ctxt->error(ctxt->userData,
5541 "Internal error: attribute %s type not resolved\n",
5542 attr->name);
5543 continue;
5544 }
5545 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5546 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005547 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005548 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005549 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005550 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5551 if (ctxt->error != NULL)
5552 ctxt->error(ctxt->userData,
5553 "attribute %s on %s does not match type\n",
5554 attr->name, elem->name);
5555 } else {
5556 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5557 }
5558 if (value != NULL) {
5559 xmlFree(value);
5560 }
5561 }
5562 attributes = attributes->next;
5563 }
5564 return(ctxt->err);
5565}
5566
5567/**
5568 * xmlSchemaValidateElement:
5569 * @ctxt: a schema validation context
5570 * @elem: an element
5571 *
5572 * Validate an element in a tree
5573 *
5574 * Returns 0 if the element is schemas valid, a positive error code
5575 * number otherwise and -1 in case of internal or API error.
5576 */
5577static int
5578xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5579 xmlSchemaElementPtr elemDecl;
5580 int ret, attrBase;
5581
5582 if (elem->ns != NULL)
5583 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5584 elem->name, elem->ns->href, NULL);
5585 else
5586 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5587 elem->name, NULL, NULL);
5588 /*
5589 * 3.3.4 : 1
5590 */
5591 if (elemDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005592 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005593 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5594 if (ctxt->error != NULL)
5595 ctxt->error(ctxt->userData, "Element %s not declared\n",
5596 elem->name);
5597 return(ctxt->err);
5598 }
5599 if (elemDecl->subtypes == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005600 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005601 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5602 if (ctxt->error != NULL)
5603 ctxt->error(ctxt->userData, "Element %s has no type\n",
5604 elem->name);
5605 return(ctxt->err);
5606 }
5607 /*
5608 * Verify the attributes
5609 */
5610 attrBase = ctxt->attrBase;
5611 ctxt->attrBase = ctxt->attrNr;
5612 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5613 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5614 /*
5615 * Verify the element content recursively
5616 */
5617 if (elemDecl->contModel != NULL) {
5618 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5619 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5620 ctxt);
5621#ifdef DEBUG_AUTOMATA
5622 xmlGenericError(xmlGenericErrorContext,
5623 "====> %s\n", elem->name);
5624#endif
5625 }
5626 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005627 if (elemDecl->contModel != NULL) {
5628 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005629#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005630 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005631 "====> %s : %d\n", elem->name, ret);
5632#endif
5633 if (ret == 0) {
5634 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005635 ctxt->nberrors++;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005636 if (ctxt->error != NULL)
5637 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5638 elem->name);
5639 } else if (ret < 0) {
5640 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005641 ctxt->nberrors++;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005642 if (ctxt->error != NULL)
5643 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5644 elem->name);
5645#ifdef DEBUG_CONTENT
5646 } else {
5647 xmlGenericError(xmlGenericErrorContext,
5648 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005649
5650#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005651 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005652 xmlRegFreeExecCtxt(ctxt->regexp);
5653 }
5654 /*
5655 * Verify that all attributes were Schemas-validated
5656 */
5657 xmlSchemaCheckAttributes(ctxt, elem);
5658 ctxt->attrNr = ctxt->attrBase;
5659 ctxt->attrBase = attrBase;
5660
5661 return(ctxt->err);
5662}
5663
5664/**
5665 * xmlSchemaValidateDocument:
5666 * @ctxt: a schema validation context
5667 * @doc: a parsed document tree
5668 *
5669 * Validate a document tree in memory.
5670 *
5671 * Returns 0 if the document is schemas valid, a positive error code
5672 * number otherwise and -1 in case of internal or API error.
5673 */
5674static int
5675xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5676 xmlNodePtr root;
5677 xmlSchemaElementPtr elemDecl;
5678
5679 root = xmlDocGetRootElement(doc);
5680 if (root == NULL) {
5681 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005682 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005683 if (ctxt->error != NULL)
5684 ctxt->error(ctxt->userData, "document has no root\n");
5685 return(ctxt->err);
5686 }
5687 if (root->ns != NULL)
5688 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5689 root->name, root->ns->href, NULL);
5690 else
5691 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5692 root->name, NULL, NULL);
5693 if (elemDecl == NULL) {
5694 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005695 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005696 if (ctxt->error != NULL)
5697 ctxt->error(ctxt->userData, "Element %s not declared\n",
5698 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005699 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005700 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005701 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005702 if (ctxt->error != NULL)
5703 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5704 root->name);
5705 }
5706 /*
5707 * Okay, start the recursive validation
5708 */
5709 xmlSchemaValidateElement(ctxt, root);
5710
5711 return(ctxt->err);
5712}
5713
5714/************************************************************************
5715 * *
5716 * SAX Validation code *
5717 * *
5718 ************************************************************************/
5719
5720/************************************************************************
5721 * *
5722 * Validation interfaces *
5723 * *
5724 ************************************************************************/
5725
5726/**
5727 * xmlSchemaNewValidCtxt:
5728 * @schema: a precompiled XML Schemas
5729 *
5730 * Create an XML Schemas validation context based on the given schema
5731 *
5732 * Returns the validation context or NULL in case of error
5733 */
5734xmlSchemaValidCtxtPtr
5735xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5736 xmlSchemaValidCtxtPtr ret;
5737
5738 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5739 if (ret == NULL) {
5740 xmlGenericError(xmlGenericErrorContext,
5741 "Failed to allocate new schama validation context\n");
5742 return (NULL);
5743 }
5744 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5745 ret->schema = schema;
5746 ret->attrNr = 0;
5747 ret->attrMax = 10;
5748 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5749 sizeof(xmlSchemaAttrState));
5750 if (ret->attr == NULL) {
5751 free(ret);
5752 return(NULL);
5753 }
5754 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5755 return (ret);
5756}
5757
5758/**
5759 * xmlSchemaFreeValidCtxt:
5760 * @ctxt: the schema validation context
5761 *
5762 * Free the resources associated to the schema validation context
5763 */
5764void
5765xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5766 if (ctxt == NULL)
5767 return;
5768 if (ctxt->attr != NULL)
5769 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005770 if (ctxt->value != NULL)
5771 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005772 xmlFree(ctxt);
5773}
5774
5775/**
5776 * xmlSchemaSetValidErrors:
5777 * @ctxt: a schema validation context
5778 * @err: the error function
5779 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00005780 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00005781 *
5782 * Set the error and warning callback informations
5783 */
5784void
5785xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5786 xmlSchemaValidityErrorFunc err,
5787 xmlSchemaValidityWarningFunc warn, void *ctx) {
5788 if (ctxt == NULL)
5789 return;
5790 ctxt->error = err;
5791 ctxt->warning = warn;
5792 ctxt->userData = ctx;
5793}
5794
5795/**
5796 * xmlSchemaValidateDoc:
5797 * @ctxt: a schema validation context
5798 * @doc: a parsed document tree
5799 *
5800 * Validate a document tree in memory.
5801 *
5802 * Returns 0 if the document is schemas valid, a positive error code
5803 * number otherwise and -1 in case of internal or API error.
5804 */
5805int
5806xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5807 int ret;
5808
5809 if ((ctxt == NULL) || (doc == NULL))
5810 return(-1);
5811
5812 ctxt->doc = doc;
5813 ret = xmlSchemaValidateDocument(ctxt, doc);
5814 return(ret);
5815}
5816
5817/**
5818 * xmlSchemaValidateStream:
5819 * @ctxt: a schema validation context
5820 * @input: the input to use for reading the data
5821 * @enc: an optional encoding information
5822 * @sax: a SAX handler for the resulting events
5823 * @user_data: the context to provide to the SAX handler.
5824 *
5825 * Validate a document tree in memory.
5826 *
5827 * Returns 0 if the document is schemas valid, a positive error code
5828 * number otherwise and -1 in case of internal or API error.
5829 */
5830int
5831xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5832 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5833 xmlSAXHandlerPtr sax, void *user_data) {
5834 if ((ctxt == NULL) || (input == NULL))
5835 return(-1);
5836 ctxt->input = input;
5837 ctxt->enc = enc;
5838 ctxt->sax = sax;
5839 ctxt->user_data = user_data;
5840 TODO
5841 return(0);
5842}
5843
5844#endif /* LIBXML_SCHEMAS_ENABLED */