blob: 29128615623a25763f1665fd08f1c0c14efdd21f [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) {
Daniel Veillard34ba3872003-07-15 13:34:05 +0000462 line = (long) node->content;
Daniel Veillard4255d502002-04-16 15:50:10 +0000463 } else if ((node->prev != NULL) &&
464 (node->prev->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +0000465 line = (long) node->prev->content;
Daniel Veillard4255d502002-04-16 15:50:10 +0000466 } else if ((node->parent != NULL) &&
467 (node->parent->type == XML_ELEMENT_NODE)) {
Daniel Veillard34ba3872003-07-15 13:34:05 +0000468 line = (long) node->parent->content;
Daniel Veillard4255d502002-04-16 15:50:10 +0000469 }
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
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000515#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4255d502002-04-16 15:50:10 +0000516/**
517 * xmlSchemaElementDump:
518 * @elem: an element
519 * @output: the file output
520 *
521 * Dump the element
522 */
523static void
524xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +0000525 const xmlChar *name ATTRIBUTE_UNUSED,
526 const xmlChar *context ATTRIBUTE_UNUSED,
527 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +0000528{
529 if (elem == NULL)
530 return;
531
532 fprintf(output, "Element ");
533 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
534 fprintf(output, "toplevel ");
535 fprintf(output, ": %s ", elem->name);
536 if (namespace != NULL)
537 fprintf(output, "namespace '%s' ", namespace);
538
539 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
540 fprintf(output, "nillable ");
541 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
542 fprintf(output, "global ");
543 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
544 fprintf(output, "default ");
545 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
546 fprintf(output, "fixed ");
547 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
548 fprintf(output, "abstract ");
549 if (elem->flags & XML_SCHEMAS_ELEM_REF)
550 fprintf(output, "ref '%s' ", elem->ref);
551 if (elem->id != NULL)
552 fprintf(output, "id '%s' ", elem->id);
553 fprintf(output, "\n");
554 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
555 fprintf(output, " ");
556 if (elem->minOccurs != 1)
557 fprintf(output, "min: %d ", elem->minOccurs);
558 if (elem->maxOccurs >= UNBOUNDED)
559 fprintf(output, "max: unbounded\n");
560 else if (elem->maxOccurs != 1)
561 fprintf(output, "max: %d\n", elem->maxOccurs);
562 else
563 fprintf(output, "\n");
564 }
565 if (elem->namedType != NULL) {
566 fprintf(output, " type: %s", elem->namedType);
567 if (elem->namedTypeNs != NULL)
568 fprintf(output, " ns %s\n", elem->namedTypeNs);
569 else
570 fprintf(output, "\n");
571 }
572 if (elem->substGroup != NULL) {
573 fprintf(output, " substitutionGroup: %s", elem->substGroup);
574 if (elem->substGroupNs != NULL)
575 fprintf(output, " ns %s\n", elem->substGroupNs);
576 else
577 fprintf(output, "\n");
578 }
579 if (elem->value != NULL)
580 fprintf(output, " default: %s", elem->value);
581}
582
583/**
584 * xmlSchemaAnnotDump:
585 * @output: the file output
586 * @annot: a annotation
587 *
588 * Dump the annotation
589 */
590static void
591xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
592{
593 xmlChar *content;
594
595 if (annot == NULL)
596 return;
597
598 content = xmlNodeGetContent(annot->content);
599 if (content != NULL) {
600 fprintf(output, " Annot: %s\n", content);
601 xmlFree(content);
602 } else
603 fprintf(output, " Annot: empty\n");
604}
605
606/**
607 * xmlSchemaTypeDump:
608 * @output: the file output
609 * @type: a type structure
610 *
611 * Dump a SchemaType structure
612 */
613static void
614xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
615{
616 if (type == NULL) {
617 fprintf(output, "Type: NULL\n");
618 return;
619 }
620 fprintf(output, "Type: ");
621 if (type->name != NULL)
622 fprintf(output, "%s, ", type->name);
623 else
624 fprintf(output, "no name");
625 switch (type->type) {
626 case XML_SCHEMA_TYPE_BASIC:
627 fprintf(output, "basic ");
628 break;
629 case XML_SCHEMA_TYPE_SIMPLE:
630 fprintf(output, "simple ");
631 break;
632 case XML_SCHEMA_TYPE_COMPLEX:
633 fprintf(output, "complex ");
634 break;
635 case XML_SCHEMA_TYPE_SEQUENCE:
636 fprintf(output, "sequence ");
637 break;
638 case XML_SCHEMA_TYPE_CHOICE:
639 fprintf(output, "choice ");
640 break;
641 case XML_SCHEMA_TYPE_ALL:
642 fprintf(output, "all ");
643 break;
644 case XML_SCHEMA_TYPE_UR:
645 fprintf(output, "ur ");
646 break;
647 case XML_SCHEMA_TYPE_RESTRICTION:
648 fprintf(output, "restriction ");
649 break;
650 case XML_SCHEMA_TYPE_EXTENSION:
651 fprintf(output, "extension ");
652 break;
653 default:
654 fprintf(output, "unknowntype%d ", type->type);
655 break;
656 }
657 if (type->base != NULL) {
658 fprintf(output, "base %s, ", type->base);
659 }
660 switch (type->contentType) {
661 case XML_SCHEMA_CONTENT_UNKNOWN:
662 fprintf(output, "unknown ");
663 break;
664 case XML_SCHEMA_CONTENT_EMPTY:
665 fprintf(output, "empty ");
666 break;
667 case XML_SCHEMA_CONTENT_ELEMENTS:
668 fprintf(output, "element ");
669 break;
670 case XML_SCHEMA_CONTENT_MIXED:
671 fprintf(output, "mixed ");
672 break;
673 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
674 fprintf(output, "mixed_or_elems ");
675 break;
676 case XML_SCHEMA_CONTENT_BASIC:
677 fprintf(output, "basic ");
678 break;
679 case XML_SCHEMA_CONTENT_SIMPLE:
680 fprintf(output, "simple ");
681 break;
Daniel Veillard88c58912002-04-23 07:12:20 +0000682 case XML_SCHEMA_CONTENT_ANY:
683 fprintf(output, "any ");
684 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000685 }
686 fprintf(output, "\n");
687 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
688 fprintf(output, " ");
689 if (type->minOccurs != 1)
690 fprintf(output, "min: %d ", type->minOccurs);
691 if (type->maxOccurs >= UNBOUNDED)
692 fprintf(output, "max: unbounded\n");
693 else if (type->maxOccurs != 1)
694 fprintf(output, "max: %d\n", type->maxOccurs);
695 else
696 fprintf(output, "\n");
697 }
698 if (type->annot != NULL)
699 xmlSchemaAnnotDump(output, type->annot);
700 if (type->subtypes != NULL) {
701 xmlSchemaTypePtr sub = type->subtypes;
702
703 fprintf(output, " subtypes: ");
704 while (sub != NULL) {
705 fprintf(output, "%s ", sub->name);
706 sub = sub->next;
707 }
708 fprintf(output, "\n");
709 }
710
711}
712
713/**
714 * xmlSchemaDump:
715 * @output: the file output
716 * @schema: a schema structure
717 *
718 * Dump a Schema structure.
719 */
720void
721xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
722{
723 if (schema == NULL) {
724 fprintf(output, "Schemas: NULL\n");
725 return;
726 }
727 fprintf(output, "Schemas: ");
728 if (schema->name != NULL)
729 fprintf(output, "%s, ", schema->name);
730 else
731 fprintf(output, "no name, ");
732 if (schema->targetNamespace != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000733 fprintf(output, "%s", (const char *) schema->targetNamespace);
Daniel Veillard4255d502002-04-16 15:50:10 +0000734 else
735 fprintf(output, "no target namespace");
736 fprintf(output, "\n");
737 if (schema->annot != NULL)
738 xmlSchemaAnnotDump(output, schema->annot);
739
740 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
741 output);
742 xmlHashScanFull(schema->elemDecl,
743 (xmlHashScannerFull) xmlSchemaElementDump, output);
744}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000745#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard4255d502002-04-16 15:50:10 +0000746
747/************************************************************************
748 * *
749 * Parsing functions *
750 * *
751 ************************************************************************/
752
753/**
754 * xmlSchemaGetType:
755 * @schema: the schemas context
756 * @name: the type name
757 * @ns: the type namespace
758 *
759 * Lookup a type in the schemas or the predefined types
760 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000761 * Returns the group definition or NULL if not found.
Daniel Veillard4255d502002-04-16 15:50:10 +0000762 */
763static xmlSchemaTypePtr
764xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
765 const xmlChar * namespace) {
766 xmlSchemaTypePtr ret;
767
768 if (name == NULL)
769 return(NULL);
770 if (schema != NULL) {
771 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
772 if (ret != NULL)
773 return(ret);
774 }
775 ret = xmlSchemaGetPredefinedType(name, namespace);
776#ifdef DEBUG
777 if (ret == NULL) {
778 if (namespace == NULL)
779 fprintf(stderr, "Unable to lookup type %s", name);
780 else
781 fprintf(stderr, "Unable to lookup type %s:%s", name, namespace);
782 }
783#endif
784 return(ret);
785}
786
787/************************************************************************
788 * *
789 * Parsing functions *
790 * *
791 ************************************************************************/
792
793#define IS_BLANK_NODE(n) \
794 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
795
796/**
797 * xmlSchemaIsBlank:
798 * @str: a string
799 *
800 * Check if a string is ignorable
801 *
802 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
803 */
804static int
805xmlSchemaIsBlank(xmlChar *str) {
806 if (str == NULL)
807 return(1);
808 while (*str != 0) {
809 if (!(IS_BLANK(*str))) return(0);
810 str++;
811 }
812 return(1);
813}
814
815/**
816 * xmlSchemaAddNotation:
817 * @ctxt: a schema validation context
818 * @schema: the schema being built
819 * @name: the item name
820 *
821 * Add an XML schema Attrribute declaration
822 * *WARNING* this interface is highly subject to change
823 *
824 * Returns the new struture or NULL in case of error
825 */
826static xmlSchemaNotationPtr
827xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
828 const xmlChar * name)
829{
830 xmlSchemaNotationPtr ret = NULL;
831 int val;
832
833 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
834 return (NULL);
835
836 if (schema->notaDecl == NULL)
837 schema->notaDecl = xmlHashCreate(10);
838 if (schema->notaDecl == NULL)
839 return (NULL);
840
841 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
842 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000843 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000844 if ((ctxt != NULL) && (ctxt->error != NULL))
845 ctxt->error(ctxt->userData, "Out of memory\n");
846 return (NULL);
847 }
848 memset(ret, 0, sizeof(xmlSchemaNotation));
849 ret->name = xmlStrdup(name);
850 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
851 ret);
852 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000853 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000854 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000855 ctxt->error(ctxt->userData, "Notation %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000856 name);
857 xmlFree((char *) ret->name);
858 xmlFree(ret);
859 return (NULL);
860 }
861 return (ret);
862}
863
864
865/**
866 * xmlSchemaAddAttribute:
867 * @ctxt: a schema validation context
868 * @schema: the schema being built
869 * @name: the item name
870 * @container: the container's name
871 *
872 * Add an XML schema Attrribute declaration
873 * *WARNING* this interface is highly subject to change
874 *
875 * Returns the new struture or NULL in case of error
876 */
877static xmlSchemaAttributePtr
878xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
879 const xmlChar * name)
880{
881 xmlSchemaAttributePtr ret = NULL;
882 int val;
883
884 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
885 return (NULL);
886
887 if (schema->attrDecl == NULL)
888 schema->attrDecl = xmlHashCreate(10);
889 if (schema->attrDecl == NULL)
890 return (NULL);
891
892 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
893 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000894 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000895 if ((ctxt != NULL) && (ctxt->error != NULL))
896 ctxt->error(ctxt->userData, "Out of memory\n");
897 return (NULL);
898 }
899 memset(ret, 0, sizeof(xmlSchemaAttribute));
900 ret->name = xmlStrdup(name);
901 val = xmlHashAddEntry3(schema->attrDecl, name,
902 schema->targetNamespace, ctxt->container, ret);
903 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000904 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000905 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000906 ctxt->error(ctxt->userData, "Attribute %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000907 name);
908 xmlFree((char *) ret->name);
909 xmlFree(ret);
910 return (NULL);
911 }
912 return (ret);
913}
914
915/**
916 * xmlSchemaAddAttributeGroup:
917 * @ctxt: a schema validation context
918 * @schema: the schema being built
919 * @name: the item name
920 *
921 * Add an XML schema Attrribute Group declaration
922 *
923 * Returns the new struture or NULL in case of error
924 */
925static xmlSchemaAttributeGroupPtr
926xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
927 const xmlChar * name)
928{
929 xmlSchemaAttributeGroupPtr ret = NULL;
930 int val;
931
932 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
933 return (NULL);
934
935 if (schema->attrgrpDecl == NULL)
936 schema->attrgrpDecl = xmlHashCreate(10);
937 if (schema->attrgrpDecl == NULL)
938 return (NULL);
939
940 ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup));
941 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000942 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000943 if ((ctxt != NULL) && (ctxt->error != NULL))
944 ctxt->error(ctxt->userData, "Out of memory\n");
945 return (NULL);
946 }
947 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
948 ret->name = xmlStrdup(name);
949 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
950 schema->targetNamespace, ctxt->container, ret);
951 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000952 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000953 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000954 ctxt->error(ctxt->userData, "Attribute group %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +0000955 name);
956 xmlFree((char *) ret->name);
957 xmlFree(ret);
958 return (NULL);
959 }
960 return (ret);
961}
962
963/**
964 * xmlSchemaAddElement:
965 * @ctxt: a schema validation context
966 * @schema: the schema being built
967 * @name: the type name
968 * @namespace: the type namespace
969 *
970 * Add an XML schema Element declaration
971 * *WARNING* this interface is highly subject to change
972 *
973 * Returns the new struture or NULL in case of error
974 */
975static xmlSchemaElementPtr
976xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
977 const xmlChar * name, const xmlChar * namespace)
978{
979 xmlSchemaElementPtr ret = NULL;
980 int val;
981
982 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
983 return (NULL);
984
985 if (schema->elemDecl == NULL)
986 schema->elemDecl = xmlHashCreate(10);
987 if (schema->elemDecl == NULL)
988 return (NULL);
989
990 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
991 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +0000992 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +0000993 if ((ctxt != NULL) && (ctxt->error != NULL))
994 ctxt->error(ctxt->userData, "Out of memory\n");
995 return (NULL);
996 }
997 memset(ret, 0, sizeof(xmlSchemaElement));
998 ret->name = xmlStrdup(name);
999 val = xmlHashAddEntry3(schema->elemDecl, name,
1000 namespace, ctxt->container, ret);
1001 if (val != 0) {
1002 char buf[100];
1003
1004 snprintf(buf, 99, "privatieelem%d", ctxt->counter++ + 1);
1005 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
1006 namespace, ret);
1007 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001008 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001009 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001010 ctxt->error(ctxt->userData, "Element %s already defined\n",
Daniel Veillard4255d502002-04-16 15:50:10 +00001011 name);
1012 xmlFree((char *) ret->name);
1013 xmlFree(ret);
1014 return (NULL);
1015 }
1016 }
1017 return (ret);
1018}
1019
1020/**
1021 * xmlSchemaAddType:
1022 * @ctxt: a schema validation context
1023 * @schema: the schema being built
1024 * @name: the item name
1025 *
1026 * Add an XML schema Simple Type definition
1027 * *WARNING* this interface is highly subject to change
1028 *
1029 * Returns the new struture or NULL in case of error
1030 */
1031static xmlSchemaTypePtr
1032xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1033 const xmlChar * name)
1034{
1035 xmlSchemaTypePtr ret = NULL;
1036 int val;
1037
1038 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1039 return (NULL);
1040
1041 if (schema->typeDecl == NULL)
1042 schema->typeDecl = xmlHashCreate(10);
1043 if (schema->typeDecl == NULL)
1044 return (NULL);
1045
1046 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1047 if (ret == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001048 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001049 if ((ctxt != NULL) && (ctxt->error != NULL))
1050 ctxt->error(ctxt->userData, "Out of memory\n");
1051 return (NULL);
1052 }
1053 memset(ret, 0, sizeof(xmlSchemaType));
1054 ret->name = xmlStrdup(name);
1055 val = xmlHashAddEntry2(schema->typeDecl, name, schema->targetNamespace,
1056 ret);
1057 if (val != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001058 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001059 if ((ctxt != NULL) && (ctxt->error != NULL))
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001060 ctxt->error(ctxt->userData, "Type %s already defined\n", name);
1061 xmlFree((char *) ret->name);
1062 xmlFree(ret);
1063 return (NULL);
1064 }
1065 ret->minOccurs = 1;
1066 ret->maxOccurs = 1;
1067
1068 return (ret);
1069}
1070
1071/**
1072 * xmlSchemaAddGroup:
1073 * @ctxt: a schema validation context
1074 * @schema: the schema being built
1075 * @name: the group name
1076 *
1077 * Add an XML schema Group definition
1078 *
1079 * Returns the new struture or NULL in case of error
1080 */
1081static xmlSchemaTypePtr
1082xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1083 const xmlChar * name)
1084{
1085 xmlSchemaTypePtr ret = NULL;
1086 int val;
1087
1088 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1089 return (NULL);
1090
1091 if (schema->groupDecl == NULL)
1092 schema->groupDecl = xmlHashCreate(10);
1093 if (schema->groupDecl == NULL)
1094 return (NULL);
1095
1096 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1097 if (ret == NULL) {
1098 ctxt->nberrors++;
1099 if ((ctxt != NULL) && (ctxt->error != NULL))
1100 ctxt->error(ctxt->userData, "Out of memory\n");
1101 return (NULL);
1102 }
1103 memset(ret, 0, sizeof(xmlSchemaType));
1104 ret->name = xmlStrdup(name);
1105 val = xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace,
1106 ret);
1107 if (val != 0) {
1108 ctxt->nberrors++;
1109 if ((ctxt != NULL) && (ctxt->error != NULL))
1110 ctxt->error(ctxt->userData, "Group %s already defined\n", name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001111 xmlFree((char *) ret->name);
1112 xmlFree(ret);
1113 return (NULL);
1114 }
1115 ret->minOccurs = 1;
1116 ret->maxOccurs = 1;
1117
1118 return (ret);
1119}
1120
1121/************************************************************************
1122 * *
1123 * Utilities for parsing *
1124 * *
1125 ************************************************************************/
1126
1127/**
1128 * xmlGetQNameProp:
1129 * @ctxt: a schema validation context
1130 * @node: a subtree containing XML Schema informations
1131 * @name: the attribute name
1132 * @namespace: the result namespace if any
1133 *
1134 * Extract a QName Attribute value
1135 *
1136 * Returns the NCName or NULL if not found, and also update @namespace
1137 * with the namespace URI
1138 */
1139static xmlChar *
1140xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1141 const char *name,
1142 xmlChar **namespace) {
1143 xmlChar *val, *ret, *prefix;
1144 xmlNsPtr ns;
1145
1146
1147 if (namespace != NULL)
1148 *namespace = NULL;
1149 val = xmlGetProp(node, (const xmlChar *) name);
1150 if (val == NULL)
1151 return(NULL);
1152
1153 ret = xmlSplitQName2(val, &prefix);
1154 if (ret == NULL)
1155 return(val);
1156 xmlFree(val);
1157
1158 ns = xmlSearchNs(node->doc, node, prefix);
1159 if (ns == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001160 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001161 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1162 if ((ctxt != NULL) && (ctxt->error != NULL))
1163 ctxt->error(ctxt->userData,
1164 "Attribute %s: the QName prefix %s is undefined\n",
1165 name, prefix);
1166 } else {
1167 *namespace = xmlStrdup(ns->href);
1168 }
1169 xmlFree(prefix);
1170 return(ret);
1171}
1172
1173/**
1174 * xmlGetMaxOccurs:
1175 * @ctxt: a schema validation context
1176 * @node: a subtree containing XML Schema informations
1177 *
1178 * Get the maxOccurs property
1179 *
1180 * Returns the default if not found, or the value
1181 */
1182static int
1183xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1184 xmlChar *val, *cur;
1185 int ret = 0;
1186
1187 val = xmlGetProp(node, (const xmlChar *) "maxOccurs");
1188 if (val == NULL)
1189 return(1);
1190
1191 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
1192 xmlFree(val);
1193 return(UNBOUNDED); /* encoding it with -1 might be another option */
1194 }
1195
1196 cur = val;
1197 while (IS_BLANK(*cur)) cur++;
1198 while ((*cur >= '0') && (*cur <= '9')) {
1199 ret = ret * 10 + (*cur - '0');
1200 cur++;
1201 }
1202 while (IS_BLANK(*cur)) cur++;
1203 if (*cur != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001204 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001205 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1206 if ((ctxt != NULL) && (ctxt->error != NULL))
1207 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1208 val);
1209 xmlFree(val);
1210 return(1);
1211 }
1212 xmlFree(val);
1213 return(ret);
1214}
1215
1216/**
1217 * xmlGetMinOccurs:
1218 * @ctxt: a schema validation context
1219 * @node: a subtree containing XML Schema informations
1220 *
1221 * Get the minOccurs property
1222 *
1223 * Returns the default if not found, or the value
1224 */
1225static int
1226xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1227 xmlChar *val, *cur;
1228 int ret = 0;
1229
1230 val = xmlGetProp(node, (const xmlChar *) "minOccurs");
1231 if (val == NULL)
1232 return(1);
1233
1234 cur = val;
1235 while (IS_BLANK(*cur)) cur++;
1236 while ((*cur >= '0') && (*cur <= '9')) {
1237 ret = ret * 10 + (*cur - '0');
1238 cur++;
1239 }
1240 while (IS_BLANK(*cur)) cur++;
1241 if (*cur != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001242 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001243 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1244 if ((ctxt != NULL) && (ctxt->error != NULL))
1245 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1246 val);
1247 xmlFree(val);
1248 return(1);
1249 }
1250 xmlFree(val);
1251 return(ret);
1252}
1253
1254/**
1255 * xmlGetBooleanProp:
1256 * @ctxt: a schema validation context
1257 * @node: a subtree containing XML Schema informations
1258 * @name: the attribute name
1259 * @def: the default value
1260 *
1261 * Get is a bolean property is set
1262 *
1263 * Returns the default if not found, 0 if found to be false,
1264 * 1 if found to be true
1265 */
1266static int
1267xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1268 const char *name, int def) {
1269 xmlChar *val;
1270
1271 val = xmlGetProp(node, (const xmlChar *) name);
1272 if (val == NULL)
1273 return(def);
1274
1275 if (xmlStrEqual(val, BAD_CAST"true"))
1276 def = 1;
1277 else if (xmlStrEqual(val, BAD_CAST"false"))
1278 def = 0;
1279 else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001280 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001281 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1282 if ((ctxt != NULL) && (ctxt->error != NULL))
1283 ctxt->error(ctxt->userData,
1284 "Attribute %s: the value %s is not boolean\n",
1285 name, val);
1286 }
1287 xmlFree(val);
1288 return(def);
1289}
1290
1291/************************************************************************
1292 * *
1293 * Shema extraction from an Infoset *
1294 * *
1295 ************************************************************************/
1296static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1297 ctxt, xmlSchemaPtr schema,
1298 xmlNodePtr node);
1299static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt,
1300 xmlSchemaPtr schema,
1301 xmlNodePtr node);
1302static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt,
1303 xmlSchemaPtr schema,
1304 xmlNodePtr node,
1305 int simple);
1306static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1307 xmlSchemaPtr schema,
1308 xmlNodePtr node);
1309static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1310 xmlSchemaPtr schema,
1311 xmlNodePtr node);
1312static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1313 ctxt,
1314 xmlSchemaPtr schema,
1315 xmlNodePtr node);
1316static xmlSchemaAttributeGroupPtr
1317xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1318 xmlSchemaPtr schema, xmlNodePtr node);
1319static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1320 xmlSchemaPtr schema,
1321 xmlNodePtr node);
1322static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1323 xmlSchemaPtr schema,
1324 xmlNodePtr node);
1325static xmlSchemaAttributePtr
1326xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1327 xmlNodePtr node);
1328
1329/**
1330 * xmlSchemaParseAttrDecls:
1331 * @ctxt: a schema validation context
1332 * @schema: the schema being built
1333 * @node: a subtree containing XML Schema informations
1334 * @type: the hosting type
1335 *
1336 * parse a XML schema attrDecls declaration corresponding to
1337 * <!ENTITY % attrDecls
1338 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1339 */
1340static xmlNodePtr
1341xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1342 xmlNodePtr child, xmlSchemaTypePtr type)
1343{
1344 xmlSchemaAttributePtr lastattr, attr;
1345
1346 lastattr = NULL;
1347 while ((IS_SCHEMA(child, "attribute")) ||
1348 (IS_SCHEMA(child, "attributeGroup"))) {
1349 attr = NULL;
1350 if (IS_SCHEMA(child, "attribute")) {
1351 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1352 } else if (IS_SCHEMA(child, "attributeGroup")) {
1353 attr = (xmlSchemaAttributePtr)
1354 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1355 }
1356 if (attr != NULL) {
1357 if (lastattr == NULL) {
1358 type->attributes = attr;
1359 lastattr = attr
1360 ;
1361 } else {
1362 lastattr->next = attr;
1363 lastattr = attr;
1364 }
1365 }
1366 child = child->next;
1367 }
1368 if (IS_SCHEMA(child, "anyAttribute")) {
1369 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1370 if (attr != NULL) {
1371 if (lastattr == NULL) {
1372 type->attributes = attr;
1373 lastattr = attr
1374 ;
1375 } else {
1376 lastattr->next = attr;
1377 lastattr = attr;
1378 }
1379 }
1380 child = child->next;
1381 }
1382 return(child);
1383}
1384
1385/**
1386 * xmlSchemaParseAnnotation:
1387 * @ctxt: a schema validation context
1388 * @schema: the schema being built
1389 * @node: a subtree containing XML Schema informations
1390 *
1391 * parse a XML schema Attrribute declaration
1392 * *WARNING* this interface is highly subject to change
1393 *
1394 * Returns -1 in case of error, 0 if the declaration is inproper and
1395 * 1 in case of success.
1396 */
1397static xmlSchemaAnnotPtr
1398xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1399 xmlNodePtr node)
1400{
1401 xmlSchemaAnnotPtr ret;
1402
1403 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1404 return (NULL);
1405 ret = xmlSchemaNewAnnot(ctxt, node);
1406
1407 return (ret);
1408}
1409
1410/**
1411 * xmlSchemaParseFacet:
1412 * @ctxt: a schema validation context
1413 * @schema: the schema being built
1414 * @node: a subtree containing XML Schema informations
1415 *
1416 * parse a XML schema Facet declaration
1417 * *WARNING* this interface is highly subject to change
1418 *
1419 * Returns the new type structure or NULL in case of error
1420 */
1421static xmlSchemaFacetPtr
1422xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1423 xmlNodePtr node)
1424{
1425 xmlSchemaFacetPtr facet;
1426 xmlNodePtr child = NULL;
1427 xmlChar *value;
1428
1429 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1430 return (NULL);
1431
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001432 facet = xmlSchemaNewFacet();
Daniel Veillard4255d502002-04-16 15:50:10 +00001433 if (facet == NULL)
1434 return (NULL);
1435 facet->node = node;
1436 value = xmlGetProp(node, (const xmlChar *) "value");
1437 if (value == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001438 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001439 xmlSchemaErrorContext(ctxt, schema, node, child);
1440 if ((ctxt != NULL) && (ctxt->error != NULL))
1441 ctxt->error(ctxt->userData, "Facet %s has no value\n", node->name);
1442 xmlSchemaFreeFacet(facet);
1443 return (NULL);
1444 }
1445 if (IS_SCHEMA(node, "minInclusive")) {
1446 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1447 } else if (IS_SCHEMA(node, "minExclusive")) {
1448 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1449 } else if (IS_SCHEMA(node, "maxInclusive")) {
1450 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1451 } else if (IS_SCHEMA(node, "maxExclusive")) {
1452 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1453 } else if (IS_SCHEMA(node, "totalDigits")) {
1454 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1455 } else if (IS_SCHEMA(node, "fractionDigits")) {
1456 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1457 } else if (IS_SCHEMA(node, "pattern")) {
1458 facet->type = XML_SCHEMA_FACET_PATTERN;
1459 } else if (IS_SCHEMA(node, "enumeration")) {
1460 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1461 } else if (IS_SCHEMA(node, "whiteSpace")) {
1462 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1463 } else if (IS_SCHEMA(node, "length")) {
1464 facet->type = XML_SCHEMA_FACET_LENGTH;
1465 } else if (IS_SCHEMA(node, "maxLength")) {
1466 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1467 } else if (IS_SCHEMA(node, "minLength")) {
1468 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1469 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001470 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001471 xmlSchemaErrorContext(ctxt, schema, node, child);
1472 if ((ctxt != NULL) && (ctxt->error != NULL))
1473 ctxt->error(ctxt->userData, "Unknown facet type %s\n", node->name);
1474 xmlSchemaFreeFacet(facet);
1475 return(NULL);
1476 }
1477 facet->id = xmlGetProp(node, (const xmlChar *) "id");
1478 facet->value = value;
1479 child = node->children;
1480
1481 if (IS_SCHEMA(child, "annotation")) {
1482 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1483 child = child->next;
1484 }
1485 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001486 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001487 xmlSchemaErrorContext(ctxt, schema, node, child);
1488 if ((ctxt != NULL) && (ctxt->error != NULL))
1489 ctxt->error(ctxt->userData,
1490 "Facet %s has unexpected child content\n",
1491 node->name);
1492 }
1493 return (facet);
1494}
1495
1496/**
1497 * xmlSchemaParseAny:
1498 * @ctxt: a schema validation context
1499 * @schema: the schema being built
1500 * @node: a subtree containing XML Schema informations
1501 *
1502 * parse a XML schema Any declaration
1503 * *WARNING* this interface is highly subject to change
1504 *
1505 * Returns the new type structure or NULL in case of error
1506 */
1507static xmlSchemaTypePtr
1508xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1509 xmlNodePtr node)
1510{
1511 xmlSchemaTypePtr type;
1512 xmlNodePtr child = NULL;
1513 xmlChar name[30];
1514
1515 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1516 return (NULL);
1517 snprintf((char *)name, 30, "any %d", ctxt->counter++ + 1);
1518 type = xmlSchemaAddType(ctxt, schema, name);
1519 if (type == NULL)
1520 return (NULL);
1521 type->node = node;
1522 type->type = XML_SCHEMA_TYPE_ANY;
1523 child = node->children;
1524 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1525 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1526
1527 if (IS_SCHEMA(child, "annotation")) {
1528 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1529 child = child->next;
1530 }
1531 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001532 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001533 xmlSchemaErrorContext(ctxt, schema, node, child);
1534 if ((ctxt != NULL) && (ctxt->error != NULL))
1535 ctxt->error(ctxt->userData,
1536 "Sequence %s has unexpected content\n",
1537 type->name);
1538 }
1539
1540 return (type);
1541}
1542
1543/**
1544 * xmlSchemaParseNotation:
1545 * @ctxt: a schema validation context
1546 * @schema: the schema being built
1547 * @node: a subtree containing XML Schema informations
1548 *
1549 * parse a XML schema Notation declaration
1550 *
1551 * Returns the new structure or NULL in case of error
1552 */
1553static xmlSchemaNotationPtr
1554xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1555 xmlNodePtr node)
1556{
1557 xmlChar *name;
1558 xmlSchemaNotationPtr ret;
1559 xmlNodePtr child = NULL;
1560
1561 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1562 return (NULL);
1563 name = xmlGetProp(node, (const xmlChar *) "name");
1564 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001565 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001566 xmlSchemaErrorContext(ctxt, schema, node, child);
1567 if ((ctxt != NULL) && (ctxt->error != NULL))
1568 ctxt->error(ctxt->userData, "Notation has no name\n");
1569 return (NULL);
1570 }
1571 ret = xmlSchemaAddNotation(ctxt, schema, name);
1572 if (ret == NULL) {
1573 xmlFree(name);
1574 return (NULL);
1575 }
1576 child = node->children;
1577 if (IS_SCHEMA(child, "annotation")) {
1578 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1579 child = child->next;
1580 }
1581 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001582 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001583 xmlSchemaErrorContext(ctxt, schema, node, child);
1584 if ((ctxt != NULL) && (ctxt->error != NULL))
1585 ctxt->error(ctxt->userData,
1586 "notation %s has unexpected content\n",
1587 name);
1588 }
1589
1590 return (ret);
1591}
1592
1593/**
1594 * xmlSchemaParseAnyAttribute:
1595 * @ctxt: a schema validation context
1596 * @schema: the schema being built
1597 * @node: a subtree containing XML Schema informations
1598 *
1599 * parse a XML schema AnyAttrribute declaration
1600 * *WARNING* this interface is highly subject to change
1601 *
1602 * Returns an attribute def structure or NULL
1603 */
1604static xmlSchemaAttributePtr
1605xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1606 xmlNodePtr node)
1607{
1608 xmlChar *processContents;
1609 xmlSchemaAttributePtr ret;
1610 xmlNodePtr child = NULL;
1611 char name[100];
1612
1613 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1614 return (NULL);
1615
1616 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
1617 ret = xmlSchemaAddAttribute(ctxt, schema, (xmlChar *)name);
1618 if (ret == NULL) {
1619 return (NULL);
1620 }
1621 ret->id = xmlGetProp(node, (const xmlChar *) "id");
1622 processContents = xmlGetProp(node, (const xmlChar *) "processContents");
1623 if ((processContents == NULL) ||
1624 (xmlStrEqual(processContents, (const xmlChar *)"strict"))) {
1625 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1626 } else if (xmlStrEqual(processContents, (const xmlChar *)"skip")) {
1627 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1628 } else if (xmlStrEqual(processContents, (const xmlChar *)"lax")) {
1629 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
1630 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001631 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001632 xmlSchemaErrorContext(ctxt, schema, node, child);
1633 if ((ctxt != NULL) && (ctxt->error != NULL))
1634 ctxt->error(ctxt->userData,
1635 "anyAttribute has unexpected content for processContents: %s\n",
1636 processContents);
1637 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1638 }
1639 if (processContents != NULL)
1640 xmlFree(processContents);
1641
1642 child = node->children;
1643 if (IS_SCHEMA(child, "annotation")) {
1644 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1645 child = child->next;
1646 }
1647 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001648 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001649 xmlSchemaErrorContext(ctxt, schema, node, child);
1650 if ((ctxt != NULL) && (ctxt->error != NULL))
1651 ctxt->error(ctxt->userData,
1652 "anyAttribute %s has unexpected content\n",
1653 name);
1654 }
1655
1656 return (ret);
1657}
1658
1659
1660/**
1661 * xmlSchemaParseAttribute:
1662 * @ctxt: a schema validation context
1663 * @schema: the schema being built
1664 * @node: a subtree containing XML Schema informations
1665 *
1666 * parse a XML schema Attrribute declaration
1667 * *WARNING* this interface is highly subject to change
1668 *
1669 * Returns -1 in case of error, 0 if the declaration is inproper and
1670 * 1 in case of success.
1671 */
1672static xmlSchemaAttributePtr
1673xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1674 xmlNodePtr node)
1675{
1676 xmlChar *name, *refNs = NULL, *ref = NULL;
1677 xmlSchemaAttributePtr ret;
1678 xmlNodePtr child = NULL;
1679
1680 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1681 return (NULL);
1682 name = xmlGetProp(node, (const xmlChar *) "name");
1683 if (name == NULL) {
1684 char buf[100];
1685
1686 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1687 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001688 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001689 xmlSchemaErrorContext(ctxt, schema, node, child);
1690 if ((ctxt != NULL) && (ctxt->error != NULL))
1691 ctxt->error(ctxt->userData, "Attribute has no name nor ref\n");
1692 return (NULL);
1693 }
1694 snprintf(buf, 99, "anonattr%d", ctxt->counter++ + 1);
1695 name = xmlStrdup((xmlChar *) buf);
1696 }
1697 ret = xmlSchemaAddAttribute(ctxt, schema, name);
1698 if (ret == NULL) {
1699 xmlFree(name);
1700 if (ref != NULL)
1701 xmlFree(ref);
1702 return (NULL);
1703 }
1704 xmlFree(name);
1705 ret->ref = ref;
1706 ret->refNs = refNs;
1707 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001708 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001709 child = node->children;
1710 if (IS_SCHEMA(child, "annotation")) {
1711 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1712 child = child->next;
1713 }
1714 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillard88c58912002-04-23 07:12:20 +00001715 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001716 child = child->next;
1717 }
1718 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001719 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001720 xmlSchemaErrorContext(ctxt, schema, node, child);
1721 if ((ctxt != NULL) && (ctxt->error != NULL))
1722 ctxt->error(ctxt->userData,
1723 "attribute %s has unexpected content\n",
1724 name);
1725 }
1726
1727 return (ret);
1728}
1729
1730/**
1731 * xmlSchemaParseAttributeGroup:
1732 * @ctxt: a schema validation context
1733 * @schema: the schema being built
1734 * @node: a subtree containing XML Schema informations
1735 *
1736 * parse a XML schema Attribute Group declaration
1737 * *WARNING* this interface is highly subject to change
1738 *
1739 * Returns the attribute group or NULL in case of error.
1740 */
1741static xmlSchemaAttributeGroupPtr
1742xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1743 xmlNodePtr node)
1744{
1745 xmlChar *name, *refNs = NULL, *ref = NULL;
1746 xmlSchemaAttributeGroupPtr ret;
1747 xmlSchemaAttributePtr last = NULL, attr;
1748 xmlNodePtr child = NULL;
1749 xmlChar *oldcontainer;
1750
1751 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1752 return (NULL);
1753 oldcontainer = ctxt->container;
1754 name = xmlGetProp(node, (const xmlChar *) "name");
1755 if (name == NULL) {
1756 char buf[100];
1757
1758 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1759 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001760 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001761 xmlSchemaErrorContext(ctxt, schema, node, child);
1762 if ((ctxt != NULL) && (ctxt->error != NULL))
1763 ctxt->error(ctxt->userData,
1764 "AttributeGroup has no name nor ref\n");
1765 return (NULL);
1766 }
1767 snprintf(buf, 99, "anonattrgroup%d", ctxt->counter++ + 1);
1768 name = xmlStrdup((xmlChar *) buf);
Daniel Veillard91a13252003-03-27 23:44:43 +00001769 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001770 ctxt->nberrors++;
Daniel Veillard91a13252003-03-27 23:44:43 +00001771 if ((ctxt != NULL) && (ctxt->error != NULL))
1772 ctxt->error(ctxt->userData,
1773 "out of memory\n");
1774 return (NULL);
1775 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001776 }
1777 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
1778 if (ret == NULL) {
1779 xmlFree(name);
1780 if (ref != NULL)
1781 xmlFree(ref);
1782 return (NULL);
1783 }
1784 ret->ref = ref;
1785 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00001786 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001787 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001788 child = node->children;
1789 ctxt->container = name;
1790 if (IS_SCHEMA(child, "annotation")) {
1791 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1792 child = child->next;
1793 }
1794 while ((IS_SCHEMA(child, "attribute")) ||
1795 (IS_SCHEMA(child, "attributeGroup"))) {
1796 attr = NULL;
1797 if (IS_SCHEMA(child, "attribute")) {
1798 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1799 } else if (IS_SCHEMA(child, "attributeGroup")) {
1800 attr = (xmlSchemaAttributePtr)
1801 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1802 }
1803 if (attr != NULL) {
1804 if (last == NULL) {
1805 ret->attributes = attr;
1806 last = attr;
1807 } else {
1808 last->next = attr;
1809 last = attr;
1810 }
1811 }
1812 child = child->next;
1813 }
1814 if (IS_SCHEMA(child, "anyAttribute")) {
1815 TODO
1816 child = child->next;
1817 }
1818 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001819 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001820 xmlSchemaErrorContext(ctxt, schema, node, child);
1821 if ((ctxt != NULL) && (ctxt->error != NULL))
1822 ctxt->error(ctxt->userData,
1823 "attribute group %s has unexpected content\n",
1824 name);
1825 }
1826
1827 ctxt->container = oldcontainer;
Daniel Veillard91a13252003-03-27 23:44:43 +00001828 xmlFree(name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001829 return (ret);
1830}
1831
1832/**
1833 * xmlSchemaParseElement:
1834 * @ctxt: a schema validation context
1835 * @schema: the schema being built
1836 * @node: a subtree containing XML Schema informations
1837 *
1838 * parse a XML schema Element declaration
1839 * *WARNING* this interface is highly subject to change
1840 *
1841 * Returns -1 in case of error, 0 if the declaration is inproper and
1842 * 1 in case of success.
1843 */
1844static xmlSchemaElementPtr
1845xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1846 xmlNodePtr node, int toplevel)
1847{
1848 xmlChar *name, *refNs = NULL, *ref = NULL, *namespace, *fixed;
1849 xmlSchemaElementPtr ret;
1850 xmlNodePtr child = NULL;
1851 xmlChar *oldcontainer;
1852
1853 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1854 return (NULL);
1855 oldcontainer = ctxt->container;
1856 name = xmlGetProp(node, (const xmlChar *) "name");
1857 if (name == NULL) {
1858 char buf[100];
1859
1860 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1861 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001862 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001863 xmlSchemaErrorContext(ctxt, schema, node, child);
1864 if ((ctxt != NULL) && (ctxt->error != NULL))
1865 ctxt->error(ctxt->userData, "Element has no name nor ref\n");
1866 return (NULL);
1867 }
1868 snprintf(buf, 99, "anonelem%d", ctxt->counter++ + 1);
1869 name = xmlStrdup((xmlChar *) buf);
1870 }
1871 namespace = xmlGetProp(node, (const xmlChar *) "targetNamespace");
1872 if (namespace == NULL)
1873 ret =
1874 xmlSchemaAddElement(ctxt, schema, name,
1875 schema->targetNamespace);
1876 else
1877 ret = xmlSchemaAddElement(ctxt, schema, name, namespace);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001878 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001879 if (namespace != NULL)
1880 xmlFree(namespace);
1881 if (ret == NULL) {
1882 xmlFree(name);
1883 if (ref != NULL)
1884 xmlFree(ref);
1885 return (NULL);
1886 }
1887 ret->type = XML_SCHEMA_TYPE_ELEMENT;
1888 ret->ref = ref;
1889 ret->refNs = refNs;
1890 if (ref != NULL)
1891 ret->flags |= XML_SCHEMAS_ELEM_REF;
1892 if (toplevel)
1893 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
1894 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
1895 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1896 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
1897 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1898 ctxt->container = name;
1899
1900 ret->id = xmlGetProp(node, BAD_CAST "id");
1901 ret->namedType = xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
1902 ret->substGroup = xmlGetQNameProp(ctxt, node, "substitutionGroup",
1903 &(ret->substGroupNs));
1904 fixed = xmlGetProp(node, BAD_CAST "fixed");
1905 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
1906 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1907
1908 ret->value = xmlGetProp(node, BAD_CAST "default");
1909 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001910 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001911 xmlSchemaErrorContext(ctxt, schema, node, child);
1912 ctxt->error(ctxt->userData,
1913 "Element %s has both default and fixed\n",
1914 ret->name);
1915 xmlFree(fixed);
1916 } else if (fixed != NULL) {
1917 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
1918 ret->value = fixed;
1919 }
1920
1921 child = node->children;
1922 if (IS_SCHEMA(child, "annotation")) {
1923 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1924 child = child->next;
1925 }
1926 if (IS_SCHEMA(child, "complexType")) {
1927 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
1928 child = child->next;
1929 } else if (IS_SCHEMA(child, "simpleType")) {
1930 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
1931 child = child->next;
1932 }
1933 while ((IS_SCHEMA(child, "unique")) ||
1934 (IS_SCHEMA(child, "key")) ||
1935 (IS_SCHEMA(child, "keyref"))) {
1936 TODO
1937 child = child->next;
1938 }
1939 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001940 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001941 xmlSchemaErrorContext(ctxt, schema, node, child);
1942 if ((ctxt != NULL) && (ctxt->error != NULL))
1943 ctxt->error(ctxt->userData,
1944 "element %s has unexpected content\n",
1945 name);
1946 }
1947
1948 ctxt->container = oldcontainer;
1949 xmlFree(name);
1950 return (ret);
1951}
1952
1953/**
1954 * xmlSchemaParseUnion:
1955 * @ctxt: a schema validation context
1956 * @schema: the schema being built
1957 * @node: a subtree containing XML Schema informations
1958 *
1959 * parse a XML schema Union definition
1960 * *WARNING* this interface is highly subject to change
1961 *
1962 * Returns -1 in case of error, 0 if the declaration is inproper and
1963 * 1 in case of success.
1964 */
1965static xmlSchemaTypePtr
1966xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1967 xmlNodePtr node)
1968{
1969 xmlSchemaTypePtr type, subtype, last = NULL;
1970 xmlNodePtr child = NULL;
1971 xmlChar name[30];
1972
1973 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1974 return (NULL);
1975
1976
1977 snprintf((char *)name, 30, "union %d", ctxt->counter++ + 1);
1978 type = xmlSchemaAddType(ctxt, schema, name);
1979 if (type == NULL)
1980 return (NULL);
1981 type->node = node;
1982 type->type = XML_SCHEMA_TYPE_LIST;
1983 type->id = xmlGetProp(node, BAD_CAST "id");
1984 type->ref = xmlGetProp(node, BAD_CAST "memberTypes");
1985
1986 child = node->children;
1987 if (IS_SCHEMA(child, "annotation")) {
1988 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1989 child = child->next;
1990 }
1991 while (IS_SCHEMA(child, "simpleType")) {
1992 subtype = (xmlSchemaTypePtr)
1993 xmlSchemaParseSimpleType(ctxt, schema, child);
1994 if (subtype != NULL) {
1995 if (last == NULL) {
1996 type->subtypes = subtype;
1997 last = subtype;
1998 } else {
1999 last->next = subtype;
2000 last = subtype;
2001 }
2002 last->next = NULL;
2003 }
2004 child = child->next;
2005 }
2006 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002007 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002008 xmlSchemaErrorContext(ctxt, schema, node, child);
2009 if ((ctxt != NULL) && (ctxt->error != NULL))
2010 ctxt->error(ctxt->userData,
2011 "Union %s has unexpected content\n",
2012 type->name);
2013 }
2014 return (type);
2015}
2016
2017/**
2018 * xmlSchemaParseList:
2019 * @ctxt: a schema validation context
2020 * @schema: the schema being built
2021 * @node: a subtree containing XML Schema informations
2022 *
2023 * parse a XML schema List definition
2024 * *WARNING* this interface is highly subject to change
2025 *
2026 * Returns -1 in case of error, 0 if the declaration is inproper and
2027 * 1 in case of success.
2028 */
2029static xmlSchemaTypePtr
2030xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2031 xmlNodePtr node)
2032{
2033 xmlSchemaTypePtr type, subtype;
2034 xmlNodePtr child = NULL;
2035 xmlChar name[30];
2036
2037 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2038 return (NULL);
2039
2040 snprintf((char *)name, 30, "list %d", ctxt->counter++ + 1);
2041 type = xmlSchemaAddType(ctxt, schema, name);
2042 if (type == NULL)
2043 return (NULL);
2044 type->node = node;
2045 type->type = XML_SCHEMA_TYPE_LIST;
2046 type->id = xmlGetProp(node, BAD_CAST "id");
2047 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
2048
2049 child = node->children;
2050 if (IS_SCHEMA(child, "annotation")) {
2051 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2052 child = child->next;
2053 }
2054 subtype = NULL;
2055 if (IS_SCHEMA(child, "simpleType")) {
2056 subtype = (xmlSchemaTypePtr)
2057 xmlSchemaParseSimpleType(ctxt, schema, child);
2058 child = child->next;
2059 type->subtypes = subtype;
2060 }
2061 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002062 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002063 xmlSchemaErrorContext(ctxt, schema, node, child);
2064 if ((ctxt != NULL) && (ctxt->error != NULL))
2065 ctxt->error(ctxt->userData,
2066 "List %s has unexpected content\n",
2067 type->name);
2068 }
2069 return (type);
2070}
2071/**
2072 * xmlSchemaParseSimpleType:
2073 * @ctxt: a schema validation context
2074 * @schema: the schema being built
2075 * @node: a subtree containing XML Schema informations
2076 *
2077 * parse a XML schema Simple Type definition
2078 * *WARNING* this interface is highly subject to change
2079 *
2080 * Returns -1 in case of error, 0 if the declaration is inproper and
2081 * 1 in case of success.
2082 */
2083static xmlSchemaTypePtr
2084xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2085 xmlNodePtr node)
2086{
2087 xmlSchemaTypePtr type, subtype;
2088 xmlNodePtr child = NULL;
2089 xmlChar *name;
2090
2091 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2092 return (NULL);
2093
2094
2095 name = xmlGetProp(node, (const xmlChar *) "name");
2096 if (name == NULL) {
2097 char buf[100];
2098
2099 snprintf(buf, 99, "simpletype%d", ctxt->counter++ + 1);
2100 name = xmlStrdup((xmlChar *) buf);
2101 }
2102 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002103 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002104 xmlSchemaErrorContext(ctxt, schema, node, child);
2105 if ((ctxt != NULL) && (ctxt->error != NULL))
2106 ctxt->error(ctxt->userData, "simpleType has no name\n");
2107 return (NULL);
2108 }
2109 type = xmlSchemaAddType(ctxt, schema, name);
2110 xmlFree(name);
2111 if (type == NULL)
2112 return (NULL);
2113 type->node = node;
2114 type->type = XML_SCHEMA_TYPE_SIMPLE;
2115 type->id = xmlGetProp(node, BAD_CAST "id");
2116
2117 child = node->children;
2118 if (IS_SCHEMA(child, "annotation")) {
2119 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2120 child = child->next;
2121 }
2122 subtype = NULL;
2123 if (IS_SCHEMA(child, "restriction")) {
2124 subtype = (xmlSchemaTypePtr)
2125 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2126 child = child->next;
2127 } else if (IS_SCHEMA(child, "list")) {
2128 subtype = (xmlSchemaTypePtr)
2129 xmlSchemaParseList(ctxt, schema, child);
2130 child = child->next;
2131 } else if (IS_SCHEMA(child, "union")) {
2132 subtype = (xmlSchemaTypePtr)
2133 xmlSchemaParseUnion(ctxt, schema, child);
2134 child = child->next;
2135 }
2136 type->subtypes = subtype;
2137 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002138 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002139 xmlSchemaErrorContext(ctxt, schema, node, child);
2140 if ((ctxt != NULL) && (ctxt->error != NULL))
2141 ctxt->error(ctxt->userData,
2142 "SimpleType %s has unexpected content\n",
2143 type->name);
2144 }
2145
2146 return (type);
2147}
2148
2149
2150/**
2151 * xmlSchemaParseGroup:
2152 * @ctxt: a schema validation context
2153 * @schema: the schema being built
2154 * @node: a subtree containing XML Schema informations
2155 *
2156 * parse a XML schema Group definition
2157 * *WARNING* this interface is highly subject to change
2158 *
2159 * Returns -1 in case of error, 0 if the declaration is inproper and
2160 * 1 in case of success.
2161 */
2162static xmlSchemaTypePtr
2163xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2164 xmlNodePtr node)
2165{
2166 xmlSchemaTypePtr type, subtype;
2167 xmlNodePtr child = NULL;
2168 xmlChar *name, *ref = NULL, *refNs = NULL;
2169
2170 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2171 return (NULL);
2172
2173
2174 name = xmlGetProp(node, (const xmlChar *) "name");
2175 if (name == NULL) {
2176 char buf[100];
2177
2178 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2179 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002180 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002181 xmlSchemaErrorContext(ctxt, schema, node, child);
2182 if ((ctxt != NULL) && (ctxt->error != NULL))
2183 ctxt->error(ctxt->userData, "Group has no name nor ref\n");
2184 return (NULL);
2185 }
2186 snprintf(buf, 99, "anongroup%d", ctxt->counter++ + 1);
2187 name = xmlStrdup((xmlChar *) buf);
2188 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002189 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002190 if (type == NULL)
2191 return (NULL);
2192 type->node = node;
2193 type->type = XML_SCHEMA_TYPE_GROUP;
2194 type->id = xmlGetProp(node, BAD_CAST "id");
2195 type->ref = ref;
2196 type->refNs = refNs;
2197 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2198 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2199
2200 child = node->children;
2201 if (IS_SCHEMA(child, "annotation")) {
2202 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2203 child = child->next;
2204 }
2205 subtype = NULL;
2206 if (IS_SCHEMA(child, "all")) {
2207 subtype = (xmlSchemaTypePtr)
2208 xmlSchemaParseAll(ctxt, schema, child);
2209 child = child->next;
2210 } else if (IS_SCHEMA(child, "choice")) {
2211 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2212 child = child->next;
2213 } else if (IS_SCHEMA(child, "sequence")) {
2214 subtype = (xmlSchemaTypePtr)
2215 xmlSchemaParseSequence(ctxt, schema, child);
2216 child = child->next;
2217 }
2218 if (subtype != NULL)
2219 type->subtypes = subtype;
2220 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002221 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002222 xmlSchemaErrorContext(ctxt, schema, node, child);
2223 if ((ctxt != NULL) && (ctxt->error != NULL))
2224 ctxt->error(ctxt->userData,
2225 "Group %s has unexpected content\n",
2226 type->name);
2227 }
2228
2229 return (type);
2230}
2231
2232/**
2233 * xmlSchemaParseAll:
2234 * @ctxt: a schema validation context
2235 * @schema: the schema being built
2236 * @node: a subtree containing XML Schema informations
2237 *
2238 * parse a XML schema All definition
2239 * *WARNING* this interface is highly subject to change
2240 *
2241 * Returns -1 in case of error, 0 if the declaration is inproper and
2242 * 1 in case of success.
2243 */
2244static xmlSchemaTypePtr
2245xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2246 xmlNodePtr node)
2247{
2248 xmlSchemaTypePtr type, subtype, last = NULL;
2249 xmlNodePtr child = NULL;
2250 xmlChar name[30];
2251
2252 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2253 return (NULL);
2254
2255
2256 snprintf((char *)name, 30, "all%d", ctxt->counter++ + 1);
2257 type = xmlSchemaAddType(ctxt, schema, name);
2258 if (type == NULL)
2259 return (NULL);
2260 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002261 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002262 type->id = xmlGetProp(node, BAD_CAST "id");
2263 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2264 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2265
2266 child = node->children;
2267 if (IS_SCHEMA(child, "annotation")) {
2268 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2269 child = child->next;
2270 }
2271 while (IS_SCHEMA(child, "element")) {
2272 subtype = (xmlSchemaTypePtr)
2273 xmlSchemaParseElement(ctxt, schema, child, 0);
2274 if (subtype != NULL) {
2275 if (last == NULL) {
2276 type->subtypes = subtype;
2277 last = subtype;
2278 } else {
2279 last->next = subtype;
2280 last = subtype;
2281 }
2282 last->next = NULL;
2283 }
2284 child = child->next;
2285 }
2286 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002287 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002288 xmlSchemaErrorContext(ctxt, schema, node, child);
2289 if ((ctxt != NULL) && (ctxt->error != NULL))
2290 ctxt->error(ctxt->userData,
2291 "All %s has unexpected content\n",
2292 type->name);
2293 }
2294
2295 return (type);
2296}
2297
2298/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002299 * xmlSchemaParseImport:
2300 * @ctxt: a schema validation context
2301 * @schema: the schema being built
2302 * @node: a subtree containing XML Schema informations
2303 *
2304 * parse a XML schema Import definition
2305 * *WARNING* this interface is highly subject to change
2306 *
2307 * Returns -1 in case of error, 0 if the declaration is inproper and
2308 * 1 in case of success.
2309 */
2310static int
2311xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2312 xmlNodePtr node)
2313{
2314 xmlNodePtr child = NULL;
2315 xmlChar *namespace;
2316 xmlChar *schemaLocation;
2317 xmlChar *previous;
2318 xmlURIPtr check;
2319
2320 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2321 return (-1);
2322
2323 namespace = xmlGetProp(node, BAD_CAST "namespace");
2324 if (namespace != NULL) {
2325 check = xmlParseURI((const char *) namespace);
2326 if (check == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002327 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002328 xmlSchemaErrorContext(ctxt, schema, node, child);
2329 if ((ctxt != NULL) && (ctxt->error != NULL))
2330 ctxt->error(ctxt->userData,
2331 "Import namespace attribute is not an URI: %s\n",
2332 namespace);
2333 xmlFree(namespace);
2334 return(-1);
2335 } else {
2336 xmlFreeURI(check);
2337 }
2338 }
2339 schemaLocation = xmlGetProp(node, BAD_CAST "schemaLocation");
2340 if (schemaLocation != NULL) {
2341 check = xmlParseURI((const char *) schemaLocation);
2342 if (check == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002343 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002344 xmlSchemaErrorContext(ctxt, schema, node, child);
2345 if ((ctxt != NULL) && (ctxt->error != NULL))
2346 ctxt->error(ctxt->userData,
2347 "Import schemaLocation attribute is not an URI: %s\n",
2348 schemaLocation);
2349 if (namespace != NULL)
2350 xmlFree(namespace);
2351 xmlFree(schemaLocation);
2352 return(-1);
2353 } else {
2354 xmlFreeURI(check);
2355 }
2356 }
2357 if (schema->schemasImports == NULL) {
2358 schema->schemasImports = xmlHashCreate(10);
2359 if (schema->schemasImports == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002360 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002361 xmlSchemaErrorContext(ctxt, schema, node, child);
2362 if ((ctxt != NULL) && (ctxt->error != NULL))
2363 ctxt->error(ctxt->userData,
2364 "Internal: failed to build import table\n");
2365 if (namespace != NULL)
2366 xmlFree(namespace);
2367 if (schemaLocation != NULL)
2368 xmlFree(schemaLocation);
2369 return(-1);
2370 }
2371 }
2372 if (namespace == NULL) {
2373 previous = xmlHashLookup(schema->schemasImports,
2374 XML_SCHEMAS_DEFAULT_NAMESPACE);
2375 if (schemaLocation != NULL) {
2376 if (previous != NULL) {
2377 if (!xmlStrEqual(schemaLocation, previous)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002378 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002379 xmlSchemaErrorContext(ctxt, schema, node, child);
2380 if ((ctxt != NULL) && (ctxt->error != NULL))
2381 ctxt->error(ctxt->userData,
2382 "Redefining import for default namespace with a different URI: %s\n",
2383 schemaLocation);
2384 }
2385 } else {
2386 xmlHashAddEntry(schema->schemasImports,
2387 XML_SCHEMAS_DEFAULT_NAMESPACE, schemaLocation);
2388 }
2389 }
2390 } else {
2391 previous = xmlHashLookup(schema->schemasImports, namespace);
2392 if (schemaLocation != NULL) {
2393 if (previous != NULL) {
2394 if (!xmlStrEqual(schemaLocation, previous)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002395 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002396 xmlSchemaErrorContext(ctxt, schema, node, child);
2397 if ((ctxt != NULL) && (ctxt->error != NULL))
2398 ctxt->error(ctxt->userData,
2399 "Redefining import for namespace %s with a different URI: %s\n",
2400 namespace, schemaLocation);
2401 }
2402 } else {
2403 xmlHashAddEntry(schema->schemasImports,
2404 namespace, schemaLocation);
2405 }
2406 }
2407 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002408
2409 child = node->children;
2410 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillard7c13af42002-05-22 09:57:32 +00002411 /*
2412 * the annotations here are simply discarded ...
2413 */
Daniel Veillard5a872412002-05-22 06:40:27 +00002414 child = child->next;
2415 }
2416 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002417 ctxt->nberrors++;
Daniel Veillard5a872412002-05-22 06:40:27 +00002418 xmlSchemaErrorContext(ctxt, schema, node, child);
2419 if ((ctxt != NULL) && (ctxt->error != NULL))
2420 ctxt->error(ctxt->userData,
2421 "Import has unexpected content\n");
2422 return(-1);
2423 }
2424 return(1);
2425}
2426
2427/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002428 * xmlSchemaParseChoice:
2429 * @ctxt: a schema validation context
2430 * @schema: the schema being built
2431 * @node: a subtree containing XML Schema informations
2432 *
2433 * parse a XML schema Choice definition
2434 * *WARNING* this interface is highly subject to change
2435 *
2436 * Returns -1 in case of error, 0 if the declaration is inproper and
2437 * 1 in case of success.
2438 */
2439static xmlSchemaTypePtr
2440xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2441 xmlNodePtr node)
2442{
2443 xmlSchemaTypePtr type, subtype, last = NULL;
2444 xmlNodePtr child = NULL;
2445 xmlChar name[30];
2446
2447 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2448 return (NULL);
2449
2450
2451 snprintf((char *)name, 30, "choice %d", ctxt->counter++ + 1);
2452 type = xmlSchemaAddType(ctxt, schema, name);
2453 if (type == NULL)
2454 return (NULL);
2455 type->node = node;
2456 type->type = XML_SCHEMA_TYPE_CHOICE;
2457 type->id = xmlGetProp(node, BAD_CAST "id");
2458 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2459 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2460
2461 child = node->children;
2462 if (IS_SCHEMA(child, "annotation")) {
2463 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2464 child = child->next;
2465 }
2466 while ((IS_SCHEMA(child, "element")) ||
2467 (IS_SCHEMA(child, "group")) ||
2468 (IS_SCHEMA(child, "any")) ||
2469 (IS_SCHEMA(child, "choice")) ||
2470 (IS_SCHEMA(child, "sequence"))) {
2471 subtype = NULL;
2472 if (IS_SCHEMA(child, "element")) {
2473 subtype = (xmlSchemaTypePtr)
2474 xmlSchemaParseElement(ctxt, schema, child, 0);
2475 } else if (IS_SCHEMA(child, "group")) {
2476 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2477 } else if (IS_SCHEMA(child, "any")) {
2478 subtype = xmlSchemaParseAny(ctxt, schema, child);
2479 } else if (IS_SCHEMA(child, "sequence")) {
2480 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2481 } else if (IS_SCHEMA(child, "choice")) {
2482 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2483 }
2484 if (subtype != NULL) {
2485 if (last == NULL) {
2486 type->subtypes = subtype;
2487 last = subtype;
2488 } else {
2489 last->next = subtype;
2490 last = subtype;
2491 }
2492 last->next = NULL;
2493 }
2494 child = child->next;
2495 }
2496 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002497 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002498 xmlSchemaErrorContext(ctxt, schema, node, child);
2499 if ((ctxt != NULL) && (ctxt->error != NULL))
2500 ctxt->error(ctxt->userData,
2501 "Choice %s has unexpected content\n",
2502 type->name);
2503 }
2504
2505 return (type);
2506}
2507
2508/**
2509 * xmlSchemaParseSequence:
2510 * @ctxt: a schema validation context
2511 * @schema: the schema being built
2512 * @node: a subtree containing XML Schema informations
2513 *
2514 * parse a XML schema Sequence definition
2515 * *WARNING* this interface is highly subject to change
2516 *
2517 * Returns -1 in case of error, 0 if the declaration is inproper and
2518 * 1 in case of success.
2519 */
2520static xmlSchemaTypePtr
2521xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2522 xmlNodePtr node)
2523{
2524 xmlSchemaTypePtr type, subtype, last = NULL;
2525 xmlNodePtr child = NULL;
2526 xmlChar name[30];
2527
2528 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2529 return (NULL);
2530
2531
2532 snprintf((char *)name, 30, "sequence %d", ctxt->counter++ + 1);
2533 type = xmlSchemaAddType(ctxt, schema, name);
2534 if (type == NULL)
2535 return (NULL);
2536 type->node = node;
2537 type->type = XML_SCHEMA_TYPE_SEQUENCE;
2538 type->id = xmlGetProp(node, BAD_CAST "id");
2539 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2540 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2541
2542 child = node->children;
2543 if (IS_SCHEMA(child, "annotation")) {
2544 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2545 child = child->next;
2546 }
2547 while ((IS_SCHEMA(child, "element")) ||
2548 (IS_SCHEMA(child, "group")) ||
2549 (IS_SCHEMA(child, "any")) ||
2550 (IS_SCHEMA(child, "choice")) ||
2551 (IS_SCHEMA(child, "sequence"))) {
2552 subtype = NULL;
2553 if (IS_SCHEMA(child, "element")) {
2554 subtype = (xmlSchemaTypePtr)
2555 xmlSchemaParseElement(ctxt, schema, child, 0);
2556 } else if (IS_SCHEMA(child, "group")) {
2557 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2558 } else if (IS_SCHEMA(child, "any")) {
2559 subtype = xmlSchemaParseAny(ctxt, schema, child);
2560 } else if (IS_SCHEMA(child, "choice")) {
2561 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2562 } else if (IS_SCHEMA(child, "sequence")) {
2563 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2564 }
2565 if (subtype != NULL) {
2566 if (last == NULL) {
2567 type->subtypes = subtype;
2568 last = subtype;
2569 } else {
2570 last->next = subtype;
2571 last = subtype;
2572 }
2573 last->next = NULL;
2574 }
2575 child = child->next;
2576 }
2577 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002578 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002579 xmlSchemaErrorContext(ctxt, schema, node, child);
2580 if ((ctxt != NULL) && (ctxt->error != NULL))
2581 ctxt->error(ctxt->userData,
2582 "Sequence %s has unexpected content\n",
2583 type->name);
2584 }
2585
2586 return (type);
2587}
2588
2589/**
2590 * xmlSchemaParseRestriction:
2591 * @ctxt: a schema validation context
2592 * @schema: the schema being built
2593 * @node: a subtree containing XML Schema informations
2594 * @simple: is that part of a simple type.
2595 *
2596 * parse a XML schema Restriction definition
2597 * *WARNING* this interface is highly subject to change
2598 *
2599 * Returns the type definition or NULL in case of error
2600 */
2601static xmlSchemaTypePtr
2602xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2603 xmlNodePtr node, int simple)
2604{
2605 xmlSchemaTypePtr type, subtype;
2606 xmlSchemaFacetPtr facet, lastfacet = NULL;
2607 xmlNodePtr child = NULL;
2608 xmlChar name[30];
2609 xmlChar *oldcontainer;
2610
2611 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2612 return (NULL);
2613
2614 oldcontainer = ctxt->container;
2615
2616 snprintf((char *)name, 30, "restriction %d", ctxt->counter++ + 1);
2617 type = xmlSchemaAddType(ctxt, schema, name);
2618 if (type == NULL)
2619 return (NULL);
2620 type->node = node;
2621 type->type = XML_SCHEMA_TYPE_RESTRICTION;
2622 type->id = xmlGetProp(node, BAD_CAST "id");
2623 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2624 if ((!simple) && (type->base == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002625 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002626 xmlSchemaErrorContext(ctxt, schema, node, child);
2627 if ((ctxt != NULL) && (ctxt->error != NULL))
2628 ctxt->error(ctxt->userData,
2629 "Restriction %s has no base\n",
2630 type->name);
2631 }
2632 ctxt->container = name;
2633
2634 child = node->children;
2635 if (IS_SCHEMA(child, "annotation")) {
2636 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2637 child = child->next;
2638 }
2639 subtype = NULL;
2640
2641 if (IS_SCHEMA(child, "all")) {
2642 subtype = (xmlSchemaTypePtr)
2643 xmlSchemaParseAll(ctxt, schema, child);
2644 child = child->next;
2645 type->subtypes = subtype;
2646 } else if (IS_SCHEMA(child, "choice")) {
2647 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2648 child = child->next;
2649 type->subtypes = subtype;
2650 } else if (IS_SCHEMA(child, "sequence")) {
2651 subtype = (xmlSchemaTypePtr)
2652 xmlSchemaParseSequence(ctxt, schema, child);
2653 child = child->next;
2654 type->subtypes = subtype;
2655 } else if (IS_SCHEMA(child, "group")) {
2656 subtype = (xmlSchemaTypePtr)
2657 xmlSchemaParseGroup(ctxt, schema, child);
2658 child = child->next;
2659 type->subtypes = subtype;
2660 } else {
2661 if (IS_SCHEMA(child, "simpleType")) {
2662 subtype = (xmlSchemaTypePtr)
2663 xmlSchemaParseSimpleType(ctxt, schema, child);
2664 child = child->next;
2665 type->baseType = subtype;
2666 }
2667 /*
2668 * Facets
2669 */
2670 while ((IS_SCHEMA(child, "minInclusive")) ||
2671 (IS_SCHEMA(child, "minExclusive")) ||
2672 (IS_SCHEMA(child, "maxInclusive")) ||
2673 (IS_SCHEMA(child, "maxExclusive")) ||
2674 (IS_SCHEMA(child, "totalDigits")) ||
2675 (IS_SCHEMA(child, "fractionDigits")) ||
2676 (IS_SCHEMA(child, "pattern")) ||
2677 (IS_SCHEMA(child, "enumeration")) ||
2678 (IS_SCHEMA(child, "whiteSpace")) ||
2679 (IS_SCHEMA(child, "length")) ||
2680 (IS_SCHEMA(child, "maxLength")) ||
2681 (IS_SCHEMA(child, "minLength"))) {
2682 facet = xmlSchemaParseFacet(ctxt, schema, child);
2683 if (facet != NULL) {
2684 if (lastfacet == NULL) {
2685 type->facets = facet;
2686 lastfacet = facet;
2687 } else {
2688 lastfacet->next = facet;
2689 lastfacet = facet;
2690 }
2691 lastfacet->next = NULL;
2692 }
2693 child = child->next;
2694 }
2695 }
2696 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2697 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002698 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002699 xmlSchemaErrorContext(ctxt, schema, node, child);
2700 if ((ctxt != NULL) && (ctxt->error != NULL))
2701 ctxt->error(ctxt->userData,
2702 "Restriction %s has unexpected content\n",
2703 type->name);
2704 }
2705 ctxt->container = oldcontainer;
2706 return (type);
2707}
2708
2709/**
2710 * xmlSchemaParseExtension:
2711 * @ctxt: a schema validation context
2712 * @schema: the schema being built
2713 * @node: a subtree containing XML Schema informations
2714 *
2715 * parse a XML schema Extension definition
2716 * *WARNING* this interface is highly subject to change
2717 *
2718 * Returns the type definition or NULL in case of error
2719 */
2720static xmlSchemaTypePtr
2721xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2722 xmlNodePtr node)
2723{
2724 xmlSchemaTypePtr type, subtype;
2725 xmlNodePtr child = NULL;
2726 xmlChar name[30];
2727 xmlChar *oldcontainer;
2728
2729 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2730 return (NULL);
2731
2732 oldcontainer = ctxt->container;
2733
2734 snprintf((char *)name, 30, "extension %d", ctxt->counter++ + 1);
2735 type = xmlSchemaAddType(ctxt, schema, name);
2736 if (type == NULL)
2737 return (NULL);
2738 type->node = node;
2739 type->type = XML_SCHEMA_TYPE_EXTENSION;
2740 type->id = xmlGetProp(node, BAD_CAST "id");
2741 ctxt->container = name;
2742
2743 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2744 if (type->base == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002745 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002746 xmlSchemaErrorContext(ctxt, schema, node, child);
2747 if ((ctxt != NULL) && (ctxt->error != NULL))
2748 ctxt->error(ctxt->userData,
2749 "Extension %s has no base\n",
2750 type->name);
2751 }
2752 child = node->children;
2753 if (IS_SCHEMA(child, "annotation")) {
2754 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2755 child = child->next;
2756 }
2757 subtype = NULL;
2758
2759 if (IS_SCHEMA(child, "all")) {
2760 subtype = xmlSchemaParseAll(ctxt, schema, child);
2761 child = child->next;
2762 } else if (IS_SCHEMA(child, "choice")) {
2763 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2764 child = child->next;
2765 } else if (IS_SCHEMA(child, "sequence")) {
2766 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2767 child = child->next;
2768 } else if (IS_SCHEMA(child, "group")) {
2769 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2770 child = child->next;
2771 }
2772 if (subtype != NULL)
2773 type->subtypes = subtype;
2774 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2775 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002776 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002777 xmlSchemaErrorContext(ctxt, schema, node, child);
2778 if ((ctxt != NULL) && (ctxt->error != NULL))
2779 ctxt->error(ctxt->userData,
2780 "Extension %s has unexpected content\n",
2781 type->name);
2782 }
2783 ctxt->container = oldcontainer;
2784 return (type);
2785}
2786
2787/**
2788 * xmlSchemaParseSimpleContent:
2789 * @ctxt: a schema validation context
2790 * @schema: the schema being built
2791 * @node: a subtree containing XML Schema informations
2792 *
2793 * parse a XML schema SimpleContent definition
2794 * *WARNING* this interface is highly subject to change
2795 *
2796 * Returns the type definition or NULL in case of error
2797 */
2798static xmlSchemaTypePtr
2799xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2800 xmlNodePtr node)
2801{
2802 xmlSchemaTypePtr type, subtype;
2803 xmlNodePtr child = NULL;
2804 xmlChar name[30];
2805
2806 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2807 return (NULL);
2808
2809
2810 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2811 type = xmlSchemaAddType(ctxt, schema, name);
2812 if (type == NULL)
2813 return (NULL);
2814 type->node = node;
2815 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
2816 type->id = xmlGetProp(node, BAD_CAST "id");
2817
2818 child = node->children;
2819 if (IS_SCHEMA(child, "annotation")) {
2820 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2821 child = child->next;
2822 }
2823 subtype = NULL;
2824 if (IS_SCHEMA(child, "restriction")) {
2825 subtype = (xmlSchemaTypePtr)
2826 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2827 child = child->next;
2828 } else if (IS_SCHEMA(child, "extension")) {
2829 subtype = (xmlSchemaTypePtr)
2830 xmlSchemaParseExtension(ctxt, schema, child);
2831 child = child->next;
2832 }
2833 type->subtypes = subtype;
2834 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002835 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002836 xmlSchemaErrorContext(ctxt, schema, node, child);
2837 if ((ctxt != NULL) && (ctxt->error != NULL))
2838 ctxt->error(ctxt->userData,
2839 "SimpleContent %s has unexpected content\n",
2840 type->name);
2841 }
2842 return (type);
2843}
2844
2845/**
2846 * xmlSchemaParseComplexContent:
2847 * @ctxt: a schema validation context
2848 * @schema: the schema being built
2849 * @node: a subtree containing XML Schema informations
2850 *
2851 * parse a XML schema ComplexContent definition
2852 * *WARNING* this interface is highly subject to change
2853 *
2854 * Returns the type definition or NULL in case of error
2855 */
2856static xmlSchemaTypePtr
2857xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2858 xmlNodePtr node)
2859{
2860 xmlSchemaTypePtr type, subtype;
2861 xmlNodePtr child = NULL;
2862 xmlChar name[30];
2863
2864 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2865 return (NULL);
2866
2867
2868 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2869 type = xmlSchemaAddType(ctxt, schema, name);
2870 if (type == NULL)
2871 return (NULL);
2872 type->node = node;
2873 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
2874 type->id = xmlGetProp(node, BAD_CAST "id");
2875
2876 child = node->children;
2877 if (IS_SCHEMA(child, "annotation")) {
2878 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2879 child = child->next;
2880 }
2881 subtype = NULL;
2882 if (IS_SCHEMA(child, "restriction")) {
2883 subtype = (xmlSchemaTypePtr)
2884 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2885 child = child->next;
2886 } else if (IS_SCHEMA(child, "extension")) {
2887 subtype = (xmlSchemaTypePtr)
2888 xmlSchemaParseExtension(ctxt, schema, child);
2889 child = child->next;
2890 }
2891 type->subtypes = subtype;
2892 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002893 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002894 xmlSchemaErrorContext(ctxt, schema, node, child);
2895 if ((ctxt != NULL) && (ctxt->error != NULL))
2896 ctxt->error(ctxt->userData,
2897 "ComplexContent %s has unexpected content\n",
2898 type->name);
2899 }
2900 return (type);
2901}
2902
2903/**
2904 * xmlSchemaParseComplexType:
2905 * @ctxt: a schema validation context
2906 * @schema: the schema being built
2907 * @node: a subtree containing XML Schema informations
2908 *
2909 * parse a XML schema Complex Type definition
2910 * *WARNING* this interface is highly subject to change
2911 *
2912 * Returns the type definition or NULL in case of error
2913 */
2914static xmlSchemaTypePtr
2915xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2916 xmlNodePtr node)
2917{
2918 xmlSchemaTypePtr type, subtype;
2919 xmlNodePtr child = NULL;
2920 xmlChar *name;
2921 xmlChar *oldcontainer;
2922
2923 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2924 return (NULL);
2925
2926 oldcontainer = ctxt->container;
2927 name = xmlGetProp(node, (const xmlChar *) "name");
2928 if (name == NULL) {
2929 char buf[100];
2930
2931 snprintf(buf, 99, "anontype%d", ctxt->counter++ + 1);
2932 name = xmlStrdup((xmlChar *) buf);
2933 }
2934 if (name == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002935 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002936 xmlSchemaErrorContext(ctxt, schema, node, child);
2937 if ((ctxt != NULL) && (ctxt->error != NULL))
2938 ctxt->error(ctxt->userData, "complexType has no name\n");
2939 return (NULL);
2940 }
2941 type = xmlSchemaAddType(ctxt, schema, name);
2942 if (type == NULL) {
2943 xmlFree(name);
2944 return (NULL);
2945 }
2946 type->node = node;
2947 type->type = XML_SCHEMA_TYPE_COMPLEX;
2948 type->id = xmlGetProp(node, BAD_CAST "id");
2949 ctxt->container = name;
2950
2951 child = node->children;
2952 if (IS_SCHEMA(child, "annotation")) {
2953 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2954 child = child->next;
2955 }
2956 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillarddecd64d2002-04-18 14:41:51 +00002957 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002958 child = child->next;
2959 } else if (IS_SCHEMA(child, "complexContent")) {
2960 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
2961 child = child->next;
2962 } else {
2963 subtype = NULL;
2964
2965 if (IS_SCHEMA(child, "all")) {
2966 subtype = xmlSchemaParseAll(ctxt, schema, child);
2967 child = child->next;
2968 } else if (IS_SCHEMA(child, "choice")) {
2969 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2970 child = child->next;
2971 } else if (IS_SCHEMA(child, "sequence")) {
2972 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2973 child = child->next;
2974 } else if (IS_SCHEMA(child, "group")) {
2975 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2976 child = child->next;
2977 }
2978 if (subtype != NULL)
2979 type->subtypes = subtype;
2980 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2981 }
2982 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002983 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00002984 xmlSchemaErrorContext(ctxt, schema, node, child);
2985 if ((ctxt != NULL) && (ctxt->error != NULL))
2986 ctxt->error(ctxt->userData,
2987 "ComplexType %s has unexpected content\n",
2988 type->name);
2989 }
2990 ctxt->container = oldcontainer;
2991 xmlFree(name);
2992 return (type);
2993}
2994
2995
2996/**
2997 * xmlSchemaParseSchema:
2998 * @ctxt: a schema validation context
2999 * @node: a subtree containing XML Schema informations
3000 *
3001 * parse a XML schema definition from a node set
3002 * *WARNING* this interface is highly subject to change
3003 *
3004 * Returns the internal XML Schema structure built from the resource or
3005 * NULL in case of error
3006 */
3007static xmlSchemaPtr
3008xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3009{
3010 xmlSchemaPtr schema = NULL;
3011 xmlSchemaAnnotPtr annot;
3012 xmlNodePtr child = NULL;
3013 xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003014 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003015
3016 if ((ctxt == NULL) || (node == NULL))
3017 return (NULL);
3018
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003019 nberrors = ctxt->nberrors;
3020 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003021 if (IS_SCHEMA(node, "schema")) {
3022 schema = xmlSchemaNewSchema(ctxt);
3023 if (schema == NULL)
3024 return(NULL);
3025 schema->targetNamespace = xmlGetProp(node, BAD_CAST "targetNamespace");
3026 schema->id = xmlGetProp(node, BAD_CAST "id");
3027 schema->version = xmlGetProp(node, BAD_CAST "version");
3028 val = xmlGetProp(node, BAD_CAST "elementFormDefault");
3029 if (val != NULL) {
3030 if (xmlStrEqual(val, BAD_CAST "qualified"))
3031 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3032 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003033 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003034 xmlSchemaErrorContext(ctxt, schema, node, child);
3035 if ((ctxt != NULL) && (ctxt->error != NULL)) {
3036 ctxt->error(ctxt->userData,
3037 "Invalid value %s for elementFormDefault\n",
3038 val);
3039 }
3040 }
3041 xmlFree(val);
3042 }
3043 val = xmlGetProp(node, BAD_CAST "attributeFormDefault");
3044 if (val != NULL) {
3045 if (xmlStrEqual(val, BAD_CAST "qualified"))
3046 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3047 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003048 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003049 xmlSchemaErrorContext(ctxt, schema, node, child);
3050 if ((ctxt != NULL) && (ctxt->error != NULL)) {
3051 ctxt->error(ctxt->userData,
3052 "Invalid value %s for elementFormDefault\n",
3053 val);
3054 }
3055 }
3056 xmlFree(val);
3057 }
3058
3059 child = node->children;
3060 while ((IS_SCHEMA(child, "include")) ||
3061 (IS_SCHEMA(child, "import")) ||
3062 (IS_SCHEMA(child, "redefine")) ||
3063 (IS_SCHEMA(child, "annotation"))) {
3064 if (IS_SCHEMA(child, "annotation")) {
3065 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3066 if (schema->annot == NULL)
3067 schema->annot = annot;
3068 else
3069 xmlSchemaFreeAnnot(annot);
3070 } else if (IS_SCHEMA(child, "include")) {
3071 TODO
3072 } else if (IS_SCHEMA(child, "import")) {
Daniel Veillard5a872412002-05-22 06:40:27 +00003073 xmlSchemaParseImport(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00003074 } else if (IS_SCHEMA(child, "redefine")) {
3075 TODO
3076 }
3077 child = child->next;
3078 }
3079 while (child != NULL) {
3080 if (IS_SCHEMA(child, "complexType")) {
3081 xmlSchemaParseComplexType(ctxt, schema, child);
3082 child = child->next;
3083 } else if (IS_SCHEMA(child, "simpleType")) {
3084 xmlSchemaParseSimpleType(ctxt, schema, child);
3085 child = child->next;
3086 } else if (IS_SCHEMA(child, "element")) {
3087 xmlSchemaParseElement(ctxt, schema, child, 1);
3088 child = child->next;
3089 } else if (IS_SCHEMA(child, "attribute")) {
3090 xmlSchemaParseAttribute(ctxt, schema, child);
3091 child = child->next;
3092 } else if (IS_SCHEMA(child, "attributeGroup")) {
3093 xmlSchemaParseAttributeGroup(ctxt, schema, child);
3094 child = child->next;
3095 } else if (IS_SCHEMA(child, "group")) {
3096 xmlSchemaParseGroup(ctxt, schema, child);
3097 child = child->next;
3098 } else if (IS_SCHEMA(child, "notation")) {
3099 xmlSchemaParseNotation(ctxt, schema, child);
3100 child = child->next;
3101 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003102 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003103 xmlSchemaErrorContext(ctxt, schema, node, child);
3104 if ((ctxt != NULL) && (ctxt->error != NULL))
3105 ctxt->error(ctxt->userData,
3106 "Schemas: unexpected element %s here \n",
3107 child->name);
3108 child = child->next;
3109 }
3110 while (IS_SCHEMA(child, "annotation")) {
3111 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3112 if (schema->annot == NULL)
3113 schema->annot = annot;
3114 else
3115 xmlSchemaFreeAnnot(annot);
3116 child = child->next;
3117 }
3118 }
3119 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003120 if (ctxt->nberrors != 0) {
3121 if (schema != NULL) {
3122 xmlSchemaFree(schema);
3123 schema = NULL;
3124 }
3125 }
3126 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003127#ifdef DEBUG
3128 if (schema == NULL)
3129 xmlGenericError(xmlGenericErrorContext,
3130 "xmlSchemaParse() failed\n");
3131#endif
3132
3133 return (schema);
3134}
3135
3136/************************************************************************
3137 * *
3138 * Validating using Schemas *
3139 * *
3140 ************************************************************************/
3141
3142/************************************************************************
3143 * *
3144 * Reading/Writing Schemas *
3145 * *
3146 ************************************************************************/
3147
3148/**
3149 * xmlSchemaNewParserCtxt:
3150 * @URL: the location of the schema
3151 *
3152 * Create an XML Schemas parse context for that file/resource expected
3153 * to contain an XML Schemas file.
3154 *
3155 * Returns the parser context or NULL in case of error
3156 */
3157xmlSchemaParserCtxtPtr
3158xmlSchemaNewParserCtxt(const char *URL) {
3159 xmlSchemaParserCtxtPtr ret;
3160
3161 if (URL == NULL)
3162 return(NULL);
3163
3164 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3165 if (ret == NULL) {
3166 xmlGenericError(xmlGenericErrorContext,
3167 "Failed to allocate new schama parser context for %s\n", URL);
3168 return (NULL);
3169 }
3170 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3171 ret->URL = xmlStrdup((const xmlChar *)URL);
3172 return (ret);
3173}
3174
3175/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003176 * xmlSchemaNewMemParserCtxt:
3177 * @buffer: a pointer to a char array containing the schemas
3178 * @size: the size of the array
3179 *
3180 * Create an XML Schemas parse context for that memory buffer expected
3181 * to contain an XML Schemas file.
3182 *
3183 * Returns the parser context or NULL in case of error
3184 */
3185xmlSchemaParserCtxtPtr
3186xmlSchemaNewMemParserCtxt(const char *buffer, int size) {
3187 xmlSchemaParserCtxtPtr ret;
3188
3189 if ((buffer == NULL) || (size <= 0))
3190 return(NULL);
3191
3192 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3193 if (ret == NULL) {
3194 xmlGenericError(xmlGenericErrorContext,
3195 "Failed to allocate new schama parser context\n");
3196 return (NULL);
3197 }
3198 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3199 ret->buffer = buffer;
3200 ret->size = size;
3201 return (ret);
3202}
3203
3204/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003205 * xmlSchemaFreeParserCtxt:
3206 * @ctxt: the schema parser context
3207 *
3208 * Free the resources associated to the schema parser context
3209 */
3210void
3211xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) {
3212 if (ctxt == NULL)
3213 return;
3214 if (ctxt->URL != NULL)
3215 xmlFree(ctxt->URL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003216 if (ctxt->doc != NULL)
3217 xmlFreeDoc(ctxt->doc);
Daniel Veillard4255d502002-04-16 15:50:10 +00003218 xmlFree(ctxt);
3219}
3220
3221/************************************************************************
3222 * *
3223 * Building the content models *
3224 * *
3225 ************************************************************************/
3226/**
3227 * xmlSchemaBuildAContentModel:
3228 * @type: the schema type definition
3229 * @ctxt: the schema parser context
3230 * @name: the element name whose content is being built
3231 *
3232 * Generate the automata sequence needed for that type
3233 */
3234static void
3235xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
3236 xmlSchemaParserCtxtPtr ctxt,
3237 const xmlChar *name) {
3238 if (type == NULL) {
3239 xmlGenericError(xmlGenericErrorContext,
3240 "Found unexpected type = NULL in %s content model\n",
3241 name);
3242 return;
3243 }
3244 switch (type->type) {
3245 case XML_SCHEMA_TYPE_ANY:
3246 /* TODO : handle the namespace too */
3247 /* TODO : make that a specific transition type */
3248 TODO
3249 ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state,
3250 NULL, BAD_CAST "*", NULL);
3251 break;
3252 case XML_SCHEMA_TYPE_ELEMENT: {
3253 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
3254 /* TODO : handle the namespace too */
3255 xmlAutomataStatePtr oldstate = ctxt->state;
3256 if (elem->maxOccurs >= UNBOUNDED) {
Daniel Veillard32370232002-10-16 14:08:14 +00003257 if (elem->minOccurs > 1) {
3258 xmlAutomataStatePtr tmp;
3259 int counter;
3260
3261 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3262 oldstate, NULL);
3263 oldstate = ctxt->state;
3264
3265 counter = xmlAutomataNewCounter(ctxt->am,
3266 elem->minOccurs - 1, UNBOUNDED);
3267
3268 if (elem->refDecl != NULL) {
3269 xmlSchemaBuildAContentModel(
3270 (xmlSchemaTypePtr) elem->refDecl,
3271 ctxt, elem->refDecl->name);
3272 } else {
3273 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3274 ctxt->state, NULL, elem->name, type);
3275 }
3276 tmp = ctxt->state;
3277 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3278 counter);
3279 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3280 NULL, counter);
3281
3282 } else {
3283 if (elem->refDecl != NULL) {
3284 xmlSchemaBuildAContentModel(
3285 (xmlSchemaTypePtr) elem->refDecl,
3286 ctxt, elem->refDecl->name);
3287 } else {
3288 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3289 ctxt->state, NULL, elem->name, type);
3290 }
3291 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3292 if (elem->minOccurs == 0) {
3293 /* basically an elem* */
3294 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3295 }
3296 }
3297 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3298 xmlAutomataStatePtr tmp;
3299 int counter;
3300
3301 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3302 oldstate, NULL);
3303 oldstate = ctxt->state;
3304
3305 counter = xmlAutomataNewCounter(ctxt->am,
3306 elem->minOccurs - 1, elem->maxOccurs - 1);
3307
Daniel Veillard4255d502002-04-16 15:50:10 +00003308 if (elem->refDecl != NULL) {
3309 xmlSchemaBuildAContentModel(
3310 (xmlSchemaTypePtr) elem->refDecl,
3311 ctxt, elem->refDecl->name);
3312 } else {
3313 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3314 ctxt->state, NULL, elem->name, type);
3315 }
Daniel Veillard32370232002-10-16 14:08:14 +00003316 tmp = ctxt->state;
3317 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3318 counter);
3319 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3320 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00003321 if (elem->minOccurs == 0) {
3322 /* basically an elem? */
3323 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3324 }
Daniel Veillard32370232002-10-16 14:08:14 +00003325
Daniel Veillard4255d502002-04-16 15:50:10 +00003326 } else {
3327 if (elem->refDecl != NULL) {
3328 xmlSchemaBuildAContentModel(
3329 (xmlSchemaTypePtr) elem->refDecl,
3330 ctxt, elem->refDecl->name);
3331 } else {
3332 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3333 ctxt->state, NULL, elem->name, type);
3334 }
3335 if (elem->minOccurs == 0) {
3336 /* basically an elem? */
3337 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3338 }
3339 }
3340 break;
3341 }
3342 case XML_SCHEMA_TYPE_SEQUENCE: {
3343 xmlSchemaTypePtr subtypes;
3344
3345 /*
Daniel Veillardb39bc392002-10-26 19:29:51 +00003346 * If max and min occurances are default (1) then
3347 * simply iterate over the subtypes
Daniel Veillard4255d502002-04-16 15:50:10 +00003348 */
Daniel Veillardb39bc392002-10-26 19:29:51 +00003349 if ((type->minOccurs == 1 ) && (type->maxOccurs == 1)) {
3350 subtypes = type->subtypes;
3351 while (subtypes != NULL) {
3352 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3353 subtypes = subtypes->next;
3354 }
3355 } else {
3356 xmlAutomataStatePtr oldstate = ctxt->state;
3357 if (type->maxOccurs >= UNBOUNDED) {
3358 if (type->minOccurs > 1) {
3359 xmlAutomataStatePtr tmp;
3360 int counter;
3361
3362 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3363 oldstate, NULL);
3364 oldstate = ctxt->state;
3365
3366 counter = xmlAutomataNewCounter(ctxt->am,
3367 type->minOccurs - 1, UNBOUNDED);
3368
3369 subtypes = type->subtypes;
3370 while (subtypes != NULL) {
3371 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3372 subtypes = subtypes->next;
3373 }
3374 tmp = ctxt->state;
3375 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3376 counter);
3377 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3378 NULL, counter);
3379
3380 } else {
3381 subtypes = type->subtypes;
3382 while (subtypes != NULL) {
3383 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3384 subtypes = subtypes->next;
3385 }
3386 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3387 if (type->minOccurs == 0) {
3388 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3389 ctxt->state);
3390 }
3391 }
3392 } else if ((type->maxOccurs > 1) || (type->minOccurs > 1)) {
3393 xmlAutomataStatePtr tmp;
3394 int counter;
3395
3396 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3397 oldstate, NULL);
3398 oldstate = ctxt->state;
3399
3400 counter = xmlAutomataNewCounter(ctxt->am,
3401 type->minOccurs - 1, type->maxOccurs - 1);
3402
3403 subtypes = type->subtypes;
3404 while (subtypes != NULL) {
3405 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3406 subtypes = subtypes->next;
3407 }
3408 tmp = ctxt->state;
3409 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3410 counter);
3411 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3412 NULL, counter);
3413 if (type->minOccurs == 0) {
3414 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3415 }
3416
3417 } else {
3418 subtypes = type->subtypes;
3419 while (subtypes != NULL) {
3420 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3421 subtypes = subtypes->next;
3422 }
3423 if (type->minOccurs == 0) {
3424 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3425 }
3426 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003427 }
3428 break;
3429 }
3430 case XML_SCHEMA_TYPE_CHOICE: {
3431 xmlSchemaTypePtr subtypes;
3432 xmlAutomataStatePtr start, end;
3433
3434 start = ctxt->state;
3435 end = xmlAutomataNewState(ctxt->am);
3436
3437 /*
3438 * iterate over the subtypes and remerge the end with an
3439 * epsilon transition
3440 */
Daniel Veillardb509f152002-04-17 16:28:10 +00003441 if (type->maxOccurs == 1) {
3442 subtypes = type->subtypes;
3443 while (subtypes != NULL) {
3444 ctxt->state = start;
3445 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3446 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3447 subtypes = subtypes->next;
3448 }
3449 } else {
3450 int counter;
3451 xmlAutomataStatePtr hop;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003452 int maxOccurs = type->maxOccurs == UNBOUNDED ?
3453 UNBOUNDED : type->maxOccurs - 1;
3454 int minOccurs = type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillardb509f152002-04-17 16:28:10 +00003455
3456 /*
3457 * use a counter to keep track of the number of transtions
3458 * which went through the choice.
3459 */
Daniel Veillardb39bc392002-10-26 19:29:51 +00003460 counter = xmlAutomataNewCounter(ctxt->am, minOccurs, maxOccurs);
Daniel Veillardb509f152002-04-17 16:28:10 +00003461 hop = xmlAutomataNewState(ctxt->am);
3462
3463 subtypes = type->subtypes;
3464 while (subtypes != NULL) {
3465 ctxt->state = start;
3466 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3467 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3468 subtypes = subtypes->next;
3469 }
3470 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3471 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3472 }
3473 if (type->minOccurs == 0) {
3474 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003475 }
3476 ctxt->state = end;
3477 break;
3478 }
3479 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003480 xmlAutomataStatePtr start;
3481 xmlSchemaTypePtr subtypes;
3482 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard441bc322002-04-20 17:38:48 +00003483 int lax;
Daniel Veillard7646b182002-04-20 06:41:40 +00003484
3485 subtypes = type->subtypes;
3486 if (subtypes == NULL)
3487 break;
3488 start = ctxt->state;
3489 while (subtypes != NULL) {
3490 ctxt->state = start;
3491 elem = (xmlSchemaElementPtr) subtypes;
3492
3493 /* TODO : handle the namespace too */
Daniel Veillard37fc84d2003-05-09 19:38:15 +00003494 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
3495 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3496 elem->name, 1, 1, subtypes);
3497 } else {
3498 xmlAutomataNewCountTrans(ctxt->am, ctxt->state, ctxt->state,
3499 elem->name, elem->minOccurs,
3500 elem->maxOccurs, subtypes);
3501 }
Daniel Veillard7646b182002-04-20 06:41:40 +00003502 subtypes = subtypes->next;
3503 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003504 lax = type->minOccurs == 0;
3505 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3506 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003507 break;
3508 }
3509 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003510 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003511 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3512 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003513 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003514 if (type->baseType != NULL) {
3515 xmlSchemaTypePtr subtypes;
3516
3517 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3518 subtypes = type->subtypes;
3519 while (subtypes != NULL) {
3520 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3521 subtypes = subtypes->next;
3522 }
3523 } else if (type->subtypes != NULL)
3524 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3525 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003526 case XML_SCHEMA_TYPE_GROUP:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003527 if (type->subtypes == NULL) {
3528 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003529 case XML_SCHEMA_TYPE_COMPLEX:
3530 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3531 if (type->subtypes != NULL)
3532 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3533 break;
3534 default:
3535 xmlGenericError(xmlGenericErrorContext,
3536 "Found unexpected type %d in %s content model\n",
3537 type->type, name);
3538 return;
3539 }
3540}
3541/**
3542 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003543 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00003544 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003545 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00003546 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003547 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00003548 */
3549static void
3550xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3551 xmlSchemaParserCtxtPtr ctxt,
3552 const xmlChar *name) {
3553 xmlAutomataStatePtr start;
3554
Daniel Veillard4255d502002-04-16 15:50:10 +00003555 if (elem->contModel != NULL)
3556 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003557 if (elem->subtypes == NULL) {
3558 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003559 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003560 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003561 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3562 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003563 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3564 return;
3565
3566#ifdef DEBUG_CONTENT
3567 xmlGenericError(xmlGenericErrorContext,
3568 "Building content model for %s\n", name);
3569#endif
3570
Daniel Veillard4255d502002-04-16 15:50:10 +00003571 ctxt->am = xmlNewAutomata();
3572 if (ctxt->am == NULL) {
3573 xmlGenericError(xmlGenericErrorContext,
3574 "Cannot create automata for elem %s\n", name);
3575 return;
3576 }
3577 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3578 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3579 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003580 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003581 if (elem->contModel == NULL) {
3582 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3583 if ((ctxt != NULL) && (ctxt->error != NULL))
3584 ctxt->error(ctxt->userData,
3585 "failed to compile %s content model\n",
3586 name);
3587 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
3588 ctxt->nberrors++;
3589 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
3590 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3591 if ((ctxt != NULL) && (ctxt->error != NULL))
3592 ctxt->error(ctxt->userData,
Daniel Veillarde19fc232002-04-22 16:01:24 +00003593 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003594 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003595 ctxt->nberrors++;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003596 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00003597#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillarde19fc232002-04-22 16:01:24 +00003598 xmlGenericError(xmlGenericErrorContext,
3599 "Content model of %s:\n", name);
3600 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003601#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00003602 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00003603 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003604 xmlFreeAutomata(ctxt->am);
3605 ctxt->am = NULL;
3606}
3607
3608/**
3609 * xmlSchemaRefFixupCallback:
3610 * @elem: the schema element context
3611 * @ctxt: the schema parser context
3612 *
3613 * Free the resources associated to the schema parser context
3614 */
3615static void
3616xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3617 xmlSchemaParserCtxtPtr ctxt,
3618 const xmlChar *name,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00003619 const xmlChar *context ATTRIBUTE_UNUSED,
3620 const xmlChar *namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00003621{
3622 if ((ctxt == NULL) || (elem == NULL))
3623 return;
3624 if (elem->ref != NULL) {
3625 xmlSchemaElementPtr elemDecl;
3626
3627 if (elem->subtypes != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003628 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003629 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3630 if ((ctxt != NULL) && (ctxt->error != NULL))
3631 ctxt->error(ctxt->userData,
3632 "Schemas: element %s have both ref and subtype\n",
3633 name);
3634 return;
3635 }
3636 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3637 elem->ref, elem->refNs);
3638
3639 if (elemDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003640 ctxt->nberrors++;
3641 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003642 if ((ctxt != NULL) && (ctxt->error != NULL))
3643 ctxt->error(ctxt->userData,
3644 "Schemas: element %s ref to %s not found\n",
3645 name, elem->ref);
3646 return;
3647 }
3648 elem->refDecl = elemDecl;
3649 } else if (elem->namedType != NULL) {
3650 xmlSchemaTypePtr typeDecl;
3651
3652 if (elem->subtypes != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003653 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003654 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3655 if ((ctxt != NULL) && (ctxt->error != NULL))
3656 ctxt->error(ctxt->userData,
3657 "Schemas: element %s have both type and subtype\n",
3658 name);
3659 return;
3660 }
3661 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3662 elem->namedTypeNs);
3663
3664 if (typeDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003665 ctxt->nberrors++;
3666 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003667 if ((ctxt != NULL) && (ctxt->error != NULL))
3668 ctxt->error(ctxt->userData,
3669 "Schemas: element %s type %s not found\n",
3670 name, elem->namedType);
3671 return;
3672 }
3673 elem->subtypes = typeDecl;
3674 }
3675}
3676
3677/**
3678 * xmlSchemaTypeFixup:
3679 * @typeDecl: the schema type definition
3680 * @ctxt: the schema parser context
3681 *
3682 * Fixes the content model of the type.
3683 */
3684static void
3685xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3686 xmlSchemaParserCtxtPtr ctxt,
3687 const xmlChar *name)
3688{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003689 if (typeDecl == NULL)
3690 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003691 if (name == NULL)
3692 name = typeDecl->name;
3693 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3694 switch (typeDecl->type) {
3695 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3696 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003697 if (typeDecl->subtypes != NULL)
3698 typeDecl->contentType = typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003699 break;
3700 }
3701 case XML_SCHEMA_TYPE_RESTRICTION: {
3702 if (typeDecl->subtypes != NULL)
3703 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3704
3705 if (typeDecl->base != NULL) {
3706 xmlSchemaTypePtr baseType;
3707
3708 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3709 typeDecl->baseNs);
3710 if (baseType == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003711 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003712 if ((ctxt != NULL) && (ctxt->error != NULL))
3713 ctxt->error(ctxt->userData,
3714 "Schemas: type %s base type %s not found\n",
3715 name, typeDecl->base);
3716 }
3717 typeDecl->baseType = baseType;
3718 }
3719 if (typeDecl->subtypes == NULL)
3720 /* 1.1.1 */
3721 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3722 else if ((typeDecl->subtypes->subtypes == NULL) &&
3723 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3724 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3725 /* 1.1.2 */
3726 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3727 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3728 (typeDecl->subtypes->subtypes == NULL))
3729 /* 1.1.3 */
3730 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3731 else {
3732 /* 1.2 and 2.X are applied at the other layer */
3733 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3734 }
3735 break;
3736 }
3737 case XML_SCHEMA_TYPE_EXTENSION: {
3738 xmlSchemaContentType explicitContentType;
3739 xmlSchemaTypePtr base;
3740
3741 if (typeDecl->base != NULL) {
3742 xmlSchemaTypePtr baseType;
3743
3744 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3745 typeDecl->baseNs);
3746 if (baseType == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003747 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003748 if ((ctxt != NULL) && (ctxt->error != NULL))
3749 ctxt->error(ctxt->userData,
3750 "Schemas: type %s base type %s not found\n",
3751 name, typeDecl->base);
3752 }
3753 typeDecl->baseType = baseType;
3754 }
3755 if (typeDecl->subtypes != NULL)
3756 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3757
Daniel Veillard8651f532002-04-17 09:06:27 +00003758 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003759 if (typeDecl->subtypes == NULL)
3760 /* 1.1.1 */
3761 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3762 else if ((typeDecl->subtypes->subtypes == NULL) &&
3763 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3764 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3765 /* 1.1.2 */
3766 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3767 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3768 (typeDecl->subtypes->subtypes == NULL))
3769 /* 1.1.3 */
3770 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3771
3772 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3773 typeDecl->baseNs);
3774 if (base == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003775 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00003776 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3777 if ((ctxt != NULL) && (ctxt->error != NULL))
3778 ctxt->error(ctxt->userData,
3779 "Schemas: base type %s of type %s not found\n",
3780 typeDecl->base, name);
3781 return;
3782 }
3783 xmlSchemaTypeFixup(base, ctxt, NULL);
3784 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3785 /* 2.1 */
3786 typeDecl->contentType = base->contentType;
3787 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3788 /* 2.2 imbitable ! */
3789 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3790 } else {
3791 /* 2.3 imbitable pareil ! */
3792 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3793 }
3794 break;
3795 }
3796 case XML_SCHEMA_TYPE_COMPLEX: {
3797 if (typeDecl->subtypes == NULL) {
3798 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3799 } else {
3800 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3801 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3802 else {
3803 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003804 if (typeDecl->subtypes != NULL)
3805 typeDecl->contentType =
3806 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003807 }
3808 }
3809 break;
3810 }
3811 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3812 if (typeDecl->subtypes == NULL) {
3813 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3814 } else {
3815 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3816 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3817 else {
3818 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00003819 if (typeDecl->subtypes != NULL)
3820 typeDecl->contentType =
3821 typeDecl->subtypes->contentType;
Daniel Veillard4255d502002-04-16 15:50:10 +00003822 }
3823 }
3824 break;
3825 }
3826 case XML_SCHEMA_TYPE_SEQUENCE:
3827 case XML_SCHEMA_TYPE_GROUP:
3828 case XML_SCHEMA_TYPE_ALL:
3829 case XML_SCHEMA_TYPE_CHOICE:
3830 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3831 break;
3832 case XML_SCHEMA_TYPE_BASIC:
3833 case XML_SCHEMA_TYPE_ANY:
3834 case XML_SCHEMA_TYPE_FACET:
3835 case XML_SCHEMA_TYPE_SIMPLE:
3836 case XML_SCHEMA_TYPE_UR:
3837 case XML_SCHEMA_TYPE_ELEMENT:
3838 case XML_SCHEMA_TYPE_ATTRIBUTE:
Daniel Veillard118aed72002-09-24 14:13:13 +00003839 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
Daniel Veillard4255d502002-04-16 15:50:10 +00003840 case XML_SCHEMA_TYPE_NOTATION:
3841 case XML_SCHEMA_TYPE_LIST:
3842 case XML_SCHEMA_TYPE_UNION:
3843 case XML_SCHEMA_FACET_MININCLUSIVE:
3844 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3845 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3846 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3847 case XML_SCHEMA_FACET_TOTALDIGITS:
3848 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3849 case XML_SCHEMA_FACET_PATTERN:
3850 case XML_SCHEMA_FACET_ENUMERATION:
3851 case XML_SCHEMA_FACET_WHITESPACE:
3852 case XML_SCHEMA_FACET_LENGTH:
3853 case XML_SCHEMA_FACET_MAXLENGTH:
3854 case XML_SCHEMA_FACET_MINLENGTH:
3855 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3856 break;
3857 }
3858 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003859#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003860 if (typeDecl->node != NULL) {
3861 xmlGenericError(xmlGenericErrorContext,
3862 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3863 xmlGetLineNo(typeDecl->node));
3864 } else {
3865 xmlGenericError(xmlGenericErrorContext,
3866 "Type of %s :", name);
3867 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003868 switch (typeDecl->contentType) {
3869 case XML_SCHEMA_CONTENT_SIMPLE:
3870 xmlGenericError(xmlGenericErrorContext,
3871 "simple\n"); break;
3872 case XML_SCHEMA_CONTENT_ELEMENTS:
3873 xmlGenericError(xmlGenericErrorContext,
3874 "elements\n"); break;
3875 case XML_SCHEMA_CONTENT_UNKNOWN:
3876 xmlGenericError(xmlGenericErrorContext,
3877 "unknown !!!\n"); break;
3878 case XML_SCHEMA_CONTENT_EMPTY:
3879 xmlGenericError(xmlGenericErrorContext,
3880 "empty\n"); break;
3881 case XML_SCHEMA_CONTENT_MIXED:
3882 xmlGenericError(xmlGenericErrorContext,
3883 "mixed\n"); break;
3884 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3885 xmlGenericError(xmlGenericErrorContext,
3886 "mixed or elems\n"); break;
3887 case XML_SCHEMA_CONTENT_BASIC:
3888 xmlGenericError(xmlGenericErrorContext,
3889 "basic\n"); break;
3890 default:
3891 xmlGenericError(xmlGenericErrorContext,
3892 "not registered !!!\n"); break;
3893 }
3894#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003895}
3896
3897/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003898 * xmlSchemaCheckFacet:
3899 * @facet: the facet
3900 * @typeDecl: the schema type definition
3901 * @ctxt: the schema parser context or NULL
3902 * @name: name of the type
3903 *
3904 * Checks the default values types, especially for facets
3905 *
3906 * Returns 0 if okay or -1 in cae of error
3907 */
3908int
3909xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
3910 xmlSchemaTypePtr typeDecl,
3911 xmlSchemaParserCtxtPtr ctxt,
3912 const xmlChar *name)
3913{
3914 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3915 int ret = 0;
3916
3917 if (nonNegativeIntegerType == NULL) {
3918 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3919 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3920 }
3921 switch (facet->type) {
3922 case XML_SCHEMA_FACET_MININCLUSIVE:
3923 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3924 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3925 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3926 /*
3927 * Okay we need to validate the value
3928 * at that point.
3929 */
3930 xmlSchemaValidCtxtPtr vctxt;
3931
3932 vctxt = xmlSchemaNewValidCtxt(NULL);
3933 if (vctxt == NULL)
3934 break;
3935 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3936 facet->value);
3937 facet->val = vctxt->value;
3938 vctxt->value = NULL;
3939 if (facet->val == NULL) {
3940 /* error code */
3941 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003942 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003943 xmlSchemaErrorContext(ctxt, NULL,
3944 facet->node, NULL);
3945 ctxt->error(ctxt->userData,
3946 "Schemas: type %s facet value %s invalid\n",
3947 name, facet->value);
3948 }
3949 ret = -1;
3950 }
3951 xmlSchemaFreeValidCtxt(vctxt);
3952 break;
3953 }
3954 case XML_SCHEMA_FACET_ENUMERATION: {
3955 /*
3956 * Okay we need to validate the value
3957 * at that point.
3958 */
3959 xmlSchemaValidCtxtPtr vctxt;
3960 int tmp;
3961
3962 vctxt = xmlSchemaNewValidCtxt(NULL);
3963 if (vctxt == NULL)
3964 break;
3965 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3966 facet->value);
3967 if (tmp != 0) {
3968 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003969 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003970 xmlSchemaErrorContext(ctxt, NULL,
3971 facet->node, NULL);
3972 ctxt->error(ctxt->userData,
3973 "Schemas: type %s enumeration value %s invalid\n",
3974 name, facet->value);
3975 }
3976 ret = -1;
3977 }
3978 xmlSchemaFreeValidCtxt(vctxt);
3979 break;
3980 }
3981 case XML_SCHEMA_FACET_PATTERN:
3982 facet->regexp = xmlRegexpCompile(facet->value);
3983 if (facet->regexp == NULL) {
3984 /* error code */
3985 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003986 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003987 ctxt->error(ctxt->userData,
3988 "Schemas: type %s facet regexp %s invalid\n",
3989 name, facet->value);
3990 }
3991 ret = -1;
3992 }
3993 break;
3994 case XML_SCHEMA_FACET_TOTALDIGITS:
3995 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3996 case XML_SCHEMA_FACET_LENGTH:
3997 case XML_SCHEMA_FACET_MAXLENGTH:
3998 case XML_SCHEMA_FACET_MINLENGTH: {
3999 int tmp;
4000
4001 tmp = xmlSchemaValidatePredefinedType(
4002 nonNegativeIntegerType, facet->value,
4003 &facet->val);
4004 if (tmp != 0) {
4005 /* error code */
4006 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004007 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004008 xmlSchemaErrorContext(ctxt, NULL,
4009 facet->node, NULL);
4010 ctxt->error(ctxt->userData,
4011 "Schemas: type %s facet value %s invalid\n",
4012 name, facet->value);
4013 }
4014 ret = -1;
4015 }
4016 break;
4017 }
4018 case XML_SCHEMA_FACET_WHITESPACE: {
4019 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
4020 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4021 } else if (xmlStrEqual(facet->value,
4022 BAD_CAST"replace")) {
4023 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4024 } else if (xmlStrEqual(facet->value,
4025 BAD_CAST"collapse")) {
4026 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4027 } else {
4028 if (ctxt != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004029 ctxt->nberrors++;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004030 xmlSchemaErrorContext(ctxt, NULL,
4031 facet->node, NULL);
4032 ctxt->error(ctxt->userData,
4033 "Schemas: type %s whiteSpace value %s invalid\n",
4034 name, facet->value);
4035 }
4036 ret = -1;
4037 }
4038 }
4039 default:
4040 break;
4041 }
4042 return(ret);
4043}
4044
4045/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004046 * xmlSchemaCheckDefaults:
4047 * @typeDecl: the schema type definition
4048 * @ctxt: the schema parser context
4049 *
4050 * Checks the default values types, especially for facets
4051 */
4052static void
4053xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
4054 xmlSchemaParserCtxtPtr ctxt,
4055 const xmlChar *name)
4056{
Daniel Veillard4255d502002-04-16 15:50:10 +00004057 if (name == NULL)
4058 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004059 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
4060 if (typeDecl->facets != NULL) {
4061 xmlSchemaFacetPtr facet = typeDecl->facets;
4062 while (facet != NULL) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004063 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004064 facet = facet->next;
4065 }
4066 }
4067 }
4068}
4069
4070/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004071 * xmlSchemaAttrGrpFixup:
4072 * @attrgrpDecl: the schema attribute definition
4073 * @ctxt: the schema parser context
4074 * @name: the attribute name
4075 *
4076 * Fixes finish doing the computations on the attributes definitions
4077 */
4078static void
4079xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
4080 xmlSchemaParserCtxtPtr ctxt,
4081 const xmlChar *name)
4082{
4083 if (name == NULL)
4084 name = attrgrpDecl->name;
4085 if (attrgrpDecl->attributes != NULL)
4086 return;
4087 if (attrgrpDecl->ref != NULL) {
4088 xmlSchemaAttributeGroupPtr ref;
4089
4090 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4091 attrgrpDecl->refNs);
4092 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004093 ctxt->nberrors++;
4094 xmlSchemaErrorContext(ctxt, NULL, attrgrpDecl->node, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004095 if ((ctxt != NULL) && (ctxt->error != NULL))
4096 ctxt->error(ctxt->userData,
4097 "Schemas: attribute group %s reference %s not found\n",
4098 name, attrgrpDecl->ref);
4099 return;
4100 }
4101 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4102 attrgrpDecl->attributes = ref->attributes;
4103 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004104 ctxt->nberrors++;
4105 xmlSchemaErrorContext(ctxt, NULL, attrgrpDecl->node, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004106 if ((ctxt != NULL) && (ctxt->error != NULL))
4107 ctxt->error(ctxt->userData,
4108 "Schemas: attribute %s has no attributes nor reference\n",
4109 name);
4110 }
4111}
4112
4113/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004114 * xmlSchemaAttrFixup:
4115 * @attrDecl: the schema attribute definition
4116 * @ctxt: the schema parser context
4117 * @name: the attribute name
4118 *
4119 * Fixes finish doing the computations on the attributes definitions
4120 */
4121static void
4122xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
4123 xmlSchemaParserCtxtPtr ctxt,
4124 const xmlChar *name)
4125{
4126 if (name == NULL)
4127 name = attrDecl->name;
4128 if (attrDecl->subtypes != NULL)
4129 return;
4130 if (attrDecl->typeName != NULL) {
4131 xmlSchemaTypePtr type;
4132
4133 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4134 attrDecl->typeNs);
4135 if (type == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004136 ctxt->nberrors++;
4137 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004138 if ((ctxt != NULL) && (ctxt->error != NULL))
4139 ctxt->error(ctxt->userData,
4140 "Schemas: attribute %s type %s not found\n",
4141 name, attrDecl->typeName);
4142 }
4143 attrDecl->subtypes = type;
4144 } else if (attrDecl->ref != NULL) {
4145 xmlSchemaAttributePtr ref;
4146
4147 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4148 attrDecl->refNs);
4149 if (ref == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004150 ctxt->nberrors++;
4151 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004152 if ((ctxt != NULL) && (ctxt->error != NULL))
4153 ctxt->error(ctxt->userData,
4154 "Schemas: attribute %s reference %s not found\n",
4155 name, attrDecl->ref);
4156 return;
4157 }
4158 xmlSchemaAttrFixup(ref, ctxt, NULL);
4159 attrDecl->subtypes = ref->subtypes;
4160 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004161 ctxt->nberrors++;
4162 xmlSchemaErrorContext(ctxt, NULL, attrDecl->node, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004163 if ((ctxt != NULL) && (ctxt->error != NULL))
4164 ctxt->error(ctxt->userData,
4165 "Schemas: attribute %s has no type nor reference\n",
4166 name);
4167 }
4168}
4169
4170/**
4171 * xmlSchemaParse:
4172 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004173 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004174 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004175 * XML Shema struture which can be used to validate instances.
4176 * *WARNING* this interface is highly subject to change
4177 *
4178 * Returns the internal XML Schema structure built from the resource or
4179 * NULL in case of error
4180 */
4181xmlSchemaPtr
4182xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4183{
4184 xmlSchemaPtr ret = NULL;
4185 xmlDocPtr doc;
4186 xmlNodePtr root, cur, delete;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004187 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00004188
4189 xmlSchemaInitTypes();
4190
Daniel Veillard6045c902002-10-09 21:13:59 +00004191 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004192 return (NULL);
4193
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004194 nberrors = ctxt->nberrors;
4195 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004196 ctxt->counter = 0;
4197 ctxt->container = NULL;
4198
4199 /*
4200 * First step is to parse the input document into an DOM/Infoset
4201 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004202 if (ctxt->URL != NULL) {
4203 doc = xmlParseFile((const char *) ctxt->URL);
4204 if (doc == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004205 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004206 if (ctxt->error != NULL)
4207 ctxt->error(ctxt->userData,
4208 "xmlSchemaParse: could not load %s\n", ctxt->URL);
4209 return (NULL);
4210 }
4211 } else if (ctxt->buffer != NULL) {
4212 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
4213 if (doc == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004214 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004215 if (ctxt->error != NULL)
4216 ctxt->error(ctxt->userData,
4217 "xmlSchemaParse: could not parse schemas\n");
4218 return (NULL);
4219 }
4220 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4221 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4222 } else {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004223 ctxt->nberrors++;
Daniel Veillard6045c902002-10-09 21:13:59 +00004224 if (ctxt->error != NULL)
4225 ctxt->error(ctxt->userData,
4226 "xmlSchemaParse: nothing to parse\n");
4227 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004228 }
4229
4230 /*
4231 * Then extract the root and Schema parse it
4232 */
4233 root = xmlDocGetRootElement(doc);
4234 if (root == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004235 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004236 if (ctxt->error != NULL)
4237 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
4238 ctxt->URL);
4239 return (NULL);
4240 }
4241
4242 /*
4243 * Remove all the blank text nodes
4244 */
4245 delete = NULL;
4246 cur = root;
4247 while (cur != NULL) {
4248 if (delete != NULL) {
4249 xmlUnlinkNode(delete);
4250 xmlFreeNode(delete);
4251 delete = NULL;
4252 }
4253 if (cur->type == XML_TEXT_NODE) {
4254 if (IS_BLANK_NODE(cur)) {
4255 if (xmlNodeGetSpacePreserve(cur) != 1) {
4256 delete = cur;
4257 }
4258 }
4259 } else if ((cur->type != XML_ELEMENT_NODE) &&
4260 (cur->type != XML_CDATA_SECTION_NODE)) {
4261 delete = cur;
4262 goto skip_children;
4263 }
4264
4265 /*
4266 * Skip to next node
4267 */
4268 if (cur->children != NULL) {
4269 if ((cur->children->type != XML_ENTITY_DECL) &&
4270 (cur->children->type != XML_ENTITY_REF_NODE) &&
4271 (cur->children->type != XML_ENTITY_NODE)) {
4272 cur = cur->children;
4273 continue;
4274 }
4275 }
4276skip_children:
4277 if (cur->next != NULL) {
4278 cur = cur->next;
4279 continue;
4280 }
4281
4282 do {
4283 cur = cur->parent;
4284 if (cur == NULL)
4285 break;
4286 if (cur == root) {
4287 cur = NULL;
4288 break;
4289 }
4290 if (cur->next != NULL) {
4291 cur = cur->next;
4292 break;
4293 }
4294 } while (cur != NULL);
4295 }
4296 if (delete != NULL) {
4297 xmlUnlinkNode(delete);
4298 xmlFreeNode(delete);
4299 delete = NULL;
4300 }
4301
4302 /*
4303 * Then do the parsing for good
4304 */
4305 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00004306 if (ret == NULL)
4307 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004308 ret->doc = doc;
4309
4310 /*
4311 * Then fix all the references.
4312 */
4313 ctxt->schema = ret;
4314 xmlHashScanFull(ret->elemDecl,
4315 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
4316
4317 /*
4318 * Then fixup all types properties
4319 */
4320 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
4321
4322 /*
4323 * Then build the content model for all elements
4324 */
4325 xmlHashScan(ret->elemDecl,
4326 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
4327
4328 /*
4329 * Then check the defaults part of the type like facets values
4330 */
4331 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
4332
4333 /*
4334 * Then fixup all attributes declarations
4335 */
4336 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4337
Daniel Veillard13e04c62002-04-23 17:51:29 +00004338 /*
4339 * Then fixup all attributes group declarations
4340 */
4341 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
4342
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004343 if (ctxt->nberrors != 0) {
4344 xmlSchemaFree(ret);
4345 ret = NULL;
4346 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004347 return (ret);
4348}
4349
4350/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004351 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00004352 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00004353 * @err: the error callback
4354 * @warn: the warning callback
4355 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00004356 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004357 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004358 */
4359void
4360xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
4361 xmlSchemaValidityErrorFunc err,
4362 xmlSchemaValidityWarningFunc warn, void *ctx) {
4363 if (ctxt == NULL)
4364 return;
4365 ctxt->error = err;
4366 ctxt->warning = warn;
4367 ctxt->userData = ctx;
4368}
4369
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004370/**
4371 * xmlSchemaFacetTypeToString:
4372 * @type: the facet type
4373 *
4374 * Convert the xmlSchemaTypeType to a char string.
4375 *
4376 * Returns the char string representation of the facet type if the
4377 * type is a facet and an "Internal Error" string otherwise.
4378 */
4379static const char *
4380xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
4381{
4382 switch (type) {
4383 case XML_SCHEMA_FACET_PATTERN:
4384 return ("pattern");
4385 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4386 return ("maxExclusive");
4387 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4388 return ("maxInclusive");
4389 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4390 return ("minExclusive");
4391 case XML_SCHEMA_FACET_MININCLUSIVE:
4392 return ("minInclusive");
4393 case XML_SCHEMA_FACET_WHITESPACE:
4394 return ("whiteSpace");
4395 case XML_SCHEMA_FACET_ENUMERATION:
4396 return ("enumeration");
4397 case XML_SCHEMA_FACET_LENGTH:
4398 return ("length");
4399 case XML_SCHEMA_FACET_MAXLENGTH:
4400 return ("maxLength");
4401 case XML_SCHEMA_FACET_MINLENGTH:
4402 return ("minLength");
4403 case XML_SCHEMA_FACET_TOTALDIGITS:
4404 return ("totalDigits");
4405 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4406 return ("fractionDigits");
4407 default:
4408 break;
4409 }
4410 return ("Internal Error");
4411}
4412
4413/**
4414 * xmlSchemaValidateFacets:
4415 * @ctxt: a schema validation context
4416 * @base: the base type
4417 * @facets: the list of facets to check
4418 * @value: the lexical repr of the value to validate
4419 * @val: the precomputed value
4420 *
4421 * Check a value against all facet conditions
4422 *
4423 * Returns 0 if the element is schemas valid, a positive error code
4424 * number otherwise and -1 in case of internal or API error.
4425 */
4426static int
4427xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
4428 xmlSchemaTypePtr base,
4429 xmlSchemaFacetPtr facets,
4430 xmlChar *value) {
4431 int ret = 0;
4432 int tmp = 0;
4433 xmlSchemaTypeType type;
4434 xmlSchemaFacetPtr facet = facets;
4435
4436 while (facet != NULL) {
4437 type = facet->type;
4438 if (type == XML_SCHEMA_FACET_ENUMERATION) {
4439 tmp = 1;
4440
4441 while (facet != NULL) {
4442 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4443 if (tmp == 0) {
4444 return 0;
4445 }
4446 facet = facet->next;
4447 }
4448 } else
4449 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
4450
4451 if (tmp != 0) {
4452 ret = tmp;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004453 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004454 if (ctxt->error != NULL)
4455 ctxt->error(ctxt->userData,
4456 "Failed to validate type with facet %s\n",
4457 xmlSchemaFacetTypeToString(type));
4458 ctxt->err = XML_SCHEMAS_ERR_FACET;
4459 }
4460 if (facet != NULL)
4461 facet = facet->next;
4462 }
4463 return (ret);
4464}
4465
Daniel Veillard4255d502002-04-16 15:50:10 +00004466/************************************************************************
4467 * *
4468 * Simple type validation *
4469 * *
4470 ************************************************************************/
4471
4472/**
4473 * xmlSchemaValidateSimpleValue:
4474 * @ctxt: a schema validation context
4475 * @type: the type declaration
4476 * @value: the value to validate
4477 *
4478 * Validate a value against a simple type
4479 *
4480 * Returns 0 if the value is valid, a positive error code
4481 * number otherwise and -1 in case of internal or API error.
4482 */
4483static int
4484xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
4485 xmlSchemaTypePtr type,
4486 xmlChar *value) {
4487 int ret = 0;
4488 /*
4489 * First normalize the value accordingly to Schema Datatype
4490 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
4491 */
4492 /*
4493 * Then check the normalized value against the lexical space of the
4494 * type.
4495 */
4496 if (type->type == XML_SCHEMA_TYPE_BASIC) {
4497 if (ctxt->value != NULL) {
4498 xmlSchemaFreeValue(ctxt->value);
4499 ctxt->value = NULL;
4500 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004501 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
4502 ctxt->cur);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004503 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004504 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004505 if (ctxt->error != NULL)
4506 ctxt->error(ctxt->userData,
4507 "Failed to validate basic type %s\n", type->name);
4508 ctxt->err = XML_SCHEMAS_ERR_VALUE;
4509 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004510 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
4511 xmlSchemaTypePtr base;
4512 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00004513
4514 base = type->baseType;
4515 if (base != NULL) {
4516 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4517 } else if (type->subtypes != NULL) {
4518
4519 }
4520 /*
4521 * Do not validate facets when working on building the Schemas
4522 */
4523 if (ctxt->schema != NULL) {
4524 if (ret == 0) {
4525 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004526 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004527 }
4528 }
4529 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4530 xmlSchemaTypePtr base;
4531
4532 base = type->subtypes;
4533 if (base != NULL) {
4534 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4535 } else {
4536 TODO
4537 }
4538 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4539 xmlSchemaTypePtr base;
4540 xmlChar *cur, *end, tmp;
4541 int ret2;
4542
4543 base = type->subtypes;
4544 if (base == NULL) {
4545 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004546 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004547 if (ctxt->error != NULL) {
4548 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4549 ctxt->error(ctxt->userData,
4550 "Internal: List type %s has no base type\n",
4551 type->name);
4552 }
4553 return(-1);
4554 }
4555 cur = value;
4556 do {
4557 while (IS_BLANK(*cur)) cur++;
4558 end = cur;
4559 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4560 if (end == cur)
4561 break;
4562 tmp = *end;
4563 *end = 0;
4564 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4565 if (ret2 != 0)
4566 ret = 1;
4567 *end = tmp;
4568 cur = end;
4569 } while (*cur != 0);
4570 } else {
4571 TODO
4572 }
4573 return(ret);
4574}
4575
4576/************************************************************************
4577 * *
4578 * DOM Validation code *
4579 * *
4580 ************************************************************************/
4581
4582static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4583 xmlNodePtr node);
4584static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4585 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4586static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4587 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4588
4589/**
4590 * xmlSchemaRegisterAttributes:
4591 * @ctxt: a schema validation context
4592 * @attrs: a list of attributes
4593 *
4594 * Register the list of attributes as the set to be validated on that element
4595 *
4596 * Returns -1 in case of error, 0 otherwise
4597 */
4598static int
4599xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4600 xmlAttrPtr attrs) {
4601 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004602 if ((attrs->ns != NULL) &&
4603 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4604 attrs = attrs->next;
4605 continue;
4606 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004607 if (ctxt->attrNr >= ctxt->attrMax) {
4608 xmlSchemaAttrStatePtr tmp;
4609
4610 ctxt->attrMax *= 2;
4611 tmp = (xmlSchemaAttrStatePtr)
4612 xmlRealloc(ctxt->attr, ctxt->attrMax *
4613 sizeof(xmlSchemaAttrState));
4614 if (tmp == NULL) {
4615 ctxt->attrMax /= 2;
4616 return(-1);
4617 }
4618 ctxt->attr = tmp;
4619 }
4620 ctxt->attr[ctxt->attrNr].attr = attrs;
4621 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4622 ctxt->attrNr++;
4623 attrs = attrs->next;
4624 }
4625 return(0);
4626}
4627
4628/**
4629 * xmlSchemaCheckAttributes:
4630 * @ctxt: a schema validation context
4631 * @node: the node carrying it.
4632 *
4633 * Check that the registered set of attributes on the current node
4634 * has been properly validated.
4635 *
4636 * Returns 0 if validity constraints are met, 1 otherwise.
4637 */
4638static int
4639xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4640 int ret = 0;
4641 int i;
4642
4643 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4644 if (ctxt->attr[i].attr == NULL)
4645 break;
4646 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4647 ret = 1;
4648 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004649 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004650 if (ctxt->error != NULL)
4651 ctxt->error(ctxt->userData,
4652 "Attribute %s on %s is unknown\n",
4653 ctxt->attr[i].attr->name,
4654 node->name);
4655 }
4656 }
4657 return(ret);
4658}
4659
4660/**
4661 * xmlSchemaValidateSimpleContent:
4662 * @ctxt: a schema validation context
4663 * @elem: an element
4664 * @type: the type declaration
4665 *
4666 * Validate the content of an element expected to be a simple type
4667 *
4668 * Returns 0 if the element is schemas valid, a positive error code
4669 * number otherwise and -1 in case of internal or API error.
4670 */
4671static int
4672xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004673 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillard4255d502002-04-16 15:50:10 +00004674 xmlNodePtr child;
4675 xmlSchemaTypePtr type, base;
4676 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004677 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004678
4679 child = ctxt->node;
4680 type = ctxt->type;
4681
4682 /*
4683 * Validation Rule: Element Locally Valid (Type): 3.1.3
4684 */
4685 value = xmlNodeGetContent(child);
4686 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4687 switch (type->type) {
4688 case XML_SCHEMA_TYPE_RESTRICTION: {
4689 xmlSchemaFacetPtr facet;
4690
4691 base = type->baseType;
4692 if (base != NULL) {
4693 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4694 } else {
4695 TODO
4696 }
4697 if (ret == 0) {
4698 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004699 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillard4255d502002-04-16 15:50:10 +00004700 }
4701 break;
4702 }
4703 default:
4704 TODO
4705 }
4706 if (value != NULL)
4707 xmlFree(value);
4708
4709 return(ret);
4710}
4711
4712/**
4713 * xmlSchemaValidateCheckNodeList
4714 * @nodelist: the list of nodes
4715 *
4716 * Check the node list is only made of text nodes and entities pointing
4717 * to text nodes
4718 *
4719 * Returns 1 if true, 0 if false and -1 in case of error
4720 */
4721static int
4722xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4723 while (nodelist != NULL) {
4724 if (nodelist->type == XML_ENTITY_REF_NODE) {
4725 TODO /* implement recursion in the entity content */
4726 }
4727 if ((nodelist->type != XML_TEXT_NODE) &&
4728 (nodelist->type != XML_COMMENT_NODE) &&
4729 (nodelist->type != XML_PI_NODE) &&
4730 (nodelist->type != XML_PI_NODE)) {
4731 return(0);
4732 }
4733 nodelist = nodelist->next;
4734 }
4735 return(1);
4736}
4737
4738/**
4739 * xmlSchemaSkipIgnored:
4740 * @ctxt: a schema validation context
4741 * @type: the current type context
4742 * @node: the top node.
4743 *
4744 * Skip ignorable nodes in that context
4745 *
4746 * Returns the new sibling
4747 * number otherwise and -1 in case of internal or API error.
4748 */
4749static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004750xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004751 xmlSchemaTypePtr type,
4752 xmlNodePtr node) {
4753 int mixed = 0;
4754 /*
4755 * TODO complete and handle entities
4756 */
4757 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4758 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4759 while ((node != NULL) &&
4760 ((node->type == XML_COMMENT_NODE) ||
4761 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4762 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4763 (node->type == XML_TEXT_NODE) &&
4764 (IS_BLANK_NODE(node)))))) {
4765 node = node->next;
4766 }
4767 return(node);
4768}
4769
4770/**
4771 * xmlSchemaValidateCallback:
4772 * @ctxt: a schema validation context
4773 * @name: the name of the element detected (might be NULL)
4774 * @type: the type
4775 *
4776 * A transition has been made in the automata associated to an element
4777 * content model
4778 */
4779static void
4780xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00004781 const xmlChar *name ATTRIBUTE_UNUSED,
Daniel Veillard4255d502002-04-16 15:50:10 +00004782 xmlSchemaTypePtr type,
4783 xmlNodePtr node) {
4784 xmlSchemaTypePtr oldtype = ctxt->type;
4785 xmlNodePtr oldnode = ctxt->node;
4786#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004787 xmlGenericError(xmlGenericErrorContext,
4788 "xmlSchemaValidateCallback: %s, %s, %s\n",
4789 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004790#endif
4791 ctxt->type = type;
4792 ctxt->node = node;
4793 xmlSchemaValidateContent(ctxt, node);
4794 ctxt->type = oldtype;
4795 ctxt->node = oldnode;
4796}
4797
4798
4799#if 0
4800/**
4801 * xmlSchemaValidateSimpleRestrictionType:
4802 * @ctxt: a schema validation context
4803 * @node: the top node.
4804 *
4805 * Validate the content of a restriction type.
4806 *
4807 * Returns 0 if the element is schemas valid, a positive error code
4808 * number otherwise and -1 in case of internal or API error.
4809 */
4810static int
4811xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4812 xmlNodePtr node)
4813{
4814 xmlNodePtr child;
4815 xmlSchemaTypePtr type;
4816 int ret;
4817
4818 child = ctxt->node;
4819 type = ctxt->type;
4820
4821 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004822 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004823 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4824 if (ctxt->error != NULL)
4825 ctxt->error(ctxt->userData,
4826 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4827 node->name);
4828 return (-1);
4829 }
4830 /*
4831 * Only text and text based entities references shall be found there
4832 */
4833 ret = xmlSchemaValidateCheckNodeList(child);
4834 if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004835 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004836 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4837 if (ctxt->error != NULL)
4838 ctxt->error(ctxt->userData,
4839 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4840 node->name);
4841 return (-1);
4842 } else if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004843 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004844 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4845 if (ctxt->error != NULL)
4846 ctxt->error(ctxt->userData,
4847 "Element %s content is not a simple type\n",
4848 node->name);
4849 return (-1);
4850 }
4851 ctxt->type = type->subtypes;
4852 xmlSchemaValidateContent(ctxt, node);
4853 ctxt->type = type;
4854 return (ret);
4855}
4856#endif
4857
4858/**
4859 * xmlSchemaValidateSimpleType:
4860 * @ctxt: a schema validation context
4861 * @node: the top node.
4862 *
4863 * Validate the content of an simple type.
4864 *
4865 * Returns 0 if the element is schemas valid, a positive error code
4866 * number otherwise and -1 in case of internal or API error.
4867 */
4868static int
4869xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4870 xmlNodePtr child;
4871 xmlSchemaTypePtr type;
4872 xmlAttrPtr attr;
4873 int ret;
4874
4875 child = ctxt->node;
4876 type = ctxt->type;
4877
4878 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004879 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004880 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4881 if (ctxt->error != NULL)
4882 ctxt->error(ctxt->userData,
4883 "Internal error: xmlSchemaValidateSimpleType %s\n",
4884 node->name);
4885 return(-1);
4886 }
4887 /*
4888 * Only text and text based entities references shall be found there
4889 */
4890 ret = xmlSchemaValidateCheckNodeList(child);
4891 if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004892 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004893 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4894 if (ctxt->error != NULL)
4895 ctxt->error(ctxt->userData,
4896 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4897 node->name);
4898 return(-1);
4899 } else if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004900 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004901 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4902 if (ctxt->error != NULL)
4903 ctxt->error(ctxt->userData,
4904 "Element %s content is not a simple type\n",
4905 node->name);
4906 return(-1);
4907 }
4908 /*
4909 * Validation Rule: Element Locally Valid (Type): 3.1.1
4910 */
4911 attr = node->properties;
4912 while (attr != NULL) {
4913 if ((attr->ns == NULL) ||
4914 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4915 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4916 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4917 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4918 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4919 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004920 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004921 if (ctxt->error != NULL)
4922 ctxt->error(ctxt->userData,
4923 "Element %s: attribute %s should not be present\n",
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004924 node->name, attr->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004925 return(ctxt->err);
4926 }
4927 }
4928
4929 ctxt->type = type->subtypes;
4930 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4931 ctxt->type = type;
4932 return(ret);
4933}
4934
4935/**
4936 * xmlSchemaValidateElementType:
4937 * @ctxt: a schema validation context
4938 * @node: the top node.
4939 *
4940 * Validate the content of an element type.
4941 * Validation Rule: Element Locally Valid (Complex Type)
4942 *
4943 * Returns 0 if the element is schemas valid, a positive error code
4944 * number otherwise and -1 in case of internal or API error.
4945 */
4946static int
4947xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4948 xmlNodePtr child;
4949 xmlSchemaTypePtr type;
4950 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4951 xmlSchemaElementPtr decl;
4952 int ret, attrBase;
4953
4954 oldregexp = ctxt->regexp;
4955
4956 child = ctxt->node;
4957 type = ctxt->type;
4958
4959 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004960 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004961 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4962 if (ctxt->error != NULL)
4963 ctxt->error(ctxt->userData,
4964 "Internal error: xmlSchemaValidateElementType\n",
4965 node->name);
4966 return(-1);
4967 }
4968 if (child == NULL) {
4969 if (type->minOccurs > 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004970 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004971 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4972 if (ctxt->error != NULL)
4973 ctxt->error(ctxt->userData,
4974 "Element %s: missing child %s\n",
4975 node->name, type->name);
4976 }
4977 return(ctxt->err);
4978 }
4979
4980 /*
4981 * Verify the element matches
4982 */
4983 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004984 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00004985 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4986 if (ctxt->error != NULL)
4987 ctxt->error(ctxt->userData,
4988 "Element %s: missing child %s found %s\n",
4989 node->name, type->name, child->name);
4990 return(ctxt->err);
4991 }
4992 /*
4993 * Verify the attributes
4994 */
4995 attrBase = ctxt->attrBase;
4996 ctxt->attrBase = ctxt->attrNr;
4997 xmlSchemaRegisterAttributes(ctxt, child->properties);
4998 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4999 /*
5000 * Verify the element content recursively
5001 */
5002 decl = (xmlSchemaElementPtr) type;
5003 oldregexp = ctxt->regexp;
5004 if (decl->contModel != NULL) {
5005 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5006 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5007 ctxt);
5008#ifdef DEBUG_AUTOMATA
5009 xmlGenericError(xmlGenericErrorContext,
5010 "====> %s\n", node->name);
5011#endif
5012 }
5013 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
5014 type->subtypes);
5015
5016 if (decl->contModel != NULL) {
5017 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
5018#ifdef DEBUG_AUTOMATA
5019 xmlGenericError(xmlGenericErrorContext,
5020 "====> %s : %d\n", node->name, ret);
5021#endif
5022 if (ret == 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005023 ctxt->nberrors++;
Daniel Veillard8651f532002-04-17 09:06:27 +00005024 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00005025 if (ctxt->error != NULL)
5026 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5027 node->name);
5028 } else if (ret < 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005029 ctxt->nberrors++;
Daniel Veillard8651f532002-04-17 09:06:27 +00005030 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00005031 if (ctxt->error != NULL)
5032 ctxt->error(ctxt->userData, "Element %s content check failure\n",
5033 node->name);
5034#ifdef DEBUG_CONTENT
5035 } else {
5036 xmlGenericError(xmlGenericErrorContext,
5037 "Element %s content check succeeded\n", node->name);
5038
5039#endif
5040 }
5041 xmlRegFreeExecCtxt(ctxt->regexp);
5042 }
5043 /*
5044 * Verify that all attributes were Schemas-validated
5045 */
5046 xmlSchemaCheckAttributes(ctxt, node);
5047 ctxt->attrNr = ctxt->attrBase;
5048 ctxt->attrBase = attrBase;
5049
5050 ctxt->regexp = oldregexp;
5051
5052 ctxt->node = child;
5053 ctxt->type = type;
5054 return(ctxt->err);
5055}
5056
5057/**
5058 * xmlSchemaValidateBasicType:
5059 * @ctxt: a schema validation context
5060 * @node: the top node.
5061 *
5062 * Validate the content of an element expected to be a basic type type
5063 *
5064 * Returns 0 if the element is schemas valid, a positive error code
5065 * number otherwise and -1 in case of internal or API error.
5066 */
5067static int
5068xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5069 int ret;
5070 xmlNodePtr child, cur;
5071 xmlSchemaTypePtr type;
5072 xmlChar *value; /* lexical representation */
5073
5074 child = ctxt->node;
5075 type = ctxt->type;
5076
5077 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005078 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005079 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5080 if (ctxt->error != NULL)
5081 ctxt->error(ctxt->userData,
5082 "Internal error: xmlSchemaValidateBasicType\n",
5083 node->name);
5084 return(-1);
5085 }
5086 /*
5087 * First check the content model of the node.
5088 */
5089 cur = child;
5090 while (cur != NULL) {
5091 switch (cur->type) {
5092 case XML_TEXT_NODE:
5093 case XML_CDATA_SECTION_NODE:
5094 case XML_PI_NODE:
5095 case XML_COMMENT_NODE:
5096 case XML_XINCLUDE_START:
5097 case XML_XINCLUDE_END:
5098 break;
5099 case XML_ENTITY_REF_NODE:
5100 case XML_ENTITY_NODE:
5101 TODO
5102 break;
5103 case XML_ELEMENT_NODE:
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005104 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005105 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
5106 if (ctxt->error != NULL)
5107 ctxt->error(ctxt->userData,
5108 "Element %s: child %s should not be present\n",
5109 node->name, cur->name);
5110 return(ctxt->err);
5111 case XML_ATTRIBUTE_NODE:
5112 case XML_DOCUMENT_NODE:
5113 case XML_DOCUMENT_TYPE_NODE:
5114 case XML_DOCUMENT_FRAG_NODE:
5115 case XML_NOTATION_NODE:
5116 case XML_HTML_DOCUMENT_NODE:
5117 case XML_DTD_NODE:
5118 case XML_ELEMENT_DECL:
5119 case XML_ATTRIBUTE_DECL:
5120 case XML_ENTITY_DECL:
5121 case XML_NAMESPACE_DECL:
5122#ifdef LIBXML_DOCB_ENABLED
5123 case XML_DOCB_DOCUMENT_NODE:
5124#endif
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005125 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005126 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
5127 if (ctxt->error != NULL)
5128 ctxt->error(ctxt->userData,
5129 "Element %s: node type %d unexpected here\n",
5130 node->name, cur->type);
5131 return(ctxt->err);
5132 }
5133 cur = cur->next;
5134 }
5135 if (child == NULL)
5136 value = NULL;
5137 else
5138 value = xmlNodeGetContent(child->parent);
5139
5140 if (ctxt->value != NULL) {
5141 xmlSchemaFreeValue(ctxt->value);
5142 ctxt->value = NULL;
5143 }
5144 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5145 if (value != NULL)
5146 xmlFree(value);
5147 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005148 ctxt->nberrors++;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005149 if (ctxt->error != NULL)
5150 ctxt->error(ctxt->userData,
5151 "Element %s: failed to validate basic type %s\n",
5152 node->name, type->name);
Daniel Veillard91a13252003-03-27 23:44:43 +00005153 ctxt->err = XML_SCHEMAS_ERR_VALUE;
Daniel Veillard4255d502002-04-16 15:50:10 +00005154 }
5155 return(ret);
5156}
5157
5158/**
5159 * xmlSchemaValidateComplexType:
5160 * @ctxt: a schema validation context
5161 * @node: the top node.
5162 *
5163 * Validate the content of an element expected to be a complex type type
5164 * xmlschema-1.html#cvc-complex-type
5165 * Validation Rule: Element Locally Valid (Complex Type)
5166 *
5167 * Returns 0 if the element is schemas valid, a positive error code
5168 * number otherwise and -1 in case of internal or API error.
5169 */
5170static int
5171xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5172 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005173 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005174 int ret;
5175
5176 child = ctxt->node;
5177 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005178 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005179
Daniel Veillard4255d502002-04-16 15:50:10 +00005180 switch (type->contentType) {
5181 case XML_SCHEMA_CONTENT_EMPTY:
5182 if (child != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005183 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005184 if (ctxt->error != NULL)
5185 ctxt->error(ctxt->userData,
5186 "Element %s is supposed to be empty\n",
5187 node->name);
5188 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00005189 if (type->attributes != NULL) {
5190 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5191 }
5192 subtype = type->subtypes;
5193 while (subtype != NULL) {
5194 ctxt->type = subtype;
5195 xmlSchemaValidateComplexType(ctxt, node);
5196 subtype = subtype->next;
5197 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005198 break;
5199 case XML_SCHEMA_CONTENT_ELEMENTS:
5200 case XML_SCHEMA_CONTENT_MIXED:
5201 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5202 /*
5203 * Skip ignorable nodes in that context
5204 */
5205 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005206 while (child != NULL) {
5207 if (child->type == XML_ELEMENT_NODE) {
5208 ret = xmlRegExecPushString(ctxt->regexp,
5209 child->name, child);
5210#ifdef DEBUG_AUTOMATA
5211 if (ret < 0)
5212 xmlGenericError(xmlGenericErrorContext,
5213 " --> %s Error\n", child->name);
5214 else
5215 xmlGenericError(xmlGenericErrorContext,
5216 " --> %s\n", child->name);
5217#endif
5218 }
5219 child = child->next;
5220 /*
5221 * Skip ignorable nodes in that context
5222 */
5223 child = xmlSchemaSkipIgnored(ctxt, type, child);
5224 }
5225 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005226 case XML_SCHEMA_CONTENT_BASIC: {
5227 if (type->subtypes != NULL) {
5228 ctxt->type = type->subtypes;
5229 xmlSchemaValidateComplexType(ctxt, node);
5230 }
5231 if (type->baseType != NULL) {
5232 ctxt->type = type->baseType;
5233 xmlSchemaValidateBasicType(ctxt, node);
5234 }
5235 if (type->attributes != NULL) {
5236 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5237 }
5238 ctxt->type = type;
5239 break;
5240 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005241 default:
5242 TODO
5243 xmlGenericError(xmlGenericErrorContext,
5244 "unimplemented content type %d\n",
5245 type->contentType);
5246 }
5247 return(ctxt->err);
5248}
5249
5250/**
5251 * xmlSchemaValidateContent:
5252 * @ctxt: a schema validation context
5253 * @elem: an element
5254 * @type: the type declaration
5255 *
5256 * Validate the content of an element against the type.
5257 *
5258 * Returns 0 if the element is schemas valid, a positive error code
5259 * number otherwise and -1 in case of internal or API error.
5260 */
5261static int
5262xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
5263 xmlNodePtr child;
5264 xmlSchemaTypePtr type;
5265
5266 child = ctxt->node;
5267 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005268 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005269
Daniel Veillarde19fc232002-04-22 16:01:24 +00005270 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005271 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00005272
Daniel Veillard4255d502002-04-16 15:50:10 +00005273 switch (type->type) {
5274 case XML_SCHEMA_TYPE_ANY:
5275 /* Any type will do it, fine */
5276 TODO /* handle recursivity */
5277 break;
5278 case XML_SCHEMA_TYPE_COMPLEX:
5279 xmlSchemaValidateComplexType(ctxt, node);
5280 break;
5281 case XML_SCHEMA_TYPE_ELEMENT: {
5282 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
5283 /*
5284 * Handle element reference here
5285 */
5286 if (decl->ref != NULL) {
5287 if (decl->refDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005288 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005289 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5290 if (ctxt->error != NULL)
5291 ctxt->error(ctxt->userData,
5292 "Internal error: element reference %s not resolved\n",
5293 decl->ref);
5294 return(-1);
5295 }
5296 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
5297 decl = decl->refDecl;
5298 }
5299 xmlSchemaValidateElementType(ctxt, node);
5300 ctxt->type = type;
5301 break;
5302 }
5303 case XML_SCHEMA_TYPE_BASIC:
5304 xmlSchemaValidateBasicType(ctxt, node);
5305 break;
5306 case XML_SCHEMA_TYPE_FACET:
5307 TODO
5308 break;
5309 case XML_SCHEMA_TYPE_SIMPLE:
5310 xmlSchemaValidateSimpleType(ctxt, node);
5311 break;
5312 case XML_SCHEMA_TYPE_SEQUENCE:
5313 TODO
5314 break;
5315 case XML_SCHEMA_TYPE_CHOICE:
5316 TODO
5317 break;
5318 case XML_SCHEMA_TYPE_ALL:
5319 TODO
5320 break;
5321 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5322 TODO
5323 break;
5324 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5325 TODO
5326 break;
5327 case XML_SCHEMA_TYPE_UR:
5328 TODO
5329 break;
5330 case XML_SCHEMA_TYPE_RESTRICTION:
5331 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5332 TODO
5333 break;
5334 case XML_SCHEMA_TYPE_EXTENSION:
5335 TODO
5336 break;
5337 case XML_SCHEMA_TYPE_ATTRIBUTE:
5338 TODO
5339 break;
5340 case XML_SCHEMA_TYPE_GROUP:
5341 TODO
5342 break;
5343 case XML_SCHEMA_TYPE_NOTATION:
5344 TODO
5345 break;
5346 case XML_SCHEMA_TYPE_LIST:
5347 TODO
5348 break;
5349 case XML_SCHEMA_TYPE_UNION:
5350 TODO
5351 break;
5352 case XML_SCHEMA_FACET_MININCLUSIVE:
5353 TODO
5354 break;
5355 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5356 TODO
5357 break;
5358 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5359 TODO
5360 break;
5361 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5362 TODO
5363 break;
5364 case XML_SCHEMA_FACET_TOTALDIGITS:
5365 TODO
5366 break;
5367 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5368 TODO
5369 break;
5370 case XML_SCHEMA_FACET_PATTERN:
5371 TODO
5372 break;
5373 case XML_SCHEMA_FACET_ENUMERATION:
5374 TODO
5375 break;
5376 case XML_SCHEMA_FACET_WHITESPACE:
5377 TODO
5378 break;
5379 case XML_SCHEMA_FACET_LENGTH:
5380 TODO
5381 break;
5382 case XML_SCHEMA_FACET_MAXLENGTH:
5383 TODO
5384 break;
5385 case XML_SCHEMA_FACET_MINLENGTH:
5386 TODO
5387 break;
Daniel Veillard118aed72002-09-24 14:13:13 +00005388 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5389 TODO
5390 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005391 }
5392 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5393
5394 if (ctxt->node == NULL)
5395 return(ctxt->err);
5396 ctxt->node = ctxt->node->next;
5397 ctxt->type = type->next;
5398 return(ctxt->err);
5399}
5400
5401/**
5402 * xmlSchemaValidateType:
5403 * @ctxt: a schema validation context
5404 * @elem: an element
5405 * @type: the list of type declarations
5406 *
5407 * Validate the content of an element against the types.
5408 *
5409 * Returns 0 if the element is schemas valid, a positive error code
5410 * number otherwise and -1 in case of internal or API error.
5411 */
5412static int
5413xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5414 xmlSchemaElementPtr elemDecl,
5415 xmlSchemaTypePtr type) {
5416 xmlChar *nil;
5417
Daniel Veillard2db8c122003-07-08 12:16:59 +00005418 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillard4255d502002-04-16 15:50:10 +00005419 return(0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00005420
Daniel Veillard4255d502002-04-16 15:50:10 +00005421 /*
5422 * 3.3.4 : 2
5423 */
5424 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005425 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005426 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
5427 if (ctxt->error != NULL)
5428 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
5429 return(ctxt->err);
5430 }
5431 /*
5432 * 3.3.4: 3
5433 */
5434 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5435 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
5436 /* 3.3.4: 3.2 */
5437 if (xmlStrEqual(nil, BAD_CAST "true")) {
5438 if (elem->children != NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005439 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005440 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
5441 if (ctxt->error != NULL)
5442 ctxt->error(ctxt->userData, "Element %s is not empty\n",
5443 elem->name);
5444 return(ctxt->err);
5445 }
5446 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5447 (elemDecl->value != NULL)) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005448 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005449 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
5450 if (ctxt->error != NULL)
5451 ctxt->error(ctxt->userData,
5452 "Empty element %s cannot get a fixed value\n",
5453 elem->name);
5454 return(ctxt->err);
5455 }
5456 }
5457 } else {
5458 /* 3.3.4: 3.1 */
5459 if (nil != NULL) {
5460 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005461 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005462 if (ctxt->error != NULL)
5463 ctxt->error(ctxt->userData,
5464 "Element %s with xs:nil but not nillable\n",
5465 elem->name);
5466 xmlFree(nil);
5467 return(ctxt->err);
5468 }
5469 }
5470
5471 /* TODO 3.3.4: 4 if the element carries xs:type*/
5472
5473 ctxt->type = elemDecl->subtypes;
5474 ctxt->node = elem->children;
5475 xmlSchemaValidateContent(ctxt, elem);
5476 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5477
5478 return(ctxt->err);
5479}
5480
5481
5482/**
5483 * xmlSchemaValidateAttributes:
5484 * @ctxt: a schema validation context
5485 * @elem: an element
5486 * @attributes: the list of attribute declarations
5487 *
5488 * Validate the attributes of an element.
5489 *
5490 * Returns 0 if the element is schemas valid, a positive error code
5491 * number otherwise and -1 in case of internal or API error.
5492 */
5493static int
5494xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
5495 xmlSchemaAttributePtr attributes) {
5496 int i, ret;
5497 xmlAttrPtr attr;
5498 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005499 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005500
5501 if (attributes == NULL)
5502 return(0);
5503 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00005504 /*
5505 * Handle attribute groups
5506 */
5507 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5508 group = (xmlSchemaAttributeGroupPtr) attributes;
5509 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5510 attributes = group->next;
5511 continue;
5512 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005513 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
5514 attr = ctxt->attr[i].attr;
5515 if (attr == NULL)
5516 continue;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005517 if (attributes->ref != NULL) {
5518 if (!xmlStrEqual(attr->name, attributes->ref))
5519 continue;
5520 if (attr->ns != NULL) {
5521 if ((attributes->refNs == NULL) ||
5522 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
5523 continue;
5524 } else if (attributes->refNs != NULL) {
5525 continue;
5526 }
5527 } else {
5528 if (!xmlStrEqual(attr->name, attributes->name))
5529 continue;
5530 /*
5531 * TODO: handle the mess about namespaces here.
5532 */
5533 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
5534 TODO
5535 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005536 }
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005537 ctxt->cur = (xmlNodePtr) attributes;
Daniel Veillard4255d502002-04-16 15:50:10 +00005538 if (attributes->subtypes == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005539 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005540 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5541 if (ctxt->error != NULL)
5542 ctxt->error(ctxt->userData,
5543 "Internal error: attribute %s type not resolved\n",
5544 attr->name);
5545 continue;
5546 }
5547 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5548 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005549 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005550 if (ret != 0) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005551 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005552 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5553 if (ctxt->error != NULL)
5554 ctxt->error(ctxt->userData,
5555 "attribute %s on %s does not match type\n",
5556 attr->name, elem->name);
5557 } else {
5558 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5559 }
5560 if (value != NULL) {
5561 xmlFree(value);
5562 }
5563 }
5564 attributes = attributes->next;
5565 }
5566 return(ctxt->err);
5567}
5568
5569/**
5570 * xmlSchemaValidateElement:
5571 * @ctxt: a schema validation context
5572 * @elem: an element
5573 *
5574 * Validate an element in a tree
5575 *
5576 * Returns 0 if the element is schemas valid, a positive error code
5577 * number otherwise and -1 in case of internal or API error.
5578 */
5579static int
5580xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5581 xmlSchemaElementPtr elemDecl;
5582 int ret, attrBase;
5583
5584 if (elem->ns != NULL)
5585 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5586 elem->name, elem->ns->href, NULL);
5587 else
5588 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5589 elem->name, NULL, NULL);
5590 /*
5591 * 3.3.4 : 1
5592 */
5593 if (elemDecl == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005594 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005595 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5596 if (ctxt->error != NULL)
5597 ctxt->error(ctxt->userData, "Element %s not declared\n",
5598 elem->name);
5599 return(ctxt->err);
5600 }
5601 if (elemDecl->subtypes == NULL) {
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005602 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005603 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5604 if (ctxt->error != NULL)
5605 ctxt->error(ctxt->userData, "Element %s has no type\n",
5606 elem->name);
5607 return(ctxt->err);
5608 }
5609 /*
5610 * Verify the attributes
5611 */
5612 attrBase = ctxt->attrBase;
5613 ctxt->attrBase = ctxt->attrNr;
5614 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5615 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5616 /*
5617 * Verify the element content recursively
5618 */
5619 if (elemDecl->contModel != NULL) {
5620 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5621 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5622 ctxt);
5623#ifdef DEBUG_AUTOMATA
5624 xmlGenericError(xmlGenericErrorContext,
5625 "====> %s\n", elem->name);
5626#endif
5627 }
5628 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005629 if (elemDecl->contModel != NULL) {
5630 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005631#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005632 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005633 "====> %s : %d\n", elem->name, ret);
5634#endif
5635 if (ret == 0) {
5636 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005637 ctxt->nberrors++;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005638 if (ctxt->error != NULL)
5639 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5640 elem->name);
5641 } else if (ret < 0) {
5642 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005643 ctxt->nberrors++;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005644 if (ctxt->error != NULL)
5645 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5646 elem->name);
5647#ifdef DEBUG_CONTENT
5648 } else {
5649 xmlGenericError(xmlGenericErrorContext,
5650 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005651
5652#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005653 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005654 xmlRegFreeExecCtxt(ctxt->regexp);
5655 }
5656 /*
5657 * Verify that all attributes were Schemas-validated
5658 */
5659 xmlSchemaCheckAttributes(ctxt, elem);
5660 ctxt->attrNr = ctxt->attrBase;
5661 ctxt->attrBase = attrBase;
5662
5663 return(ctxt->err);
5664}
5665
5666/**
5667 * xmlSchemaValidateDocument:
5668 * @ctxt: a schema validation context
5669 * @doc: a parsed document tree
5670 *
5671 * Validate a document tree in memory.
5672 *
5673 * Returns 0 if the document is schemas valid, a positive error code
5674 * number otherwise and -1 in case of internal or API error.
5675 */
5676static int
5677xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5678 xmlNodePtr root;
5679 xmlSchemaElementPtr elemDecl;
5680
5681 root = xmlDocGetRootElement(doc);
5682 if (root == NULL) {
5683 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005684 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005685 if (ctxt->error != NULL)
5686 ctxt->error(ctxt->userData, "document has no root\n");
5687 return(ctxt->err);
5688 }
5689 if (root->ns != NULL)
5690 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5691 root->name, root->ns->href, NULL);
5692 else
5693 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5694 root->name, NULL, NULL);
5695 if (elemDecl == NULL) {
5696 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005697 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005698 if (ctxt->error != NULL)
5699 ctxt->error(ctxt->userData, "Element %s not declared\n",
5700 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005701 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005702 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005703 ctxt->nberrors++;
Daniel Veillard4255d502002-04-16 15:50:10 +00005704 if (ctxt->error != NULL)
5705 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5706 root->name);
5707 }
5708 /*
5709 * Okay, start the recursive validation
5710 */
5711 xmlSchemaValidateElement(ctxt, root);
5712
5713 return(ctxt->err);
5714}
5715
5716/************************************************************************
5717 * *
5718 * SAX Validation code *
5719 * *
5720 ************************************************************************/
5721
5722/************************************************************************
5723 * *
5724 * Validation interfaces *
5725 * *
5726 ************************************************************************/
5727
5728/**
5729 * xmlSchemaNewValidCtxt:
5730 * @schema: a precompiled XML Schemas
5731 *
5732 * Create an XML Schemas validation context based on the given schema
5733 *
5734 * Returns the validation context or NULL in case of error
5735 */
5736xmlSchemaValidCtxtPtr
5737xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5738 xmlSchemaValidCtxtPtr ret;
5739
5740 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5741 if (ret == NULL) {
5742 xmlGenericError(xmlGenericErrorContext,
5743 "Failed to allocate new schama validation context\n");
5744 return (NULL);
5745 }
5746 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5747 ret->schema = schema;
5748 ret->attrNr = 0;
5749 ret->attrMax = 10;
5750 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5751 sizeof(xmlSchemaAttrState));
5752 if (ret->attr == NULL) {
5753 free(ret);
5754 return(NULL);
5755 }
5756 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5757 return (ret);
5758}
5759
5760/**
5761 * xmlSchemaFreeValidCtxt:
5762 * @ctxt: the schema validation context
5763 *
5764 * Free the resources associated to the schema validation context
5765 */
5766void
5767xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5768 if (ctxt == NULL)
5769 return;
5770 if (ctxt->attr != NULL)
5771 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005772 if (ctxt->value != NULL)
5773 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005774 xmlFree(ctxt);
5775}
5776
5777/**
5778 * xmlSchemaSetValidErrors:
5779 * @ctxt: a schema validation context
5780 * @err: the error function
5781 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00005782 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00005783 *
5784 * Set the error and warning callback informations
5785 */
5786void
5787xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5788 xmlSchemaValidityErrorFunc err,
5789 xmlSchemaValidityWarningFunc warn, void *ctx) {
5790 if (ctxt == NULL)
5791 return;
5792 ctxt->error = err;
5793 ctxt->warning = warn;
5794 ctxt->userData = ctx;
5795}
5796
5797/**
5798 * xmlSchemaValidateDoc:
5799 * @ctxt: a schema validation context
5800 * @doc: a parsed document tree
5801 *
5802 * Validate a document tree in memory.
5803 *
5804 * Returns 0 if the document is schemas valid, a positive error code
5805 * number otherwise and -1 in case of internal or API error.
5806 */
5807int
5808xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5809 int ret;
5810
5811 if ((ctxt == NULL) || (doc == NULL))
5812 return(-1);
5813
5814 ctxt->doc = doc;
5815 ret = xmlSchemaValidateDocument(ctxt, doc);
5816 return(ret);
5817}
5818
5819/**
5820 * xmlSchemaValidateStream:
5821 * @ctxt: a schema validation context
5822 * @input: the input to use for reading the data
5823 * @enc: an optional encoding information
5824 * @sax: a SAX handler for the resulting events
5825 * @user_data: the context to provide to the SAX handler.
5826 *
5827 * Validate a document tree in memory.
5828 *
5829 * Returns 0 if the document is schemas valid, a positive error code
5830 * number otherwise and -1 in case of internal or API error.
5831 */
5832int
5833xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5834 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5835 xmlSAXHandlerPtr sax, void *user_data) {
5836 if ((ctxt == NULL) || (input == NULL))
5837 return(-1);
5838 ctxt->input = input;
5839 ctxt->enc = enc;
5840 ctxt->sax = sax;
5841 ctxt->user_data = user_data;
5842 TODO
5843 return(0);
5844}
5845
5846#endif /* LIBXML_SCHEMAS_ENABLED */