blob: 79e376d2d9228d86d9d843c769b07e75188532c5 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemas.c : implementation of the XML Schema handling and
3 * schema validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
Daniel Veillard5a872412002-05-22 06:40:27 +000020#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000021
22#include <libxml/xmlschemas.h>
23#include <libxml/schemasInternals.h>
24#include <libxml/xmlschemastypes.h>
25#include <libxml/xmlautomata.h>
26#include <libxml/xmlregexp.h>
27
Daniel Veillard8651f532002-04-17 09:06:27 +000028#define DEBUG 1 /* very verbose output */
29#define DEBUG_CONTENT 1
30#define DEBUG_TYPE 1
Daniel Veillard4255d502002-04-16 15:50:10 +000031/* #define DEBUG_AUTOMATA 1 */
32
33#define UNBOUNDED (1 << 30)
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
Daniel Veillard5a872412002-05-22 06:40:27 +000039#define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar *)"the default namespace"
40
Daniel Veillard4255d502002-04-16 15:50:10 +000041/*
42 * The XML Schemas namespaces
43 */
44static const xmlChar *xmlSchemaNs = (const xmlChar *)
45 "http://www.w3.org/2001/XMLSchema";
46
47static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
48 "http://www.w3.org/2001/XMLSchema-instance";
49
50#define IS_SCHEMA(node, type) \
51 ((node != NULL) && (node->ns != NULL) && \
52 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
53 (xmlStrEqual(node->ns->href, xmlSchemaNs)))
54
55#define XML_SCHEMAS_PARSE_ERROR 1
56
57struct _xmlSchemaParserCtxt {
58 void *userData; /* user specific data block */
59 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
60 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillarde19fc232002-04-22 16:01:24 +000061 xmlSchemaValidError err;
Daniel Veillard4255d502002-04-16 15:50:10 +000062
63 xmlSchemaPtr schema; /* The schema in use */
64 xmlChar *container; /* the current element, group, ... */
65 int counter;
66
67 xmlChar *URL;
68 xmlDocPtr doc;
69
70 /*
71 * Used to build complex element content models
72 */
73 xmlAutomataPtr am;
74 xmlAutomataStatePtr start;
75 xmlAutomataStatePtr end;
76 xmlAutomataStatePtr state;
77};
78
79
80#define XML_SCHEMAS_ATTR_UNKNOWN 1
81#define XML_SCHEMAS_ATTR_CHECKED 2
82
83typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
84typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
85struct _xmlSchemaAttrState {
86 xmlAttrPtr attr;
87 int state;
88};
89
90/**
91 * xmlSchemaValidCtxt:
92 *
93 * A Schemas validation context
94 */
95
96struct _xmlSchemaValidCtxt {
97 void *userData; /* user specific data block */
98 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
99 xmlSchemaValidityWarningFunc warning;/* the callback in case of warning */
100
101 xmlSchemaPtr schema; /* The schema in use */
102 xmlDocPtr doc;
103 xmlParserInputBufferPtr input;
104 xmlCharEncoding enc;
105 xmlSAXHandlerPtr sax;
106 void *user_data;
107
108 xmlDocPtr myDoc;
109 int err;
110
111 xmlNodePtr node;
112 xmlSchemaTypePtr type;
113
114 xmlRegExecCtxtPtr regexp;
115 xmlSchemaValPtr value;
116
117 int attrNr;
118 int attrBase;
119 int attrMax;
120 xmlSchemaAttrStatePtr attr;
121};
122
123
124/************************************************************************
125 * *
126 * Some predeclarations *
127 * *
128 ************************************************************************/
129static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
130 xmlSchemaTypePtr type,
131 xmlChar *value);
132
133/************************************************************************
134 * *
135 * Allocation functions *
136 * *
137 ************************************************************************/
138
139/**
140 * xmlSchemaNewSchema:
141 * @ctxt: a schema validation context (optional)
142 *
143 * Allocate a new Schema structure.
144 *
145 * Returns the newly allocated structure or NULL in case or error
146 */
147static xmlSchemaPtr
148xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
149{
150 xmlSchemaPtr ret;
151
152 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
153 if (ret == NULL) {
154 if ((ctxt != NULL) && (ctxt->error != NULL))
155 ctxt->error(ctxt->userData, "Out of memory\n");
156 return (NULL);
157 }
158 memset(ret, 0, sizeof(xmlSchema));
159
160 return (ret);
161}
162
163/**
164 * xmlSchemaNewFacet:
165 * @ctxt: a schema validation context (optional)
166 *
167 * Allocate a new Facet structure.
168 *
169 * Returns the newly allocated structure or NULL in case or error
170 */
171static xmlSchemaFacetPtr
172xmlSchemaNewFacet(xmlSchemaParserCtxtPtr ctxt)
173{
174 xmlSchemaFacetPtr ret;
175
176 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
177 if (ret == NULL) {
178 if ((ctxt != NULL) && (ctxt->error != NULL))
179 ctxt->error(ctxt->userData, "Out of memory\n");
180 return (NULL);
181 }
182 memset(ret, 0, sizeof(xmlSchemaFacet));
183
184 return (ret);
185}
186
187/**
188 * xmlSchemaNewAnnot:
189 * @ctxt: a schema validation context (optional)
190 * @node: a node
191 *
192 * Allocate a new annotation structure.
193 *
194 * Returns the newly allocated structure or NULL in case or error
195 */
196static xmlSchemaAnnotPtr
197xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
198{
199 xmlSchemaAnnotPtr ret;
200
201 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
202 if (ret == NULL) {
203 if ((ctxt != NULL) && (ctxt->error != NULL))
204 ctxt->error(ctxt->userData, "Out of memory\n");
205 return (NULL);
206 }
207 memset(ret, 0, sizeof(xmlSchemaAnnot));
208 ret->content = node;
209 return (ret);
210}
211
212/**
Daniel Veillardfdc91562002-07-01 21:52:03 +0000213 * xmlSchemaFreeAnnot:
214 * @annot: a schema type structure
215 *
216 * Deallocate a annotation structure
217 */
218static void
219xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
220{
221 if (annot == NULL)
222 return;
223 xmlFree(annot);
224}
225
226/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000227 * xmlSchemaFreeNotation:
228 * @schema: a schema notation structure
229 *
230 * Deallocate a Schema Notation structure.
231 */
232static void
233xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
234{
235 if (nota == NULL)
236 return;
237 if (nota->name != NULL)
238 xmlFree((xmlChar *) nota->name);
239 xmlFree(nota);
240}
241
242/**
243 * xmlSchemaFreeAttribute:
244 * @schema: a schema attribute structure
245 *
246 * Deallocate a Schema Attribute structure.
247 */
248static void
249xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
250{
251 if (attr == NULL)
252 return;
253 if (attr->name != NULL)
254 xmlFree((xmlChar *) attr->name);
255 if (attr->ref != NULL)
256 xmlFree((xmlChar *) attr->ref);
257 if (attr->refNs != NULL)
258 xmlFree((xmlChar *) attr->refNs);
259 if (attr->typeName != NULL)
260 xmlFree((xmlChar *) attr->typeName);
261 if (attr->typeNs != NULL)
262 xmlFree((xmlChar *) attr->typeNs);
263 xmlFree(attr);
264}
265
266/**
267 * xmlSchemaFreeAttributeGroup:
268 * @schema: a schema attribute group structure
269 *
270 * Deallocate a Schema Attribute Group structure.
271 */
272static void
273xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
274{
275 if (attr == NULL)
276 return;
277 if (attr->name != NULL)
278 xmlFree((xmlChar *) attr->name);
279 xmlFree(attr);
280}
281
282/**
283 * xmlSchemaFreeElement:
284 * @schema: a schema element structure
285 *
286 * Deallocate a Schema Element structure.
287 */
288static void
289xmlSchemaFreeElement(xmlSchemaElementPtr elem)
290{
291 if (elem == NULL)
292 return;
293 if (elem->name != NULL)
294 xmlFree((xmlChar *) elem->name);
295 if (elem->namedType != NULL)
296 xmlFree((xmlChar *) elem->namedType);
297 if (elem->namedTypeNs != NULL)
298 xmlFree((xmlChar *) elem->namedTypeNs);
299 if (elem->ref != NULL)
300 xmlFree((xmlChar *) elem->ref);
301 if (elem->refNs != NULL)
302 xmlFree((xmlChar *) elem->refNs);
303 if (elem->contModel != NULL)
304 xmlRegFreeRegexp(elem->contModel);
305 xmlFree(elem);
306}
307
308/**
309 * xmlSchemaFreeFacet:
310 * @facet: a schema facet structure
311 *
312 * Deallocate a Schema Facet structure.
313 */
314static void
315xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
316{
317 if (facet == NULL)
318 return;
319 if (facet->value != NULL)
320 xmlFree((xmlChar *) facet->value);
321 if (facet->id != NULL)
322 xmlFree((xmlChar *) facet->id);
323 if (facet->val != NULL)
324 xmlSchemaFreeValue(facet->val);
325 if (facet->regexp != NULL)
326 xmlRegFreeRegexp(facet->regexp);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000327 if (facet->annot != NULL)
328 xmlSchemaFreeAnnot(facet->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000329 xmlFree(facet);
330}
331
332/**
333 * xmlSchemaFreeType:
334 * @type: a schema type structure
335 *
336 * Deallocate a Schema Type structure.
337 */
338void
339xmlSchemaFreeType(xmlSchemaTypePtr type)
340{
341 if (type == NULL)
342 return;
343 if (type->name != NULL)
344 xmlFree((xmlChar *) type->name);
345 if (type->base != NULL)
346 xmlFree((xmlChar *) type->base);
347 if (type->baseNs != NULL)
348 xmlFree((xmlChar *) type->baseNs);
349 if (type->annot != NULL)
350 xmlFree((xmlChar *) type->annot);
351 if (type->facets != NULL) {
352 xmlSchemaFacetPtr facet, next;
353
354 facet = type->facets;
355 while (facet != NULL) {
356 next = facet->next;
357 xmlSchemaFreeFacet(facet);
358 facet = next;
359 }
360 }
361 xmlFree(type);
362}
363
364/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000365 * xmlSchemaFree:
366 * @schema: a schema structure
367 *
368 * Deallocate a Schema structure.
369 */
370void
371xmlSchemaFree(xmlSchemaPtr schema)
372{
373 if (schema == NULL)
374 return;
375
376 if (schema->name != NULL)
377 xmlFree((xmlChar *) schema->name);
378 if (schema->notaDecl != NULL)
379 xmlHashFree(schema->notaDecl,
380 (xmlHashDeallocator) xmlSchemaFreeNotation);
381 if (schema->attrDecl != NULL)
382 xmlHashFree(schema->attrDecl,
383 (xmlHashDeallocator) xmlSchemaFreeAttribute);
384 if (schema->attrgrpDecl != NULL)
385 xmlHashFree(schema->attrgrpDecl,
386 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup);
387 if (schema->elemDecl != NULL)
388 xmlHashFree(schema->elemDecl,
389 (xmlHashDeallocator) xmlSchemaFreeElement);
390 if (schema->typeDecl != NULL)
391 xmlHashFree(schema->typeDecl,
392 (xmlHashDeallocator) xmlSchemaFreeType);
393 if (schema->annot != NULL)
394 xmlSchemaFreeAnnot(schema->annot);
395 if (schema->doc != NULL)
396 xmlFreeDoc(schema->doc);
397
398 xmlFree(schema);
399}
400
401/************************************************************************
402 * *
403 * Error functions *
404 * *
405 ************************************************************************/
406
407/**
408 * xmlSchemaErrorContext:
409 * @ctxt: the parsing context
410 * @schema: the schema being built
411 * @node: the node being processed
412 * @child: the child being processed
413 *
414 * Dump a SchemaType structure
415 */
416static void
417xmlSchemaErrorContext(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
418 xmlNodePtr node, xmlNodePtr child)
419{
420 int line = 0;
421 const xmlChar *file = NULL;
422 const xmlChar *name = NULL;
423 const char *type = "error";
424
425 if ((ctxt == NULL) || (ctxt->error == NULL))
426 return;
427
428 if (child != NULL)
429 node = child;
430
431 if (node != NULL) {
432 if ((node->type == XML_DOCUMENT_NODE) ||
433 (node->type == XML_HTML_DOCUMENT_NODE)) {
434 xmlDocPtr doc = (xmlDocPtr) node;
435
436 file = doc->URL;
437 } else {
438 /*
439 * Try to find contextual informations to report
440 */
441 if (node->type == XML_ELEMENT_NODE) {
442 line = (int) node->content;
443 } else if ((node->prev != NULL) &&
444 (node->prev->type == XML_ELEMENT_NODE)) {
445 line = (int) node->prev->content;
446 } else if ((node->parent != NULL) &&
447 (node->parent->type == XML_ELEMENT_NODE)) {
448 line = (int) node->parent->content;
449 }
450 if ((node->doc != NULL) && (node->doc->URL != NULL))
451 file = node->doc->URL;
452 if (node->name != NULL)
453 name = node->name;
454 }
455 }
456
457 if (ctxt != NULL)
458 type = "compilation error";
459 else if (schema != NULL)
460 type = "runtime error";
461
462 if ((file != NULL) && (line != 0) && (name != NULL))
463 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
464 type, file, line, name);
465 else if ((file != NULL) && (name != NULL))
466 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
467 type, file, name);
468 else if ((file != NULL) && (line != 0))
469 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
470 else if (file != NULL)
471 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
472 else if (name != NULL)
473 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
474 else
475 ctxt->error(ctxt->userData, "%s\n", type);
476}
477
478/************************************************************************
479 * *
480 * Debug functions *
481 * *
482 ************************************************************************/
483
484/**
485 * xmlSchemaElementDump:
486 * @elem: an element
487 * @output: the file output
488 *
489 * Dump the element
490 */
491static void
492xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
493 ATTRIBUTE_UNUSED const xmlChar *name,
494 ATTRIBUTE_UNUSED const xmlChar *context,
495 ATTRIBUTE_UNUSED const xmlChar *namespace)
496{
497 if (elem == NULL)
498 return;
499
500 fprintf(output, "Element ");
501 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
502 fprintf(output, "toplevel ");
503 fprintf(output, ": %s ", elem->name);
504 if (namespace != NULL)
505 fprintf(output, "namespace '%s' ", namespace);
506
507 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
508 fprintf(output, "nillable ");
509 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
510 fprintf(output, "global ");
511 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
512 fprintf(output, "default ");
513 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
514 fprintf(output, "fixed ");
515 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
516 fprintf(output, "abstract ");
517 if (elem->flags & XML_SCHEMAS_ELEM_REF)
518 fprintf(output, "ref '%s' ", elem->ref);
519 if (elem->id != NULL)
520 fprintf(output, "id '%s' ", elem->id);
521 fprintf(output, "\n");
522 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
523 fprintf(output, " ");
524 if (elem->minOccurs != 1)
525 fprintf(output, "min: %d ", elem->minOccurs);
526 if (elem->maxOccurs >= UNBOUNDED)
527 fprintf(output, "max: unbounded\n");
528 else if (elem->maxOccurs != 1)
529 fprintf(output, "max: %d\n", elem->maxOccurs);
530 else
531 fprintf(output, "\n");
532 }
533 if (elem->namedType != NULL) {
534 fprintf(output, " type: %s", elem->namedType);
535 if (elem->namedTypeNs != NULL)
536 fprintf(output, " ns %s\n", elem->namedTypeNs);
537 else
538 fprintf(output, "\n");
539 }
540 if (elem->substGroup != NULL) {
541 fprintf(output, " substitutionGroup: %s", elem->substGroup);
542 if (elem->substGroupNs != NULL)
543 fprintf(output, " ns %s\n", elem->substGroupNs);
544 else
545 fprintf(output, "\n");
546 }
547 if (elem->value != NULL)
548 fprintf(output, " default: %s", elem->value);
549}
550
551/**
552 * xmlSchemaAnnotDump:
553 * @output: the file output
554 * @annot: a annotation
555 *
556 * Dump the annotation
557 */
558static void
559xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
560{
561 xmlChar *content;
562
563 if (annot == NULL)
564 return;
565
566 content = xmlNodeGetContent(annot->content);
567 if (content != NULL) {
568 fprintf(output, " Annot: %s\n", content);
569 xmlFree(content);
570 } else
571 fprintf(output, " Annot: empty\n");
572}
573
574/**
575 * xmlSchemaTypeDump:
576 * @output: the file output
577 * @type: a type structure
578 *
579 * Dump a SchemaType structure
580 */
581static void
582xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
583{
584 if (type == NULL) {
585 fprintf(output, "Type: NULL\n");
586 return;
587 }
588 fprintf(output, "Type: ");
589 if (type->name != NULL)
590 fprintf(output, "%s, ", type->name);
591 else
592 fprintf(output, "no name");
593 switch (type->type) {
594 case XML_SCHEMA_TYPE_BASIC:
595 fprintf(output, "basic ");
596 break;
597 case XML_SCHEMA_TYPE_SIMPLE:
598 fprintf(output, "simple ");
599 break;
600 case XML_SCHEMA_TYPE_COMPLEX:
601 fprintf(output, "complex ");
602 break;
603 case XML_SCHEMA_TYPE_SEQUENCE:
604 fprintf(output, "sequence ");
605 break;
606 case XML_SCHEMA_TYPE_CHOICE:
607 fprintf(output, "choice ");
608 break;
609 case XML_SCHEMA_TYPE_ALL:
610 fprintf(output, "all ");
611 break;
612 case XML_SCHEMA_TYPE_UR:
613 fprintf(output, "ur ");
614 break;
615 case XML_SCHEMA_TYPE_RESTRICTION:
616 fprintf(output, "restriction ");
617 break;
618 case XML_SCHEMA_TYPE_EXTENSION:
619 fprintf(output, "extension ");
620 break;
621 default:
622 fprintf(output, "unknowntype%d ", type->type);
623 break;
624 }
625 if (type->base != NULL) {
626 fprintf(output, "base %s, ", type->base);
627 }
628 switch (type->contentType) {
629 case XML_SCHEMA_CONTENT_UNKNOWN:
630 fprintf(output, "unknown ");
631 break;
632 case XML_SCHEMA_CONTENT_EMPTY:
633 fprintf(output, "empty ");
634 break;
635 case XML_SCHEMA_CONTENT_ELEMENTS:
636 fprintf(output, "element ");
637 break;
638 case XML_SCHEMA_CONTENT_MIXED:
639 fprintf(output, "mixed ");
640 break;
641 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
642 fprintf(output, "mixed_or_elems ");
643 break;
644 case XML_SCHEMA_CONTENT_BASIC:
645 fprintf(output, "basic ");
646 break;
647 case XML_SCHEMA_CONTENT_SIMPLE:
648 fprintf(output, "simple ");
649 break;
Daniel Veillard88c58912002-04-23 07:12:20 +0000650 case XML_SCHEMA_CONTENT_ANY:
651 fprintf(output, "any ");
652 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000653 }
654 fprintf(output, "\n");
655 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
656 fprintf(output, " ");
657 if (type->minOccurs != 1)
658 fprintf(output, "min: %d ", type->minOccurs);
659 if (type->maxOccurs >= UNBOUNDED)
660 fprintf(output, "max: unbounded\n");
661 else if (type->maxOccurs != 1)
662 fprintf(output, "max: %d\n", type->maxOccurs);
663 else
664 fprintf(output, "\n");
665 }
666 if (type->annot != NULL)
667 xmlSchemaAnnotDump(output, type->annot);
668 if (type->subtypes != NULL) {
669 xmlSchemaTypePtr sub = type->subtypes;
670
671 fprintf(output, " subtypes: ");
672 while (sub != NULL) {
673 fprintf(output, "%s ", sub->name);
674 sub = sub->next;
675 }
676 fprintf(output, "\n");
677 }
678
679}
680
681/**
682 * xmlSchemaDump:
683 * @output: the file output
684 * @schema: a schema structure
685 *
686 * Dump a Schema structure.
687 */
688void
689xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
690{
691 if (schema == NULL) {
692 fprintf(output, "Schemas: NULL\n");
693 return;
694 }
695 fprintf(output, "Schemas: ");
696 if (schema->name != NULL)
697 fprintf(output, "%s, ", schema->name);
698 else
699 fprintf(output, "no name, ");
700 if (schema->targetNamespace != NULL)
701 fprintf(output, "%s", schema->targetNamespace);
702 else
703 fprintf(output, "no target namespace");
704 fprintf(output, "\n");
705 if (schema->annot != NULL)
706 xmlSchemaAnnotDump(output, schema->annot);
707
708 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
709 output);
710 xmlHashScanFull(schema->elemDecl,
711 (xmlHashScannerFull) xmlSchemaElementDump, output);
712}
713
714/************************************************************************
715 * *
716 * Parsing functions *
717 * *
718 ************************************************************************/
719
720/**
721 * xmlSchemaGetType:
722 * @schema: the schemas context
723 * @name: the type name
724 * @ns: the type namespace
725 *
726 * Lookup a type in the schemas or the predefined types
727 *
728 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
729 */
730static xmlSchemaTypePtr
731xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
732 const xmlChar * namespace) {
733 xmlSchemaTypePtr ret;
734
735 if (name == NULL)
736 return(NULL);
737 if (schema != NULL) {
738 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
739 if (ret != NULL)
740 return(ret);
741 }
742 ret = xmlSchemaGetPredefinedType(name, namespace);
743#ifdef DEBUG
744 if (ret == NULL) {
745 if (namespace == NULL)
746 fprintf(stderr, "Unable to lookup type %s", name);
747 else
748 fprintf(stderr, "Unable to lookup type %s:%s", name, namespace);
749 }
750#endif
751 return(ret);
752}
753
754/************************************************************************
755 * *
756 * Parsing functions *
757 * *
758 ************************************************************************/
759
760#define IS_BLANK_NODE(n) \
761 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
762
763/**
764 * xmlSchemaIsBlank:
765 * @str: a string
766 *
767 * Check if a string is ignorable
768 *
769 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
770 */
771static int
772xmlSchemaIsBlank(xmlChar *str) {
773 if (str == NULL)
774 return(1);
775 while (*str != 0) {
776 if (!(IS_BLANK(*str))) return(0);
777 str++;
778 }
779 return(1);
780}
781
782/**
783 * xmlSchemaAddNotation:
784 * @ctxt: a schema validation context
785 * @schema: the schema being built
786 * @name: the item name
787 *
788 * Add an XML schema Attrribute declaration
789 * *WARNING* this interface is highly subject to change
790 *
791 * Returns the new struture or NULL in case of error
792 */
793static xmlSchemaNotationPtr
794xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
795 const xmlChar * name)
796{
797 xmlSchemaNotationPtr ret = NULL;
798 int val;
799
800 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
801 return (NULL);
802
803 if (schema->notaDecl == NULL)
804 schema->notaDecl = xmlHashCreate(10);
805 if (schema->notaDecl == NULL)
806 return (NULL);
807
808 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
809 if (ret == NULL) {
810 if ((ctxt != NULL) && (ctxt->error != NULL))
811 ctxt->error(ctxt->userData, "Out of memory\n");
812 return (NULL);
813 }
814 memset(ret, 0, sizeof(xmlSchemaNotation));
815 ret->name = xmlStrdup(name);
816 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
817 ret);
818 if (val != 0) {
819 if ((ctxt != NULL) && (ctxt->error != NULL))
820 ctxt->error(ctxt->userData, "Could not add notation %s\n",
821 name);
822 xmlFree((char *) ret->name);
823 xmlFree(ret);
824 return (NULL);
825 }
826 return (ret);
827}
828
829
830/**
831 * xmlSchemaAddAttribute:
832 * @ctxt: a schema validation context
833 * @schema: the schema being built
834 * @name: the item name
835 * @container: the container's name
836 *
837 * Add an XML schema Attrribute declaration
838 * *WARNING* this interface is highly subject to change
839 *
840 * Returns the new struture or NULL in case of error
841 */
842static xmlSchemaAttributePtr
843xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
844 const xmlChar * name)
845{
846 xmlSchemaAttributePtr ret = NULL;
847 int val;
848
849 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
850 return (NULL);
851
852 if (schema->attrDecl == NULL)
853 schema->attrDecl = xmlHashCreate(10);
854 if (schema->attrDecl == NULL)
855 return (NULL);
856
857 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
858 if (ret == NULL) {
859 if ((ctxt != NULL) && (ctxt->error != NULL))
860 ctxt->error(ctxt->userData, "Out of memory\n");
861 return (NULL);
862 }
863 memset(ret, 0, sizeof(xmlSchemaAttribute));
864 ret->name = xmlStrdup(name);
865 val = xmlHashAddEntry3(schema->attrDecl, name,
866 schema->targetNamespace, ctxt->container, ret);
867 if (val != 0) {
868 if ((ctxt != NULL) && (ctxt->error != NULL))
869 ctxt->error(ctxt->userData, "Could not add attribute %s\n",
870 name);
871 xmlFree((char *) ret->name);
872 xmlFree(ret);
873 return (NULL);
874 }
875 return (ret);
876}
877
878/**
879 * xmlSchemaAddAttributeGroup:
880 * @ctxt: a schema validation context
881 * @schema: the schema being built
882 * @name: the item name
883 *
884 * Add an XML schema Attrribute Group declaration
885 *
886 * Returns the new struture or NULL in case of error
887 */
888static xmlSchemaAttributeGroupPtr
889xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
890 const xmlChar * name)
891{
892 xmlSchemaAttributeGroupPtr ret = NULL;
893 int val;
894
895 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
896 return (NULL);
897
898 if (schema->attrgrpDecl == NULL)
899 schema->attrgrpDecl = xmlHashCreate(10);
900 if (schema->attrgrpDecl == NULL)
901 return (NULL);
902
903 ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup));
904 if (ret == NULL) {
905 if ((ctxt != NULL) && (ctxt->error != NULL))
906 ctxt->error(ctxt->userData, "Out of memory\n");
907 return (NULL);
908 }
909 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
910 ret->name = xmlStrdup(name);
911 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
912 schema->targetNamespace, ctxt->container, ret);
913 if (val != 0) {
914 if ((ctxt != NULL) && (ctxt->error != NULL))
915 ctxt->error(ctxt->userData, "Could not add attribute group %s\n",
916 name);
917 xmlFree((char *) ret->name);
918 xmlFree(ret);
919 return (NULL);
920 }
921 return (ret);
922}
923
924/**
925 * xmlSchemaAddElement:
926 * @ctxt: a schema validation context
927 * @schema: the schema being built
928 * @name: the type name
929 * @namespace: the type namespace
930 *
931 * Add an XML schema Element declaration
932 * *WARNING* this interface is highly subject to change
933 *
934 * Returns the new struture or NULL in case of error
935 */
936static xmlSchemaElementPtr
937xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
938 const xmlChar * name, const xmlChar * namespace)
939{
940 xmlSchemaElementPtr ret = NULL;
941 int val;
942
943 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
944 return (NULL);
945
946 if (schema->elemDecl == NULL)
947 schema->elemDecl = xmlHashCreate(10);
948 if (schema->elemDecl == NULL)
949 return (NULL);
950
951 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
952 if (ret == NULL) {
953 if ((ctxt != NULL) && (ctxt->error != NULL))
954 ctxt->error(ctxt->userData, "Out of memory\n");
955 return (NULL);
956 }
957 memset(ret, 0, sizeof(xmlSchemaElement));
958 ret->name = xmlStrdup(name);
959 val = xmlHashAddEntry3(schema->elemDecl, name,
960 namespace, ctxt->container, ret);
961 if (val != 0) {
962 char buf[100];
963
964 snprintf(buf, 99, "privatieelem%d", ctxt->counter++ + 1);
965 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
966 namespace, ret);
967 if (val != 0) {
968 if ((ctxt != NULL) && (ctxt->error != NULL))
969 ctxt->error(ctxt->userData, "Could not add element %s\n",
970 name);
971 xmlFree((char *) ret->name);
972 xmlFree(ret);
973 return (NULL);
974 }
975 }
976 return (ret);
977}
978
979/**
980 * xmlSchemaAddType:
981 * @ctxt: a schema validation context
982 * @schema: the schema being built
983 * @name: the item name
984 *
985 * Add an XML schema Simple Type definition
986 * *WARNING* this interface is highly subject to change
987 *
988 * Returns the new struture or NULL in case of error
989 */
990static xmlSchemaTypePtr
991xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
992 const xmlChar * name)
993{
994 xmlSchemaTypePtr ret = NULL;
995 int val;
996
997 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
998 return (NULL);
999
1000 if (schema->typeDecl == NULL)
1001 schema->typeDecl = xmlHashCreate(10);
1002 if (schema->typeDecl == NULL)
1003 return (NULL);
1004
1005 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1006 if (ret == NULL) {
1007 if ((ctxt != NULL) && (ctxt->error != NULL))
1008 ctxt->error(ctxt->userData, "Out of memory\n");
1009 return (NULL);
1010 }
1011 memset(ret, 0, sizeof(xmlSchemaType));
1012 ret->name = xmlStrdup(name);
1013 val = xmlHashAddEntry2(schema->typeDecl, name, schema->targetNamespace,
1014 ret);
1015 if (val != 0) {
1016 if ((ctxt != NULL) && (ctxt->error != NULL))
1017 ctxt->error(ctxt->userData, "Could not add type %s\n", name);
1018 xmlFree((char *) ret->name);
1019 xmlFree(ret);
1020 return (NULL);
1021 }
1022 ret->minOccurs = 1;
1023 ret->maxOccurs = 1;
1024
1025 return (ret);
1026}
1027
1028/************************************************************************
1029 * *
1030 * Utilities for parsing *
1031 * *
1032 ************************************************************************/
1033
1034/**
1035 * xmlGetQNameProp:
1036 * @ctxt: a schema validation context
1037 * @node: a subtree containing XML Schema informations
1038 * @name: the attribute name
1039 * @namespace: the result namespace if any
1040 *
1041 * Extract a QName Attribute value
1042 *
1043 * Returns the NCName or NULL if not found, and also update @namespace
1044 * with the namespace URI
1045 */
1046static xmlChar *
1047xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1048 const char *name,
1049 xmlChar **namespace) {
1050 xmlChar *val, *ret, *prefix;
1051 xmlNsPtr ns;
1052
1053
1054 if (namespace != NULL)
1055 *namespace = NULL;
1056 val = xmlGetProp(node, (const xmlChar *) name);
1057 if (val == NULL)
1058 return(NULL);
1059
1060 ret = xmlSplitQName2(val, &prefix);
1061 if (ret == NULL)
1062 return(val);
1063 xmlFree(val);
1064
1065 ns = xmlSearchNs(node->doc, node, prefix);
1066 if (ns == NULL) {
1067 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1068 if ((ctxt != NULL) && (ctxt->error != NULL))
1069 ctxt->error(ctxt->userData,
1070 "Attribute %s: the QName prefix %s is undefined\n",
1071 name, prefix);
1072 } else {
1073 *namespace = xmlStrdup(ns->href);
1074 }
1075 xmlFree(prefix);
1076 return(ret);
1077}
1078
1079/**
1080 * xmlGetMaxOccurs:
1081 * @ctxt: a schema validation context
1082 * @node: a subtree containing XML Schema informations
1083 *
1084 * Get the maxOccurs property
1085 *
1086 * Returns the default if not found, or the value
1087 */
1088static int
1089xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1090 xmlChar *val, *cur;
1091 int ret = 0;
1092
1093 val = xmlGetProp(node, (const xmlChar *) "maxOccurs");
1094 if (val == NULL)
1095 return(1);
1096
1097 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
1098 xmlFree(val);
1099 return(UNBOUNDED); /* encoding it with -1 might be another option */
1100 }
1101
1102 cur = val;
1103 while (IS_BLANK(*cur)) cur++;
1104 while ((*cur >= '0') && (*cur <= '9')) {
1105 ret = ret * 10 + (*cur - '0');
1106 cur++;
1107 }
1108 while (IS_BLANK(*cur)) cur++;
1109 if (*cur != 0) {
1110 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1111 if ((ctxt != NULL) && (ctxt->error != NULL))
1112 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1113 val);
1114 xmlFree(val);
1115 return(1);
1116 }
1117 xmlFree(val);
1118 return(ret);
1119}
1120
1121/**
1122 * xmlGetMinOccurs:
1123 * @ctxt: a schema validation context
1124 * @node: a subtree containing XML Schema informations
1125 *
1126 * Get the minOccurs property
1127 *
1128 * Returns the default if not found, or the value
1129 */
1130static int
1131xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) {
1132 xmlChar *val, *cur;
1133 int ret = 0;
1134
1135 val = xmlGetProp(node, (const xmlChar *) "minOccurs");
1136 if (val == NULL)
1137 return(1);
1138
1139 cur = val;
1140 while (IS_BLANK(*cur)) cur++;
1141 while ((*cur >= '0') && (*cur <= '9')) {
1142 ret = ret * 10 + (*cur - '0');
1143 cur++;
1144 }
1145 while (IS_BLANK(*cur)) cur++;
1146 if (*cur != 0) {
1147 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1148 if ((ctxt != NULL) && (ctxt->error != NULL))
1149 ctxt->error(ctxt->userData, "invalid value for minOccurs: %s\n",
1150 val);
1151 xmlFree(val);
1152 return(1);
1153 }
1154 xmlFree(val);
1155 return(ret);
1156}
1157
1158/**
1159 * xmlGetBooleanProp:
1160 * @ctxt: a schema validation context
1161 * @node: a subtree containing XML Schema informations
1162 * @name: the attribute name
1163 * @def: the default value
1164 *
1165 * Get is a bolean property is set
1166 *
1167 * Returns the default if not found, 0 if found to be false,
1168 * 1 if found to be true
1169 */
1170static int
1171xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
1172 const char *name, int def) {
1173 xmlChar *val;
1174
1175 val = xmlGetProp(node, (const xmlChar *) name);
1176 if (val == NULL)
1177 return(def);
1178
1179 if (xmlStrEqual(val, BAD_CAST"true"))
1180 def = 1;
1181 else if (xmlStrEqual(val, BAD_CAST"false"))
1182 def = 0;
1183 else {
1184 xmlSchemaErrorContext(ctxt, NULL, node, NULL);
1185 if ((ctxt != NULL) && (ctxt->error != NULL))
1186 ctxt->error(ctxt->userData,
1187 "Attribute %s: the value %s is not boolean\n",
1188 name, val);
1189 }
1190 xmlFree(val);
1191 return(def);
1192}
1193
1194/************************************************************************
1195 * *
1196 * Shema extraction from an Infoset *
1197 * *
1198 ************************************************************************/
1199static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1200 ctxt, xmlSchemaPtr schema,
1201 xmlNodePtr node);
1202static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt,
1203 xmlSchemaPtr schema,
1204 xmlNodePtr node);
1205static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt,
1206 xmlSchemaPtr schema,
1207 xmlNodePtr node,
1208 int simple);
1209static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1210 xmlSchemaPtr schema,
1211 xmlNodePtr node);
1212static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1213 xmlSchemaPtr schema,
1214 xmlNodePtr node);
1215static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1216 ctxt,
1217 xmlSchemaPtr schema,
1218 xmlNodePtr node);
1219static xmlSchemaAttributeGroupPtr
1220xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1221 xmlSchemaPtr schema, xmlNodePtr node);
1222static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1223 xmlSchemaPtr schema,
1224 xmlNodePtr node);
1225static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1226 xmlSchemaPtr schema,
1227 xmlNodePtr node);
1228static xmlSchemaAttributePtr
1229xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1230 xmlNodePtr node);
1231
1232/**
1233 * xmlSchemaParseAttrDecls:
1234 * @ctxt: a schema validation context
1235 * @schema: the schema being built
1236 * @node: a subtree containing XML Schema informations
1237 * @type: the hosting type
1238 *
1239 * parse a XML schema attrDecls declaration corresponding to
1240 * <!ENTITY % attrDecls
1241 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1242 */
1243static xmlNodePtr
1244xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1245 xmlNodePtr child, xmlSchemaTypePtr type)
1246{
1247 xmlSchemaAttributePtr lastattr, attr;
1248
1249 lastattr = NULL;
1250 while ((IS_SCHEMA(child, "attribute")) ||
1251 (IS_SCHEMA(child, "attributeGroup"))) {
1252 attr = NULL;
1253 if (IS_SCHEMA(child, "attribute")) {
1254 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1255 } else if (IS_SCHEMA(child, "attributeGroup")) {
1256 attr = (xmlSchemaAttributePtr)
1257 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1258 }
1259 if (attr != NULL) {
1260 if (lastattr == NULL) {
1261 type->attributes = attr;
1262 lastattr = attr
1263 ;
1264 } else {
1265 lastattr->next = attr;
1266 lastattr = attr;
1267 }
1268 }
1269 child = child->next;
1270 }
1271 if (IS_SCHEMA(child, "anyAttribute")) {
1272 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1273 if (attr != NULL) {
1274 if (lastattr == NULL) {
1275 type->attributes = attr;
1276 lastattr = attr
1277 ;
1278 } else {
1279 lastattr->next = attr;
1280 lastattr = attr;
1281 }
1282 }
1283 child = child->next;
1284 }
1285 return(child);
1286}
1287
1288/**
1289 * xmlSchemaParseAnnotation:
1290 * @ctxt: a schema validation context
1291 * @schema: the schema being built
1292 * @node: a subtree containing XML Schema informations
1293 *
1294 * parse a XML schema Attrribute declaration
1295 * *WARNING* this interface is highly subject to change
1296 *
1297 * Returns -1 in case of error, 0 if the declaration is inproper and
1298 * 1 in case of success.
1299 */
1300static xmlSchemaAnnotPtr
1301xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1302 xmlNodePtr node)
1303{
1304 xmlSchemaAnnotPtr ret;
1305
1306 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1307 return (NULL);
1308 ret = xmlSchemaNewAnnot(ctxt, node);
1309
1310 return (ret);
1311}
1312
1313/**
1314 * xmlSchemaParseFacet:
1315 * @ctxt: a schema validation context
1316 * @schema: the schema being built
1317 * @node: a subtree containing XML Schema informations
1318 *
1319 * parse a XML schema Facet declaration
1320 * *WARNING* this interface is highly subject to change
1321 *
1322 * Returns the new type structure or NULL in case of error
1323 */
1324static xmlSchemaFacetPtr
1325xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1326 xmlNodePtr node)
1327{
1328 xmlSchemaFacetPtr facet;
1329 xmlNodePtr child = NULL;
1330 xmlChar *value;
1331
1332 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1333 return (NULL);
1334
1335 facet = xmlSchemaNewFacet(ctxt);
1336 if (facet == NULL)
1337 return (NULL);
1338 facet->node = node;
1339 value = xmlGetProp(node, (const xmlChar *) "value");
1340 if (value == NULL) {
1341 xmlSchemaErrorContext(ctxt, schema, node, child);
1342 if ((ctxt != NULL) && (ctxt->error != NULL))
1343 ctxt->error(ctxt->userData, "Facet %s has no value\n", node->name);
1344 xmlSchemaFreeFacet(facet);
1345 return (NULL);
1346 }
1347 if (IS_SCHEMA(node, "minInclusive")) {
1348 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1349 } else if (IS_SCHEMA(node, "minExclusive")) {
1350 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1351 } else if (IS_SCHEMA(node, "maxInclusive")) {
1352 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1353 } else if (IS_SCHEMA(node, "maxExclusive")) {
1354 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1355 } else if (IS_SCHEMA(node, "totalDigits")) {
1356 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1357 } else if (IS_SCHEMA(node, "fractionDigits")) {
1358 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1359 } else if (IS_SCHEMA(node, "pattern")) {
1360 facet->type = XML_SCHEMA_FACET_PATTERN;
1361 } else if (IS_SCHEMA(node, "enumeration")) {
1362 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1363 } else if (IS_SCHEMA(node, "whiteSpace")) {
1364 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1365 } else if (IS_SCHEMA(node, "length")) {
1366 facet->type = XML_SCHEMA_FACET_LENGTH;
1367 } else if (IS_SCHEMA(node, "maxLength")) {
1368 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1369 } else if (IS_SCHEMA(node, "minLength")) {
1370 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1371 } else {
1372 xmlSchemaErrorContext(ctxt, schema, node, child);
1373 if ((ctxt != NULL) && (ctxt->error != NULL))
1374 ctxt->error(ctxt->userData, "Unknown facet type %s\n", node->name);
1375 xmlSchemaFreeFacet(facet);
1376 return(NULL);
1377 }
1378 facet->id = xmlGetProp(node, (const xmlChar *) "id");
1379 facet->value = value;
1380 child = node->children;
1381
1382 if (IS_SCHEMA(child, "annotation")) {
1383 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1384 child = child->next;
1385 }
1386 if (child != NULL) {
1387 xmlSchemaErrorContext(ctxt, schema, node, child);
1388 if ((ctxt != NULL) && (ctxt->error != NULL))
1389 ctxt->error(ctxt->userData,
1390 "Facet %s has unexpected child content\n",
1391 node->name);
1392 }
1393 return (facet);
1394}
1395
1396/**
1397 * xmlSchemaParseAny:
1398 * @ctxt: a schema validation context
1399 * @schema: the schema being built
1400 * @node: a subtree containing XML Schema informations
1401 *
1402 * parse a XML schema Any declaration
1403 * *WARNING* this interface is highly subject to change
1404 *
1405 * Returns the new type structure or NULL in case of error
1406 */
1407static xmlSchemaTypePtr
1408xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1409 xmlNodePtr node)
1410{
1411 xmlSchemaTypePtr type;
1412 xmlNodePtr child = NULL;
1413 xmlChar name[30];
1414
1415 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1416 return (NULL);
1417 snprintf((char *)name, 30, "any %d", ctxt->counter++ + 1);
1418 type = xmlSchemaAddType(ctxt, schema, name);
1419 if (type == NULL)
1420 return (NULL);
1421 type->node = node;
1422 type->type = XML_SCHEMA_TYPE_ANY;
1423 child = node->children;
1424 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1425 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1426
1427 if (IS_SCHEMA(child, "annotation")) {
1428 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1429 child = child->next;
1430 }
1431 if (child != NULL) {
1432 xmlSchemaErrorContext(ctxt, schema, node, child);
1433 if ((ctxt != NULL) && (ctxt->error != NULL))
1434 ctxt->error(ctxt->userData,
1435 "Sequence %s has unexpected content\n",
1436 type->name);
1437 }
1438
1439 return (type);
1440}
1441
1442/**
1443 * xmlSchemaParseNotation:
1444 * @ctxt: a schema validation context
1445 * @schema: the schema being built
1446 * @node: a subtree containing XML Schema informations
1447 *
1448 * parse a XML schema Notation declaration
1449 *
1450 * Returns the new structure or NULL in case of error
1451 */
1452static xmlSchemaNotationPtr
1453xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1454 xmlNodePtr node)
1455{
1456 xmlChar *name;
1457 xmlSchemaNotationPtr ret;
1458 xmlNodePtr child = NULL;
1459
1460 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1461 return (NULL);
1462 name = xmlGetProp(node, (const xmlChar *) "name");
1463 if (name == NULL) {
1464 xmlSchemaErrorContext(ctxt, schema, node, child);
1465 if ((ctxt != NULL) && (ctxt->error != NULL))
1466 ctxt->error(ctxt->userData, "Notation has no name\n");
1467 return (NULL);
1468 }
1469 ret = xmlSchemaAddNotation(ctxt, schema, name);
1470 if (ret == NULL) {
1471 xmlFree(name);
1472 return (NULL);
1473 }
1474 child = node->children;
1475 if (IS_SCHEMA(child, "annotation")) {
1476 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1477 child = child->next;
1478 }
1479 if (child != NULL) {
1480 xmlSchemaErrorContext(ctxt, schema, node, child);
1481 if ((ctxt != NULL) && (ctxt->error != NULL))
1482 ctxt->error(ctxt->userData,
1483 "notation %s has unexpected content\n",
1484 name);
1485 }
1486
1487 return (ret);
1488}
1489
1490/**
1491 * xmlSchemaParseAnyAttribute:
1492 * @ctxt: a schema validation context
1493 * @schema: the schema being built
1494 * @node: a subtree containing XML Schema informations
1495 *
1496 * parse a XML schema AnyAttrribute declaration
1497 * *WARNING* this interface is highly subject to change
1498 *
1499 * Returns an attribute def structure or NULL
1500 */
1501static xmlSchemaAttributePtr
1502xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1503 xmlNodePtr node)
1504{
1505 xmlChar *processContents;
1506 xmlSchemaAttributePtr ret;
1507 xmlNodePtr child = NULL;
1508 char name[100];
1509
1510 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1511 return (NULL);
1512
1513 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
1514 ret = xmlSchemaAddAttribute(ctxt, schema, (xmlChar *)name);
1515 if (ret == NULL) {
1516 return (NULL);
1517 }
1518 ret->id = xmlGetProp(node, (const xmlChar *) "id");
1519 processContents = xmlGetProp(node, (const xmlChar *) "processContents");
1520 if ((processContents == NULL) ||
1521 (xmlStrEqual(processContents, (const xmlChar *)"strict"))) {
1522 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1523 } else if (xmlStrEqual(processContents, (const xmlChar *)"skip")) {
1524 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1525 } else if (xmlStrEqual(processContents, (const xmlChar *)"lax")) {
1526 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
1527 } else {
1528 xmlSchemaErrorContext(ctxt, schema, node, child);
1529 if ((ctxt != NULL) && (ctxt->error != NULL))
1530 ctxt->error(ctxt->userData,
1531 "anyAttribute has unexpected content for processContents: %s\n",
1532 processContents);
1533 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1534 }
1535 if (processContents != NULL)
1536 xmlFree(processContents);
1537
1538 child = node->children;
1539 if (IS_SCHEMA(child, "annotation")) {
1540 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1541 child = child->next;
1542 }
1543 if (child != NULL) {
1544 xmlSchemaErrorContext(ctxt, schema, node, child);
1545 if ((ctxt != NULL) && (ctxt->error != NULL))
1546 ctxt->error(ctxt->userData,
1547 "anyAttribute %s has unexpected content\n",
1548 name);
1549 }
1550
1551 return (ret);
1552}
1553
1554
1555/**
1556 * xmlSchemaParseAttribute:
1557 * @ctxt: a schema validation context
1558 * @schema: the schema being built
1559 * @node: a subtree containing XML Schema informations
1560 *
1561 * parse a XML schema Attrribute declaration
1562 * *WARNING* this interface is highly subject to change
1563 *
1564 * Returns -1 in case of error, 0 if the declaration is inproper and
1565 * 1 in case of success.
1566 */
1567static xmlSchemaAttributePtr
1568xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1569 xmlNodePtr node)
1570{
1571 xmlChar *name, *refNs = NULL, *ref = NULL;
1572 xmlSchemaAttributePtr ret;
1573 xmlNodePtr child = NULL;
1574
1575 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1576 return (NULL);
1577 name = xmlGetProp(node, (const xmlChar *) "name");
1578 if (name == NULL) {
1579 char buf[100];
1580
1581 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1582 if (ref == NULL) {
1583 xmlSchemaErrorContext(ctxt, schema, node, child);
1584 if ((ctxt != NULL) && (ctxt->error != NULL))
1585 ctxt->error(ctxt->userData, "Attribute has no name nor ref\n");
1586 return (NULL);
1587 }
1588 snprintf(buf, 99, "anonattr%d", ctxt->counter++ + 1);
1589 name = xmlStrdup((xmlChar *) buf);
1590 }
1591 ret = xmlSchemaAddAttribute(ctxt, schema, name);
1592 if (ret == NULL) {
1593 xmlFree(name);
1594 if (ref != NULL)
1595 xmlFree(ref);
1596 return (NULL);
1597 }
1598 xmlFree(name);
1599 ret->ref = ref;
1600 ret->refNs = refNs;
1601 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
1602 child = node->children;
1603 if (IS_SCHEMA(child, "annotation")) {
1604 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1605 child = child->next;
1606 }
1607 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillard88c58912002-04-23 07:12:20 +00001608 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001609 child = child->next;
1610 }
1611 if (child != NULL) {
1612 xmlSchemaErrorContext(ctxt, schema, node, child);
1613 if ((ctxt != NULL) && (ctxt->error != NULL))
1614 ctxt->error(ctxt->userData,
1615 "attribute %s has unexpected content\n",
1616 name);
1617 }
1618
1619 return (ret);
1620}
1621
1622/**
1623 * xmlSchemaParseAttributeGroup:
1624 * @ctxt: a schema validation context
1625 * @schema: the schema being built
1626 * @node: a subtree containing XML Schema informations
1627 *
1628 * parse a XML schema Attribute Group declaration
1629 * *WARNING* this interface is highly subject to change
1630 *
1631 * Returns the attribute group or NULL in case of error.
1632 */
1633static xmlSchemaAttributeGroupPtr
1634xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1635 xmlNodePtr node)
1636{
1637 xmlChar *name, *refNs = NULL, *ref = NULL;
1638 xmlSchemaAttributeGroupPtr ret;
1639 xmlSchemaAttributePtr last = NULL, attr;
1640 xmlNodePtr child = NULL;
1641 xmlChar *oldcontainer;
1642
1643 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1644 return (NULL);
1645 oldcontainer = ctxt->container;
1646 name = xmlGetProp(node, (const xmlChar *) "name");
1647 if (name == NULL) {
1648 char buf[100];
1649
1650 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1651 if (ref == NULL) {
1652 xmlSchemaErrorContext(ctxt, schema, node, child);
1653 if ((ctxt != NULL) && (ctxt->error != NULL))
1654 ctxt->error(ctxt->userData,
1655 "AttributeGroup has no name nor ref\n");
1656 return (NULL);
1657 }
1658 snprintf(buf, 99, "anonattrgroup%d", ctxt->counter++ + 1);
1659 name = xmlStrdup((xmlChar *) buf);
1660 }
1661 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
1662 if (ret == NULL) {
1663 xmlFree(name);
1664 if (ref != NULL)
1665 xmlFree(ref);
1666 return (NULL);
1667 }
1668 ret->ref = ref;
1669 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00001670 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard4255d502002-04-16 15:50:10 +00001671 child = node->children;
1672 ctxt->container = name;
1673 if (IS_SCHEMA(child, "annotation")) {
1674 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1675 child = child->next;
1676 }
1677 while ((IS_SCHEMA(child, "attribute")) ||
1678 (IS_SCHEMA(child, "attributeGroup"))) {
1679 attr = NULL;
1680 if (IS_SCHEMA(child, "attribute")) {
1681 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1682 } else if (IS_SCHEMA(child, "attributeGroup")) {
1683 attr = (xmlSchemaAttributePtr)
1684 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1685 }
1686 if (attr != NULL) {
1687 if (last == NULL) {
1688 ret->attributes = attr;
1689 last = attr;
1690 } else {
1691 last->next = attr;
1692 last = attr;
1693 }
1694 }
1695 child = child->next;
1696 }
1697 if (IS_SCHEMA(child, "anyAttribute")) {
1698 TODO
1699 child = child->next;
1700 }
1701 if (child != NULL) {
1702 xmlSchemaErrorContext(ctxt, schema, node, child);
1703 if ((ctxt != NULL) && (ctxt->error != NULL))
1704 ctxt->error(ctxt->userData,
1705 "attribute group %s has unexpected content\n",
1706 name);
1707 }
1708
1709 ctxt->container = oldcontainer;
1710 return (ret);
1711}
1712
1713/**
1714 * xmlSchemaParseElement:
1715 * @ctxt: a schema validation context
1716 * @schema: the schema being built
1717 * @node: a subtree containing XML Schema informations
1718 *
1719 * parse a XML schema Element declaration
1720 * *WARNING* this interface is highly subject to change
1721 *
1722 * Returns -1 in case of error, 0 if the declaration is inproper and
1723 * 1 in case of success.
1724 */
1725static xmlSchemaElementPtr
1726xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1727 xmlNodePtr node, int toplevel)
1728{
1729 xmlChar *name, *refNs = NULL, *ref = NULL, *namespace, *fixed;
1730 xmlSchemaElementPtr ret;
1731 xmlNodePtr child = NULL;
1732 xmlChar *oldcontainer;
1733
1734 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1735 return (NULL);
1736 oldcontainer = ctxt->container;
1737 name = xmlGetProp(node, (const xmlChar *) "name");
1738 if (name == NULL) {
1739 char buf[100];
1740
1741 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1742 if (ref == NULL) {
1743 xmlSchemaErrorContext(ctxt, schema, node, child);
1744 if ((ctxt != NULL) && (ctxt->error != NULL))
1745 ctxt->error(ctxt->userData, "Element has no name nor ref\n");
1746 return (NULL);
1747 }
1748 snprintf(buf, 99, "anonelem%d", ctxt->counter++ + 1);
1749 name = xmlStrdup((xmlChar *) buf);
1750 }
1751 namespace = xmlGetProp(node, (const xmlChar *) "targetNamespace");
1752 if (namespace == NULL)
1753 ret =
1754 xmlSchemaAddElement(ctxt, schema, name,
1755 schema->targetNamespace);
1756 else
1757 ret = xmlSchemaAddElement(ctxt, schema, name, namespace);
1758 if (namespace != NULL)
1759 xmlFree(namespace);
1760 if (ret == NULL) {
1761 xmlFree(name);
1762 if (ref != NULL)
1763 xmlFree(ref);
1764 return (NULL);
1765 }
1766 ret->type = XML_SCHEMA_TYPE_ELEMENT;
1767 ret->ref = ref;
1768 ret->refNs = refNs;
1769 if (ref != NULL)
1770 ret->flags |= XML_SCHEMAS_ELEM_REF;
1771 if (toplevel)
1772 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
1773 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
1774 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1775 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
1776 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
1777 ctxt->container = name;
1778
1779 ret->id = xmlGetProp(node, BAD_CAST "id");
1780 ret->namedType = xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
1781 ret->substGroup = xmlGetQNameProp(ctxt, node, "substitutionGroup",
1782 &(ret->substGroupNs));
1783 fixed = xmlGetProp(node, BAD_CAST "fixed");
1784 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
1785 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1786
1787 ret->value = xmlGetProp(node, BAD_CAST "default");
1788 if ((ret->value != NULL) && (fixed != NULL)) {
1789 xmlSchemaErrorContext(ctxt, schema, node, child);
1790 ctxt->error(ctxt->userData,
1791 "Element %s has both default and fixed\n",
1792 ret->name);
1793 xmlFree(fixed);
1794 } else if (fixed != NULL) {
1795 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
1796 ret->value = fixed;
1797 }
1798
1799 child = node->children;
1800 if (IS_SCHEMA(child, "annotation")) {
1801 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1802 child = child->next;
1803 }
1804 if (IS_SCHEMA(child, "complexType")) {
1805 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
1806 child = child->next;
1807 } else if (IS_SCHEMA(child, "simpleType")) {
1808 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
1809 child = child->next;
1810 }
1811 while ((IS_SCHEMA(child, "unique")) ||
1812 (IS_SCHEMA(child, "key")) ||
1813 (IS_SCHEMA(child, "keyref"))) {
1814 TODO
1815 child = child->next;
1816 }
1817 if (child != NULL) {
1818 xmlSchemaErrorContext(ctxt, schema, node, child);
1819 if ((ctxt != NULL) && (ctxt->error != NULL))
1820 ctxt->error(ctxt->userData,
1821 "element %s has unexpected content\n",
1822 name);
1823 }
1824
1825 ctxt->container = oldcontainer;
1826 xmlFree(name);
1827 return (ret);
1828}
1829
1830/**
1831 * xmlSchemaParseUnion:
1832 * @ctxt: a schema validation context
1833 * @schema: the schema being built
1834 * @node: a subtree containing XML Schema informations
1835 *
1836 * parse a XML schema Union definition
1837 * *WARNING* this interface is highly subject to change
1838 *
1839 * Returns -1 in case of error, 0 if the declaration is inproper and
1840 * 1 in case of success.
1841 */
1842static xmlSchemaTypePtr
1843xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1844 xmlNodePtr node)
1845{
1846 xmlSchemaTypePtr type, subtype, last = NULL;
1847 xmlNodePtr child = NULL;
1848 xmlChar name[30];
1849
1850 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1851 return (NULL);
1852
1853
1854 snprintf((char *)name, 30, "union %d", ctxt->counter++ + 1);
1855 type = xmlSchemaAddType(ctxt, schema, name);
1856 if (type == NULL)
1857 return (NULL);
1858 type->node = node;
1859 type->type = XML_SCHEMA_TYPE_LIST;
1860 type->id = xmlGetProp(node, BAD_CAST "id");
1861 type->ref = xmlGetProp(node, BAD_CAST "memberTypes");
1862
1863 child = node->children;
1864 if (IS_SCHEMA(child, "annotation")) {
1865 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1866 child = child->next;
1867 }
1868 while (IS_SCHEMA(child, "simpleType")) {
1869 subtype = (xmlSchemaTypePtr)
1870 xmlSchemaParseSimpleType(ctxt, schema, child);
1871 if (subtype != NULL) {
1872 if (last == NULL) {
1873 type->subtypes = subtype;
1874 last = subtype;
1875 } else {
1876 last->next = subtype;
1877 last = subtype;
1878 }
1879 last->next = NULL;
1880 }
1881 child = child->next;
1882 }
1883 if (child != NULL) {
1884 xmlSchemaErrorContext(ctxt, schema, node, child);
1885 if ((ctxt != NULL) && (ctxt->error != NULL))
1886 ctxt->error(ctxt->userData,
1887 "Union %s has unexpected content\n",
1888 type->name);
1889 }
1890 return (type);
1891}
1892
1893/**
1894 * xmlSchemaParseList:
1895 * @ctxt: a schema validation context
1896 * @schema: the schema being built
1897 * @node: a subtree containing XML Schema informations
1898 *
1899 * parse a XML schema List definition
1900 * *WARNING* this interface is highly subject to change
1901 *
1902 * Returns -1 in case of error, 0 if the declaration is inproper and
1903 * 1 in case of success.
1904 */
1905static xmlSchemaTypePtr
1906xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1907 xmlNodePtr node)
1908{
1909 xmlSchemaTypePtr type, subtype;
1910 xmlNodePtr child = NULL;
1911 xmlChar name[30];
1912
1913 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1914 return (NULL);
1915
1916 snprintf((char *)name, 30, "list %d", ctxt->counter++ + 1);
1917 type = xmlSchemaAddType(ctxt, schema, name);
1918 if (type == NULL)
1919 return (NULL);
1920 type->node = node;
1921 type->type = XML_SCHEMA_TYPE_LIST;
1922 type->id = xmlGetProp(node, BAD_CAST "id");
1923 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
1924
1925 child = node->children;
1926 if (IS_SCHEMA(child, "annotation")) {
1927 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1928 child = child->next;
1929 }
1930 subtype = NULL;
1931 if (IS_SCHEMA(child, "simpleType")) {
1932 subtype = (xmlSchemaTypePtr)
1933 xmlSchemaParseSimpleType(ctxt, schema, child);
1934 child = child->next;
1935 type->subtypes = subtype;
1936 }
1937 if (child != NULL) {
1938 xmlSchemaErrorContext(ctxt, schema, node, child);
1939 if ((ctxt != NULL) && (ctxt->error != NULL))
1940 ctxt->error(ctxt->userData,
1941 "List %s has unexpected content\n",
1942 type->name);
1943 }
1944 return (type);
1945}
1946/**
1947 * xmlSchemaParseSimpleType:
1948 * @ctxt: a schema validation context
1949 * @schema: the schema being built
1950 * @node: a subtree containing XML Schema informations
1951 *
1952 * parse a XML schema Simple Type definition
1953 * *WARNING* this interface is highly subject to change
1954 *
1955 * Returns -1 in case of error, 0 if the declaration is inproper and
1956 * 1 in case of success.
1957 */
1958static xmlSchemaTypePtr
1959xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1960 xmlNodePtr node)
1961{
1962 xmlSchemaTypePtr type, subtype;
1963 xmlNodePtr child = NULL;
1964 xmlChar *name;
1965
1966 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1967 return (NULL);
1968
1969
1970 name = xmlGetProp(node, (const xmlChar *) "name");
1971 if (name == NULL) {
1972 char buf[100];
1973
1974 snprintf(buf, 99, "simpletype%d", ctxt->counter++ + 1);
1975 name = xmlStrdup((xmlChar *) buf);
1976 }
1977 if (name == NULL) {
1978 xmlSchemaErrorContext(ctxt, schema, node, child);
1979 if ((ctxt != NULL) && (ctxt->error != NULL))
1980 ctxt->error(ctxt->userData, "simpleType has no name\n");
1981 return (NULL);
1982 }
1983 type = xmlSchemaAddType(ctxt, schema, name);
1984 xmlFree(name);
1985 if (type == NULL)
1986 return (NULL);
1987 type->node = node;
1988 type->type = XML_SCHEMA_TYPE_SIMPLE;
1989 type->id = xmlGetProp(node, BAD_CAST "id");
1990
1991 child = node->children;
1992 if (IS_SCHEMA(child, "annotation")) {
1993 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1994 child = child->next;
1995 }
1996 subtype = NULL;
1997 if (IS_SCHEMA(child, "restriction")) {
1998 subtype = (xmlSchemaTypePtr)
1999 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2000 child = child->next;
2001 } else if (IS_SCHEMA(child, "list")) {
2002 subtype = (xmlSchemaTypePtr)
2003 xmlSchemaParseList(ctxt, schema, child);
2004 child = child->next;
2005 } else if (IS_SCHEMA(child, "union")) {
2006 subtype = (xmlSchemaTypePtr)
2007 xmlSchemaParseUnion(ctxt, schema, child);
2008 child = child->next;
2009 }
2010 type->subtypes = subtype;
2011 if (child != NULL) {
2012 xmlSchemaErrorContext(ctxt, schema, node, child);
2013 if ((ctxt != NULL) && (ctxt->error != NULL))
2014 ctxt->error(ctxt->userData,
2015 "SimpleType %s has unexpected content\n",
2016 type->name);
2017 }
2018
2019 return (type);
2020}
2021
2022
2023/**
2024 * xmlSchemaParseGroup:
2025 * @ctxt: a schema validation context
2026 * @schema: the schema being built
2027 * @node: a subtree containing XML Schema informations
2028 *
2029 * parse a XML schema Group definition
2030 * *WARNING* this interface is highly subject to change
2031 *
2032 * Returns -1 in case of error, 0 if the declaration is inproper and
2033 * 1 in case of success.
2034 */
2035static xmlSchemaTypePtr
2036xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2037 xmlNodePtr node)
2038{
2039 xmlSchemaTypePtr type, subtype;
2040 xmlNodePtr child = NULL;
2041 xmlChar *name, *ref = NULL, *refNs = NULL;
2042
2043 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2044 return (NULL);
2045
2046
2047 name = xmlGetProp(node, (const xmlChar *) "name");
2048 if (name == NULL) {
2049 char buf[100];
2050
2051 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2052 if (ref == NULL) {
2053 xmlSchemaErrorContext(ctxt, schema, node, child);
2054 if ((ctxt != NULL) && (ctxt->error != NULL))
2055 ctxt->error(ctxt->userData, "Group has no name nor ref\n");
2056 return (NULL);
2057 }
2058 snprintf(buf, 99, "anongroup%d", ctxt->counter++ + 1);
2059 name = xmlStrdup((xmlChar *) buf);
2060 }
2061 type = xmlSchemaAddType(ctxt, schema, name);
2062 if (type == NULL)
2063 return (NULL);
2064 type->node = node;
2065 type->type = XML_SCHEMA_TYPE_GROUP;
2066 type->id = xmlGetProp(node, BAD_CAST "id");
2067 type->ref = ref;
2068 type->refNs = refNs;
2069 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2070 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2071
2072 child = node->children;
2073 if (IS_SCHEMA(child, "annotation")) {
2074 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2075 child = child->next;
2076 }
2077 subtype = NULL;
2078 if (IS_SCHEMA(child, "all")) {
2079 subtype = (xmlSchemaTypePtr)
2080 xmlSchemaParseAll(ctxt, schema, child);
2081 child = child->next;
2082 } else if (IS_SCHEMA(child, "choice")) {
2083 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2084 child = child->next;
2085 } else if (IS_SCHEMA(child, "sequence")) {
2086 subtype = (xmlSchemaTypePtr)
2087 xmlSchemaParseSequence(ctxt, schema, child);
2088 child = child->next;
2089 }
2090 if (subtype != NULL)
2091 type->subtypes = subtype;
2092 if (child != NULL) {
2093 xmlSchemaErrorContext(ctxt, schema, node, child);
2094 if ((ctxt != NULL) && (ctxt->error != NULL))
2095 ctxt->error(ctxt->userData,
2096 "Group %s has unexpected content\n",
2097 type->name);
2098 }
2099
2100 return (type);
2101}
2102
2103/**
2104 * xmlSchemaParseAll:
2105 * @ctxt: a schema validation context
2106 * @schema: the schema being built
2107 * @node: a subtree containing XML Schema informations
2108 *
2109 * parse a XML schema All definition
2110 * *WARNING* this interface is highly subject to change
2111 *
2112 * Returns -1 in case of error, 0 if the declaration is inproper and
2113 * 1 in case of success.
2114 */
2115static xmlSchemaTypePtr
2116xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2117 xmlNodePtr node)
2118{
2119 xmlSchemaTypePtr type, subtype, last = NULL;
2120 xmlNodePtr child = NULL;
2121 xmlChar name[30];
2122
2123 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2124 return (NULL);
2125
2126
2127 snprintf((char *)name, 30, "all%d", ctxt->counter++ + 1);
2128 type = xmlSchemaAddType(ctxt, schema, name);
2129 if (type == NULL)
2130 return (NULL);
2131 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002132 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002133 type->id = xmlGetProp(node, BAD_CAST "id");
2134 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2135 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2136
2137 child = node->children;
2138 if (IS_SCHEMA(child, "annotation")) {
2139 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2140 child = child->next;
2141 }
2142 while (IS_SCHEMA(child, "element")) {
2143 subtype = (xmlSchemaTypePtr)
2144 xmlSchemaParseElement(ctxt, schema, child, 0);
2145 if (subtype != NULL) {
2146 if (last == NULL) {
2147 type->subtypes = subtype;
2148 last = subtype;
2149 } else {
2150 last->next = subtype;
2151 last = subtype;
2152 }
2153 last->next = NULL;
2154 }
2155 child = child->next;
2156 }
2157 if (child != NULL) {
2158 xmlSchemaErrorContext(ctxt, schema, node, child);
2159 if ((ctxt != NULL) && (ctxt->error != NULL))
2160 ctxt->error(ctxt->userData,
2161 "All %s has unexpected content\n",
2162 type->name);
2163 }
2164
2165 return (type);
2166}
2167
2168/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002169 * xmlSchemaParseImport:
2170 * @ctxt: a schema validation context
2171 * @schema: the schema being built
2172 * @node: a subtree containing XML Schema informations
2173 *
2174 * parse a XML schema Import definition
2175 * *WARNING* this interface is highly subject to change
2176 *
2177 * Returns -1 in case of error, 0 if the declaration is inproper and
2178 * 1 in case of success.
2179 */
2180static int
2181xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2182 xmlNodePtr node)
2183{
2184 xmlNodePtr child = NULL;
2185 xmlChar *namespace;
2186 xmlChar *schemaLocation;
2187 xmlChar *previous;
2188 xmlURIPtr check;
2189
2190 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2191 return (-1);
2192
2193 namespace = xmlGetProp(node, BAD_CAST "namespace");
2194 if (namespace != NULL) {
2195 check = xmlParseURI((const char *) namespace);
2196 if (check == NULL) {
2197 xmlSchemaErrorContext(ctxt, schema, node, child);
2198 if ((ctxt != NULL) && (ctxt->error != NULL))
2199 ctxt->error(ctxt->userData,
2200 "Import namespace attribute is not an URI: %s\n",
2201 namespace);
2202 xmlFree(namespace);
2203 return(-1);
2204 } else {
2205 xmlFreeURI(check);
2206 }
2207 }
2208 schemaLocation = xmlGetProp(node, BAD_CAST "schemaLocation");
2209 if (schemaLocation != NULL) {
2210 check = xmlParseURI((const char *) schemaLocation);
2211 if (check == NULL) {
2212 xmlSchemaErrorContext(ctxt, schema, node, child);
2213 if ((ctxt != NULL) && (ctxt->error != NULL))
2214 ctxt->error(ctxt->userData,
2215 "Import schemaLocation attribute is not an URI: %s\n",
2216 schemaLocation);
2217 if (namespace != NULL)
2218 xmlFree(namespace);
2219 xmlFree(schemaLocation);
2220 return(-1);
2221 } else {
2222 xmlFreeURI(check);
2223 }
2224 }
2225 if (schema->schemasImports == NULL) {
2226 schema->schemasImports = xmlHashCreate(10);
2227 if (schema->schemasImports == NULL) {
2228 xmlSchemaErrorContext(ctxt, schema, node, child);
2229 if ((ctxt != NULL) && (ctxt->error != NULL))
2230 ctxt->error(ctxt->userData,
2231 "Internal: failed to build import table\n");
2232 if (namespace != NULL)
2233 xmlFree(namespace);
2234 if (schemaLocation != NULL)
2235 xmlFree(schemaLocation);
2236 return(-1);
2237 }
2238 }
2239 if (namespace == NULL) {
2240 previous = xmlHashLookup(schema->schemasImports,
2241 XML_SCHEMAS_DEFAULT_NAMESPACE);
2242 if (schemaLocation != NULL) {
2243 if (previous != NULL) {
2244 if (!xmlStrEqual(schemaLocation, previous)) {
2245 xmlSchemaErrorContext(ctxt, schema, node, child);
2246 if ((ctxt != NULL) && (ctxt->error != NULL))
2247 ctxt->error(ctxt->userData,
2248 "Redefining import for default namespace with a different URI: %s\n",
2249 schemaLocation);
2250 }
2251 } else {
2252 xmlHashAddEntry(schema->schemasImports,
2253 XML_SCHEMAS_DEFAULT_NAMESPACE, schemaLocation);
2254 }
2255 }
2256 } else {
2257 previous = xmlHashLookup(schema->schemasImports, namespace);
2258 if (schemaLocation != NULL) {
2259 if (previous != NULL) {
2260 if (!xmlStrEqual(schemaLocation, previous)) {
2261 xmlSchemaErrorContext(ctxt, schema, node, child);
2262 if ((ctxt != NULL) && (ctxt->error != NULL))
2263 ctxt->error(ctxt->userData,
2264 "Redefining import for namespace %s with a different URI: %s\n",
2265 namespace, schemaLocation);
2266 }
2267 } else {
2268 xmlHashAddEntry(schema->schemasImports,
2269 namespace, schemaLocation);
2270 }
2271 }
2272 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002273
2274 child = node->children;
2275 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillard7c13af42002-05-22 09:57:32 +00002276 /*
2277 * the annotations here are simply discarded ...
2278 */
Daniel Veillard5a872412002-05-22 06:40:27 +00002279 child = child->next;
2280 }
2281 if (child != NULL) {
2282 xmlSchemaErrorContext(ctxt, schema, node, child);
2283 if ((ctxt != NULL) && (ctxt->error != NULL))
2284 ctxt->error(ctxt->userData,
2285 "Import has unexpected content\n");
2286 return(-1);
2287 }
2288 return(1);
2289}
2290
2291/**
Daniel Veillard4255d502002-04-16 15:50:10 +00002292 * xmlSchemaParseChoice:
2293 * @ctxt: a schema validation context
2294 * @schema: the schema being built
2295 * @node: a subtree containing XML Schema informations
2296 *
2297 * parse a XML schema Choice definition
2298 * *WARNING* this interface is highly subject to change
2299 *
2300 * Returns -1 in case of error, 0 if the declaration is inproper and
2301 * 1 in case of success.
2302 */
2303static xmlSchemaTypePtr
2304xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2305 xmlNodePtr node)
2306{
2307 xmlSchemaTypePtr type, subtype, last = NULL;
2308 xmlNodePtr child = NULL;
2309 xmlChar name[30];
2310
2311 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2312 return (NULL);
2313
2314
2315 snprintf((char *)name, 30, "choice %d", ctxt->counter++ + 1);
2316 type = xmlSchemaAddType(ctxt, schema, name);
2317 if (type == NULL)
2318 return (NULL);
2319 type->node = node;
2320 type->type = XML_SCHEMA_TYPE_CHOICE;
2321 type->id = xmlGetProp(node, BAD_CAST "id");
2322 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2323 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2324
2325 child = node->children;
2326 if (IS_SCHEMA(child, "annotation")) {
2327 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2328 child = child->next;
2329 }
2330 while ((IS_SCHEMA(child, "element")) ||
2331 (IS_SCHEMA(child, "group")) ||
2332 (IS_SCHEMA(child, "any")) ||
2333 (IS_SCHEMA(child, "choice")) ||
2334 (IS_SCHEMA(child, "sequence"))) {
2335 subtype = NULL;
2336 if (IS_SCHEMA(child, "element")) {
2337 subtype = (xmlSchemaTypePtr)
2338 xmlSchemaParseElement(ctxt, schema, child, 0);
2339 } else if (IS_SCHEMA(child, "group")) {
2340 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2341 } else if (IS_SCHEMA(child, "any")) {
2342 subtype = xmlSchemaParseAny(ctxt, schema, child);
2343 } else if (IS_SCHEMA(child, "sequence")) {
2344 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2345 } else if (IS_SCHEMA(child, "choice")) {
2346 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2347 }
2348 if (subtype != NULL) {
2349 if (last == NULL) {
2350 type->subtypes = subtype;
2351 last = subtype;
2352 } else {
2353 last->next = subtype;
2354 last = subtype;
2355 }
2356 last->next = NULL;
2357 }
2358 child = child->next;
2359 }
2360 if (child != NULL) {
2361 xmlSchemaErrorContext(ctxt, schema, node, child);
2362 if ((ctxt != NULL) && (ctxt->error != NULL))
2363 ctxt->error(ctxt->userData,
2364 "Choice %s has unexpected content\n",
2365 type->name);
2366 }
2367
2368 return (type);
2369}
2370
2371/**
2372 * xmlSchemaParseSequence:
2373 * @ctxt: a schema validation context
2374 * @schema: the schema being built
2375 * @node: a subtree containing XML Schema informations
2376 *
2377 * parse a XML schema Sequence definition
2378 * *WARNING* this interface is highly subject to change
2379 *
2380 * Returns -1 in case of error, 0 if the declaration is inproper and
2381 * 1 in case of success.
2382 */
2383static xmlSchemaTypePtr
2384xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2385 xmlNodePtr node)
2386{
2387 xmlSchemaTypePtr type, subtype, last = NULL;
2388 xmlNodePtr child = NULL;
2389 xmlChar name[30];
2390
2391 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2392 return (NULL);
2393
2394
2395 snprintf((char *)name, 30, "sequence %d", ctxt->counter++ + 1);
2396 type = xmlSchemaAddType(ctxt, schema, name);
2397 if (type == NULL)
2398 return (NULL);
2399 type->node = node;
2400 type->type = XML_SCHEMA_TYPE_SEQUENCE;
2401 type->id = xmlGetProp(node, BAD_CAST "id");
2402 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2403 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2404
2405 child = node->children;
2406 if (IS_SCHEMA(child, "annotation")) {
2407 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2408 child = child->next;
2409 }
2410 while ((IS_SCHEMA(child, "element")) ||
2411 (IS_SCHEMA(child, "group")) ||
2412 (IS_SCHEMA(child, "any")) ||
2413 (IS_SCHEMA(child, "choice")) ||
2414 (IS_SCHEMA(child, "sequence"))) {
2415 subtype = NULL;
2416 if (IS_SCHEMA(child, "element")) {
2417 subtype = (xmlSchemaTypePtr)
2418 xmlSchemaParseElement(ctxt, schema, child, 0);
2419 } else if (IS_SCHEMA(child, "group")) {
2420 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2421 } else if (IS_SCHEMA(child, "any")) {
2422 subtype = xmlSchemaParseAny(ctxt, schema, child);
2423 } else if (IS_SCHEMA(child, "choice")) {
2424 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2425 } else if (IS_SCHEMA(child, "sequence")) {
2426 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2427 }
2428 if (subtype != NULL) {
2429 if (last == NULL) {
2430 type->subtypes = subtype;
2431 last = subtype;
2432 } else {
2433 last->next = subtype;
2434 last = subtype;
2435 }
2436 last->next = NULL;
2437 }
2438 child = child->next;
2439 }
2440 if (child != NULL) {
2441 xmlSchemaErrorContext(ctxt, schema, node, child);
2442 if ((ctxt != NULL) && (ctxt->error != NULL))
2443 ctxt->error(ctxt->userData,
2444 "Sequence %s has unexpected content\n",
2445 type->name);
2446 }
2447
2448 return (type);
2449}
2450
2451/**
2452 * xmlSchemaParseRestriction:
2453 * @ctxt: a schema validation context
2454 * @schema: the schema being built
2455 * @node: a subtree containing XML Schema informations
2456 * @simple: is that part of a simple type.
2457 *
2458 * parse a XML schema Restriction definition
2459 * *WARNING* this interface is highly subject to change
2460 *
2461 * Returns the type definition or NULL in case of error
2462 */
2463static xmlSchemaTypePtr
2464xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2465 xmlNodePtr node, int simple)
2466{
2467 xmlSchemaTypePtr type, subtype;
2468 xmlSchemaFacetPtr facet, lastfacet = NULL;
2469 xmlNodePtr child = NULL;
2470 xmlChar name[30];
2471 xmlChar *oldcontainer;
2472
2473 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2474 return (NULL);
2475
2476 oldcontainer = ctxt->container;
2477
2478 snprintf((char *)name, 30, "restriction %d", ctxt->counter++ + 1);
2479 type = xmlSchemaAddType(ctxt, schema, name);
2480 if (type == NULL)
2481 return (NULL);
2482 type->node = node;
2483 type->type = XML_SCHEMA_TYPE_RESTRICTION;
2484 type->id = xmlGetProp(node, BAD_CAST "id");
2485 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2486 if ((!simple) && (type->base == NULL)) {
2487 xmlSchemaErrorContext(ctxt, schema, node, child);
2488 if ((ctxt != NULL) && (ctxt->error != NULL))
2489 ctxt->error(ctxt->userData,
2490 "Restriction %s has no base\n",
2491 type->name);
2492 }
2493 ctxt->container = name;
2494
2495 child = node->children;
2496 if (IS_SCHEMA(child, "annotation")) {
2497 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2498 child = child->next;
2499 }
2500 subtype = NULL;
2501
2502 if (IS_SCHEMA(child, "all")) {
2503 subtype = (xmlSchemaTypePtr)
2504 xmlSchemaParseAll(ctxt, schema, child);
2505 child = child->next;
2506 type->subtypes = subtype;
2507 } else if (IS_SCHEMA(child, "choice")) {
2508 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2509 child = child->next;
2510 type->subtypes = subtype;
2511 } else if (IS_SCHEMA(child, "sequence")) {
2512 subtype = (xmlSchemaTypePtr)
2513 xmlSchemaParseSequence(ctxt, schema, child);
2514 child = child->next;
2515 type->subtypes = subtype;
2516 } else if (IS_SCHEMA(child, "group")) {
2517 subtype = (xmlSchemaTypePtr)
2518 xmlSchemaParseGroup(ctxt, schema, child);
2519 child = child->next;
2520 type->subtypes = subtype;
2521 } else {
2522 if (IS_SCHEMA(child, "simpleType")) {
2523 subtype = (xmlSchemaTypePtr)
2524 xmlSchemaParseSimpleType(ctxt, schema, child);
2525 child = child->next;
2526 type->baseType = subtype;
2527 }
2528 /*
2529 * Facets
2530 */
2531 while ((IS_SCHEMA(child, "minInclusive")) ||
2532 (IS_SCHEMA(child, "minExclusive")) ||
2533 (IS_SCHEMA(child, "maxInclusive")) ||
2534 (IS_SCHEMA(child, "maxExclusive")) ||
2535 (IS_SCHEMA(child, "totalDigits")) ||
2536 (IS_SCHEMA(child, "fractionDigits")) ||
2537 (IS_SCHEMA(child, "pattern")) ||
2538 (IS_SCHEMA(child, "enumeration")) ||
2539 (IS_SCHEMA(child, "whiteSpace")) ||
2540 (IS_SCHEMA(child, "length")) ||
2541 (IS_SCHEMA(child, "maxLength")) ||
2542 (IS_SCHEMA(child, "minLength"))) {
2543 facet = xmlSchemaParseFacet(ctxt, schema, child);
2544 if (facet != NULL) {
2545 if (lastfacet == NULL) {
2546 type->facets = facet;
2547 lastfacet = facet;
2548 } else {
2549 lastfacet->next = facet;
2550 lastfacet = facet;
2551 }
2552 lastfacet->next = NULL;
2553 }
2554 child = child->next;
2555 }
2556 }
2557 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2558 if (child != NULL) {
2559 xmlSchemaErrorContext(ctxt, schema, node, child);
2560 if ((ctxt != NULL) && (ctxt->error != NULL))
2561 ctxt->error(ctxt->userData,
2562 "Restriction %s has unexpected content\n",
2563 type->name);
2564 }
2565 ctxt->container = oldcontainer;
2566 return (type);
2567}
2568
2569/**
2570 * xmlSchemaParseExtension:
2571 * @ctxt: a schema validation context
2572 * @schema: the schema being built
2573 * @node: a subtree containing XML Schema informations
2574 *
2575 * parse a XML schema Extension definition
2576 * *WARNING* this interface is highly subject to change
2577 *
2578 * Returns the type definition or NULL in case of error
2579 */
2580static xmlSchemaTypePtr
2581xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2582 xmlNodePtr node)
2583{
2584 xmlSchemaTypePtr type, subtype;
2585 xmlNodePtr child = NULL;
2586 xmlChar name[30];
2587 xmlChar *oldcontainer;
2588
2589 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2590 return (NULL);
2591
2592 oldcontainer = ctxt->container;
2593
2594 snprintf((char *)name, 30, "extension %d", ctxt->counter++ + 1);
2595 type = xmlSchemaAddType(ctxt, schema, name);
2596 if (type == NULL)
2597 return (NULL);
2598 type->node = node;
2599 type->type = XML_SCHEMA_TYPE_EXTENSION;
2600 type->id = xmlGetProp(node, BAD_CAST "id");
2601 ctxt->container = name;
2602
2603 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
2604 if (type->base == NULL) {
2605 xmlSchemaErrorContext(ctxt, schema, node, child);
2606 if ((ctxt != NULL) && (ctxt->error != NULL))
2607 ctxt->error(ctxt->userData,
2608 "Extension %s has no base\n",
2609 type->name);
2610 }
2611 child = node->children;
2612 if (IS_SCHEMA(child, "annotation")) {
2613 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2614 child = child->next;
2615 }
2616 subtype = NULL;
2617
2618 if (IS_SCHEMA(child, "all")) {
2619 subtype = xmlSchemaParseAll(ctxt, schema, child);
2620 child = child->next;
2621 } else if (IS_SCHEMA(child, "choice")) {
2622 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2623 child = child->next;
2624 } else if (IS_SCHEMA(child, "sequence")) {
2625 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2626 child = child->next;
2627 } else if (IS_SCHEMA(child, "group")) {
2628 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2629 child = child->next;
2630 }
2631 if (subtype != NULL)
2632 type->subtypes = subtype;
2633 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2634 if (child != NULL) {
2635 xmlSchemaErrorContext(ctxt, schema, node, child);
2636 if ((ctxt != NULL) && (ctxt->error != NULL))
2637 ctxt->error(ctxt->userData,
2638 "Extension %s has unexpected content\n",
2639 type->name);
2640 }
2641 ctxt->container = oldcontainer;
2642 return (type);
2643}
2644
2645/**
2646 * xmlSchemaParseSimpleContent:
2647 * @ctxt: a schema validation context
2648 * @schema: the schema being built
2649 * @node: a subtree containing XML Schema informations
2650 *
2651 * parse a XML schema SimpleContent definition
2652 * *WARNING* this interface is highly subject to change
2653 *
2654 * Returns the type definition or NULL in case of error
2655 */
2656static xmlSchemaTypePtr
2657xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2658 xmlNodePtr node)
2659{
2660 xmlSchemaTypePtr type, subtype;
2661 xmlNodePtr child = NULL;
2662 xmlChar name[30];
2663
2664 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2665 return (NULL);
2666
2667
2668 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2669 type = xmlSchemaAddType(ctxt, schema, name);
2670 if (type == NULL)
2671 return (NULL);
2672 type->node = node;
2673 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
2674 type->id = xmlGetProp(node, BAD_CAST "id");
2675
2676 child = node->children;
2677 if (IS_SCHEMA(child, "annotation")) {
2678 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2679 child = child->next;
2680 }
2681 subtype = NULL;
2682 if (IS_SCHEMA(child, "restriction")) {
2683 subtype = (xmlSchemaTypePtr)
2684 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2685 child = child->next;
2686 } else if (IS_SCHEMA(child, "extension")) {
2687 subtype = (xmlSchemaTypePtr)
2688 xmlSchemaParseExtension(ctxt, schema, child);
2689 child = child->next;
2690 }
2691 type->subtypes = subtype;
2692 if (child != NULL) {
2693 xmlSchemaErrorContext(ctxt, schema, node, child);
2694 if ((ctxt != NULL) && (ctxt->error != NULL))
2695 ctxt->error(ctxt->userData,
2696 "SimpleContent %s has unexpected content\n",
2697 type->name);
2698 }
2699 return (type);
2700}
2701
2702/**
2703 * xmlSchemaParseComplexContent:
2704 * @ctxt: a schema validation context
2705 * @schema: the schema being built
2706 * @node: a subtree containing XML Schema informations
2707 *
2708 * parse a XML schema ComplexContent definition
2709 * *WARNING* this interface is highly subject to change
2710 *
2711 * Returns the type definition or NULL in case of error
2712 */
2713static xmlSchemaTypePtr
2714xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2715 xmlNodePtr node)
2716{
2717 xmlSchemaTypePtr type, subtype;
2718 xmlNodePtr child = NULL;
2719 xmlChar name[30];
2720
2721 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2722 return (NULL);
2723
2724
2725 snprintf((char *)name, 30, "complexContent %d", ctxt->counter++ + 1);
2726 type = xmlSchemaAddType(ctxt, schema, name);
2727 if (type == NULL)
2728 return (NULL);
2729 type->node = node;
2730 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
2731 type->id = xmlGetProp(node, BAD_CAST "id");
2732
2733 child = node->children;
2734 if (IS_SCHEMA(child, "annotation")) {
2735 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2736 child = child->next;
2737 }
2738 subtype = NULL;
2739 if (IS_SCHEMA(child, "restriction")) {
2740 subtype = (xmlSchemaTypePtr)
2741 xmlSchemaParseRestriction(ctxt, schema, child, 0);
2742 child = child->next;
2743 } else if (IS_SCHEMA(child, "extension")) {
2744 subtype = (xmlSchemaTypePtr)
2745 xmlSchemaParseExtension(ctxt, schema, child);
2746 child = child->next;
2747 }
2748 type->subtypes = subtype;
2749 if (child != NULL) {
2750 xmlSchemaErrorContext(ctxt, schema, node, child);
2751 if ((ctxt != NULL) && (ctxt->error != NULL))
2752 ctxt->error(ctxt->userData,
2753 "ComplexContent %s has unexpected content\n",
2754 type->name);
2755 }
2756 return (type);
2757}
2758
2759/**
2760 * xmlSchemaParseComplexType:
2761 * @ctxt: a schema validation context
2762 * @schema: the schema being built
2763 * @node: a subtree containing XML Schema informations
2764 *
2765 * parse a XML schema Complex Type definition
2766 * *WARNING* this interface is highly subject to change
2767 *
2768 * Returns the type definition or NULL in case of error
2769 */
2770static xmlSchemaTypePtr
2771xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2772 xmlNodePtr node)
2773{
2774 xmlSchemaTypePtr type, subtype;
2775 xmlNodePtr child = NULL;
2776 xmlChar *name;
2777 xmlChar *oldcontainer;
2778
2779 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2780 return (NULL);
2781
2782 oldcontainer = ctxt->container;
2783 name = xmlGetProp(node, (const xmlChar *) "name");
2784 if (name == NULL) {
2785 char buf[100];
2786
2787 snprintf(buf, 99, "anontype%d", ctxt->counter++ + 1);
2788 name = xmlStrdup((xmlChar *) buf);
2789 }
2790 if (name == NULL) {
2791 xmlSchemaErrorContext(ctxt, schema, node, child);
2792 if ((ctxt != NULL) && (ctxt->error != NULL))
2793 ctxt->error(ctxt->userData, "complexType has no name\n");
2794 return (NULL);
2795 }
2796 type = xmlSchemaAddType(ctxt, schema, name);
2797 if (type == NULL) {
2798 xmlFree(name);
2799 return (NULL);
2800 }
2801 type->node = node;
2802 type->type = XML_SCHEMA_TYPE_COMPLEX;
2803 type->id = xmlGetProp(node, BAD_CAST "id");
2804 ctxt->container = name;
2805
2806 child = node->children;
2807 if (IS_SCHEMA(child, "annotation")) {
2808 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2809 child = child->next;
2810 }
2811 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillarddecd64d2002-04-18 14:41:51 +00002812 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002813 child = child->next;
2814 } else if (IS_SCHEMA(child, "complexContent")) {
2815 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
2816 child = child->next;
2817 } else {
2818 subtype = NULL;
2819
2820 if (IS_SCHEMA(child, "all")) {
2821 subtype = xmlSchemaParseAll(ctxt, schema, child);
2822 child = child->next;
2823 } else if (IS_SCHEMA(child, "choice")) {
2824 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2825 child = child->next;
2826 } else if (IS_SCHEMA(child, "sequence")) {
2827 subtype = xmlSchemaParseSequence(ctxt, schema, child);
2828 child = child->next;
2829 } else if (IS_SCHEMA(child, "group")) {
2830 subtype = xmlSchemaParseGroup(ctxt, schema, child);
2831 child = child->next;
2832 }
2833 if (subtype != NULL)
2834 type->subtypes = subtype;
2835 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
2836 }
2837 if (child != NULL) {
2838 xmlSchemaErrorContext(ctxt, schema, node, child);
2839 if ((ctxt != NULL) && (ctxt->error != NULL))
2840 ctxt->error(ctxt->userData,
2841 "ComplexType %s has unexpected content\n",
2842 type->name);
2843 }
2844 ctxt->container = oldcontainer;
2845 xmlFree(name);
2846 return (type);
2847}
2848
2849
2850/**
2851 * xmlSchemaParseSchema:
2852 * @ctxt: a schema validation context
2853 * @node: a subtree containing XML Schema informations
2854 *
2855 * parse a XML schema definition from a node set
2856 * *WARNING* this interface is highly subject to change
2857 *
2858 * Returns the internal XML Schema structure built from the resource or
2859 * NULL in case of error
2860 */
2861static xmlSchemaPtr
2862xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
2863{
2864 xmlSchemaPtr schema = NULL;
2865 xmlSchemaAnnotPtr annot;
2866 xmlNodePtr child = NULL;
2867 xmlChar *val;
2868
2869 if ((ctxt == NULL) || (node == NULL))
2870 return (NULL);
2871
2872 if (IS_SCHEMA(node, "schema")) {
2873 schema = xmlSchemaNewSchema(ctxt);
2874 if (schema == NULL)
2875 return(NULL);
2876 schema->targetNamespace = xmlGetProp(node, BAD_CAST "targetNamespace");
2877 schema->id = xmlGetProp(node, BAD_CAST "id");
2878 schema->version = xmlGetProp(node, BAD_CAST "version");
2879 val = xmlGetProp(node, BAD_CAST "elementFormDefault");
2880 if (val != NULL) {
2881 if (xmlStrEqual(val, BAD_CAST "qualified"))
2882 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
2883 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
2884 xmlSchemaErrorContext(ctxt, schema, node, child);
2885 if ((ctxt != NULL) && (ctxt->error != NULL)) {
2886 ctxt->error(ctxt->userData,
2887 "Invalid value %s for elementFormDefault\n",
2888 val);
2889 }
2890 }
2891 xmlFree(val);
2892 }
2893 val = xmlGetProp(node, BAD_CAST "attributeFormDefault");
2894 if (val != NULL) {
2895 if (xmlStrEqual(val, BAD_CAST "qualified"))
2896 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
2897 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
2898 xmlSchemaErrorContext(ctxt, schema, node, child);
2899 if ((ctxt != NULL) && (ctxt->error != NULL)) {
2900 ctxt->error(ctxt->userData,
2901 "Invalid value %s for elementFormDefault\n",
2902 val);
2903 }
2904 }
2905 xmlFree(val);
2906 }
2907
2908 child = node->children;
2909 while ((IS_SCHEMA(child, "include")) ||
2910 (IS_SCHEMA(child, "import")) ||
2911 (IS_SCHEMA(child, "redefine")) ||
2912 (IS_SCHEMA(child, "annotation"))) {
2913 if (IS_SCHEMA(child, "annotation")) {
2914 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2915 if (schema->annot == NULL)
2916 schema->annot = annot;
2917 else
2918 xmlSchemaFreeAnnot(annot);
2919 } else if (IS_SCHEMA(child, "include")) {
2920 TODO
2921 } else if (IS_SCHEMA(child, "import")) {
Daniel Veillard5a872412002-05-22 06:40:27 +00002922 xmlSchemaParseImport(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002923 } else if (IS_SCHEMA(child, "redefine")) {
2924 TODO
2925 }
2926 child = child->next;
2927 }
2928 while (child != NULL) {
2929 if (IS_SCHEMA(child, "complexType")) {
2930 xmlSchemaParseComplexType(ctxt, schema, child);
2931 child = child->next;
2932 } else if (IS_SCHEMA(child, "simpleType")) {
2933 xmlSchemaParseSimpleType(ctxt, schema, child);
2934 child = child->next;
2935 } else if (IS_SCHEMA(child, "element")) {
2936 xmlSchemaParseElement(ctxt, schema, child, 1);
2937 child = child->next;
2938 } else if (IS_SCHEMA(child, "attribute")) {
2939 xmlSchemaParseAttribute(ctxt, schema, child);
2940 child = child->next;
2941 } else if (IS_SCHEMA(child, "attributeGroup")) {
2942 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2943 child = child->next;
2944 } else if (IS_SCHEMA(child, "group")) {
2945 xmlSchemaParseGroup(ctxt, schema, child);
2946 child = child->next;
2947 } else if (IS_SCHEMA(child, "notation")) {
2948 xmlSchemaParseNotation(ctxt, schema, child);
2949 child = child->next;
2950 } else {
2951 xmlSchemaErrorContext(ctxt, schema, node, child);
2952 if ((ctxt != NULL) && (ctxt->error != NULL))
2953 ctxt->error(ctxt->userData,
2954 "Schemas: unexpected element %s here \n",
2955 child->name);
2956 child = child->next;
2957 }
2958 while (IS_SCHEMA(child, "annotation")) {
2959 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2960 if (schema->annot == NULL)
2961 schema->annot = annot;
2962 else
2963 xmlSchemaFreeAnnot(annot);
2964 child = child->next;
2965 }
2966 }
2967 }
2968#ifdef DEBUG
2969 if (schema == NULL)
2970 xmlGenericError(xmlGenericErrorContext,
2971 "xmlSchemaParse() failed\n");
2972#endif
2973
2974 return (schema);
2975}
2976
2977/************************************************************************
2978 * *
2979 * Validating using Schemas *
2980 * *
2981 ************************************************************************/
2982
2983/************************************************************************
2984 * *
2985 * Reading/Writing Schemas *
2986 * *
2987 ************************************************************************/
2988
2989/**
2990 * xmlSchemaNewParserCtxt:
2991 * @URL: the location of the schema
2992 *
2993 * Create an XML Schemas parse context for that file/resource expected
2994 * to contain an XML Schemas file.
2995 *
2996 * Returns the parser context or NULL in case of error
2997 */
2998xmlSchemaParserCtxtPtr
2999xmlSchemaNewParserCtxt(const char *URL) {
3000 xmlSchemaParserCtxtPtr ret;
3001
3002 if (URL == NULL)
3003 return(NULL);
3004
3005 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3006 if (ret == NULL) {
3007 xmlGenericError(xmlGenericErrorContext,
3008 "Failed to allocate new schama parser context for %s\n", URL);
3009 return (NULL);
3010 }
3011 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3012 ret->URL = xmlStrdup((const xmlChar *)URL);
3013 return (ret);
3014}
3015
3016/**
3017 * xmlSchemaFreeParserCtxt:
3018 * @ctxt: the schema parser context
3019 *
3020 * Free the resources associated to the schema parser context
3021 */
3022void
3023xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) {
3024 if (ctxt == NULL)
3025 return;
3026 if (ctxt->URL != NULL)
3027 xmlFree(ctxt->URL);
3028 xmlFree(ctxt);
3029}
3030
3031/************************************************************************
3032 * *
3033 * Building the content models *
3034 * *
3035 ************************************************************************/
3036/**
3037 * xmlSchemaBuildAContentModel:
3038 * @type: the schema type definition
3039 * @ctxt: the schema parser context
3040 * @name: the element name whose content is being built
3041 *
3042 * Generate the automata sequence needed for that type
3043 */
3044static void
3045xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
3046 xmlSchemaParserCtxtPtr ctxt,
3047 const xmlChar *name) {
3048 if (type == NULL) {
3049 xmlGenericError(xmlGenericErrorContext,
3050 "Found unexpected type = NULL in %s content model\n",
3051 name);
3052 return;
3053 }
3054 switch (type->type) {
3055 case XML_SCHEMA_TYPE_ANY:
3056 /* TODO : handle the namespace too */
3057 /* TODO : make that a specific transition type */
3058 TODO
3059 ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state,
3060 NULL, BAD_CAST "*", NULL);
3061 break;
3062 case XML_SCHEMA_TYPE_ELEMENT: {
3063 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
3064 /* TODO : handle the namespace too */
3065 xmlAutomataStatePtr oldstate = ctxt->state;
3066 if (elem->maxOccurs >= UNBOUNDED) {
3067 if (elem->refDecl != NULL) {
3068 xmlSchemaBuildAContentModel(
3069 (xmlSchemaTypePtr) elem->refDecl,
3070 ctxt, elem->refDecl->name);
3071 } else {
3072 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3073 ctxt->state, NULL, elem->name, type);
3074 }
3075 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3076 if (elem->minOccurs == 0) {
3077 /* basically an elem* */
3078 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3079 }
3080 } else if (elem->maxOccurs > 1) {
3081 if (elem->refDecl != NULL) {
3082 TODO
3083 xmlSchemaBuildAContentModel(
3084 (xmlSchemaTypePtr) elem->refDecl,
3085 ctxt, elem->refDecl->name);
3086 } else {
3087 ctxt->state = xmlAutomataNewCountTrans(ctxt->am,
3088 ctxt->state, NULL, elem->name,
3089 elem->minOccurs, elem->maxOccurs, type);
3090 }
3091 } else {
3092 if (elem->refDecl != NULL) {
3093 xmlSchemaBuildAContentModel(
3094 (xmlSchemaTypePtr) elem->refDecl,
3095 ctxt, elem->refDecl->name);
3096 } else {
3097 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3098 ctxt->state, NULL, elem->name, type);
3099 }
3100 if (elem->minOccurs == 0) {
3101 /* basically an elem? */
3102 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3103 }
3104 }
3105 break;
3106 }
3107 case XML_SCHEMA_TYPE_SEQUENCE: {
3108 xmlSchemaTypePtr subtypes;
3109
3110 /*
3111 * Simply iterate over the subtypes
3112 */
3113 subtypes = type->subtypes;
3114 while (subtypes != NULL) {
3115 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3116 subtypes = subtypes->next;
3117 }
3118 break;
3119 }
3120 case XML_SCHEMA_TYPE_CHOICE: {
3121 xmlSchemaTypePtr subtypes;
3122 xmlAutomataStatePtr start, end;
3123
3124 start = ctxt->state;
3125 end = xmlAutomataNewState(ctxt->am);
3126
3127 /*
3128 * iterate over the subtypes and remerge the end with an
3129 * epsilon transition
3130 */
Daniel Veillardb509f152002-04-17 16:28:10 +00003131 if (type->maxOccurs == 1) {
3132 subtypes = type->subtypes;
3133 while (subtypes != NULL) {
3134 ctxt->state = start;
3135 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3136 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
3137 subtypes = subtypes->next;
3138 }
3139 } else {
3140 int counter;
3141 xmlAutomataStatePtr hop;
3142
3143 /*
3144 * use a counter to keep track of the number of transtions
3145 * which went through the choice.
3146 */
3147 if (type->minOccurs < 1) {
3148 counter = xmlAutomataNewCounter(ctxt->am, 0,
3149 type->maxOccurs - 1);
3150 } else {
3151 counter = xmlAutomataNewCounter(ctxt->am,
3152 type->minOccurs - 1, type->maxOccurs - 1);
3153 }
3154 hop = xmlAutomataNewState(ctxt->am);
3155
3156 subtypes = type->subtypes;
3157 while (subtypes != NULL) {
3158 ctxt->state = start;
3159 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3160 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
3161 subtypes = subtypes->next;
3162 }
3163 xmlAutomataNewCountedTrans(ctxt->am, hop, start, counter);
3164 xmlAutomataNewCounterTrans(ctxt->am, hop, end, counter);
3165 }
3166 if (type->minOccurs == 0) {
3167 xmlAutomataNewEpsilon(ctxt->am, start, end);
Daniel Veillard4255d502002-04-16 15:50:10 +00003168 }
3169 ctxt->state = end;
3170 break;
3171 }
3172 case XML_SCHEMA_TYPE_ALL: {
Daniel Veillard7646b182002-04-20 06:41:40 +00003173 xmlAutomataStatePtr start;
3174 xmlSchemaTypePtr subtypes;
3175 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard441bc322002-04-20 17:38:48 +00003176 int lax;
Daniel Veillard7646b182002-04-20 06:41:40 +00003177
3178 subtypes = type->subtypes;
3179 if (subtypes == NULL)
3180 break;
3181 start = ctxt->state;
3182 while (subtypes != NULL) {
3183 ctxt->state = start;
3184 elem = (xmlSchemaElementPtr) subtypes;
3185
3186 /* TODO : handle the namespace too */
3187 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, ctxt->state,
3188 elem->name, elem->minOccurs, elem->maxOccurs,
3189 subtypes);
3190 subtypes = subtypes->next;
3191 }
Daniel Veillard441bc322002-04-20 17:38:48 +00003192 lax = type->minOccurs == 0;
3193 ctxt->state = xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
3194 lax);
Daniel Veillard4255d502002-04-16 15:50:10 +00003195 break;
3196 }
3197 case XML_SCHEMA_TYPE_RESTRICTION:
Daniel Veillardb4398962002-04-19 07:01:55 +00003198 if (type->subtypes != NULL)
Daniel Veillard6231e842002-04-18 11:54:04 +00003199 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3200 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003201 case XML_SCHEMA_TYPE_EXTENSION:
Daniel Veillard6231e842002-04-18 11:54:04 +00003202 if (type->baseType != NULL) {
3203 xmlSchemaTypePtr subtypes;
3204
3205 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
3206 subtypes = type->subtypes;
3207 while (subtypes != NULL) {
3208 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3209 subtypes = subtypes->next;
3210 }
3211 } else if (type->subtypes != NULL)
3212 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3213 break;
Daniel Veillard4255d502002-04-16 15:50:10 +00003214 case XML_SCHEMA_TYPE_GROUP:
3215 case XML_SCHEMA_TYPE_COMPLEX:
3216 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
3217 if (type->subtypes != NULL)
3218 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
3219 break;
3220 default:
3221 xmlGenericError(xmlGenericErrorContext,
3222 "Found unexpected type %d in %s content model\n",
3223 type->type, name);
3224 return;
3225 }
3226}
3227/**
3228 * xmlSchemaBuildContentModel:
3229 * @typeDecl: the schema type definition
3230 * @ctxt: the schema parser context
3231 *
3232 * Fixes the content model of the element.
3233 */
3234static void
3235xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
3236 xmlSchemaParserCtxtPtr ctxt,
3237 const xmlChar *name) {
3238 xmlAutomataStatePtr start;
3239
Daniel Veillard4255d502002-04-16 15:50:10 +00003240 if (elem->contModel != NULL)
3241 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003242 if (elem->subtypes == NULL) {
3243 elem->contentType = XML_SCHEMA_CONTENT_ANY;
Daniel Veillard4255d502002-04-16 15:50:10 +00003244 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00003245 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003246 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
3247 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003248 if (elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC)
3249 return;
3250
3251#ifdef DEBUG_CONTENT
3252 xmlGenericError(xmlGenericErrorContext,
3253 "Building content model for %s\n", name);
3254#endif
3255
Daniel Veillard4255d502002-04-16 15:50:10 +00003256 ctxt->am = xmlNewAutomata();
3257 if (ctxt->am == NULL) {
3258 xmlGenericError(xmlGenericErrorContext,
3259 "Cannot create automata for elem %s\n", name);
3260 return;
3261 }
3262 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
3263 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
3264 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00003265 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003266 if (!xmlAutomataIsDeterminist(ctxt->am)) {
3267 xmlGenericError(xmlGenericErrorContext,
3268 "Content model of %s is not determinist:\n", name);
Daniel Veillarde19fc232002-04-22 16:01:24 +00003269 ctxt->err = XML_SCHEMAS_ERR_NOTDETERMINIST;
Daniel Veillard4402ab42002-09-12 16:02:56 +00003270 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003271 } else {
Daniel Veillard4255d502002-04-16 15:50:10 +00003272#ifdef DEBUG_CONTENT
Daniel Veillarde19fc232002-04-22 16:01:24 +00003273 xmlGenericError(xmlGenericErrorContext,
3274 "Content model of %s:\n", name);
3275 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00003276#endif
Daniel Veillard4402ab42002-09-12 16:02:56 +00003277 ctxt->state = NULL;
Daniel Veillarde19fc232002-04-22 16:01:24 +00003278 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003279 xmlFreeAutomata(ctxt->am);
3280 ctxt->am = NULL;
3281}
3282
3283/**
3284 * xmlSchemaRefFixupCallback:
3285 * @elem: the schema element context
3286 * @ctxt: the schema parser context
3287 *
3288 * Free the resources associated to the schema parser context
3289 */
3290static void
3291xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
3292 xmlSchemaParserCtxtPtr ctxt,
3293 const xmlChar *name,
3294 ATTRIBUTE_UNUSED const xmlChar *context,
3295 ATTRIBUTE_UNUSED const xmlChar *namespace)
3296{
3297 if ((ctxt == NULL) || (elem == NULL))
3298 return;
3299 if (elem->ref != NULL) {
3300 xmlSchemaElementPtr elemDecl;
3301
3302 if (elem->subtypes != NULL) {
3303 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3304 if ((ctxt != NULL) && (ctxt->error != NULL))
3305 ctxt->error(ctxt->userData,
3306 "Schemas: element %s have both ref and subtype\n",
3307 name);
3308 return;
3309 }
3310 elemDecl = xmlHashLookup2(ctxt->schema->elemDecl,
3311 elem->ref, elem->refNs);
3312
3313 if (elemDecl == NULL) {
3314 if ((ctxt != NULL) && (ctxt->error != NULL))
3315 ctxt->error(ctxt->userData,
3316 "Schemas: element %s ref to %s not found\n",
3317 name, elem->ref);
3318 return;
3319 }
3320 elem->refDecl = elemDecl;
3321 } else if (elem->namedType != NULL) {
3322 xmlSchemaTypePtr typeDecl;
3323
3324 if (elem->subtypes != NULL) {
3325 xmlSchemaErrorContext(ctxt, NULL, elem->node, NULL);
3326 if ((ctxt != NULL) && (ctxt->error != NULL))
3327 ctxt->error(ctxt->userData,
3328 "Schemas: element %s have both type and subtype\n",
3329 name);
3330 return;
3331 }
3332 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
3333 elem->namedTypeNs);
3334
3335 if (typeDecl == NULL) {
3336 if ((ctxt != NULL) && (ctxt->error != NULL))
3337 ctxt->error(ctxt->userData,
3338 "Schemas: element %s type %s not found\n",
3339 name, elem->namedType);
3340 return;
3341 }
3342 elem->subtypes = typeDecl;
3343 }
3344}
3345
3346/**
3347 * xmlSchemaTypeFixup:
3348 * @typeDecl: the schema type definition
3349 * @ctxt: the schema parser context
3350 *
3351 * Fixes the content model of the type.
3352 */
3353static void
3354xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
3355 xmlSchemaParserCtxtPtr ctxt,
3356 const xmlChar *name)
3357{
3358 if (name == NULL)
3359 name = typeDecl->name;
3360 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
3361 switch (typeDecl->type) {
3362 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: {
3363 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3364 typeDecl->contentType = typeDecl->subtypes->contentType;
3365 break;
3366 }
3367 case XML_SCHEMA_TYPE_RESTRICTION: {
3368 if (typeDecl->subtypes != NULL)
3369 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3370
3371 if (typeDecl->base != NULL) {
3372 xmlSchemaTypePtr baseType;
3373
3374 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3375 typeDecl->baseNs);
3376 if (baseType == NULL) {
3377 if ((ctxt != NULL) && (ctxt->error != NULL))
3378 ctxt->error(ctxt->userData,
3379 "Schemas: type %s base type %s not found\n",
3380 name, typeDecl->base);
3381 }
3382 typeDecl->baseType = baseType;
3383 }
3384 if (typeDecl->subtypes == NULL)
3385 /* 1.1.1 */
3386 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3387 else if ((typeDecl->subtypes->subtypes == NULL) &&
3388 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3389 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3390 /* 1.1.2 */
3391 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3392 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3393 (typeDecl->subtypes->subtypes == NULL))
3394 /* 1.1.3 */
3395 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3396 else {
3397 /* 1.2 and 2.X are applied at the other layer */
3398 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3399 }
3400 break;
3401 }
3402 case XML_SCHEMA_TYPE_EXTENSION: {
3403 xmlSchemaContentType explicitContentType;
3404 xmlSchemaTypePtr base;
3405
3406 if (typeDecl->base != NULL) {
3407 xmlSchemaTypePtr baseType;
3408
3409 baseType = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3410 typeDecl->baseNs);
3411 if (baseType == NULL) {
3412 if ((ctxt != NULL) && (ctxt->error != NULL))
3413 ctxt->error(ctxt->userData,
3414 "Schemas: type %s base type %s not found\n",
3415 name, typeDecl->base);
3416 }
3417 typeDecl->baseType = baseType;
3418 }
3419 if (typeDecl->subtypes != NULL)
3420 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3421
Daniel Veillard8651f532002-04-17 09:06:27 +00003422 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
Daniel Veillard4255d502002-04-16 15:50:10 +00003423 if (typeDecl->subtypes == NULL)
3424 /* 1.1.1 */
3425 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3426 else if ((typeDecl->subtypes->subtypes == NULL) &&
3427 ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_ALL) ||
3428 (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SEQUENCE)))
3429 /* 1.1.2 */
3430 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3431 else if ((typeDecl->subtypes->type == XML_SCHEMA_TYPE_CHOICE) &&
3432 (typeDecl->subtypes->subtypes == NULL))
3433 /* 1.1.3 */
3434 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
3435
3436 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
3437 typeDecl->baseNs);
3438 if (base == NULL) {
3439 xmlSchemaErrorContext(ctxt, NULL, typeDecl->node, NULL);
3440 if ((ctxt != NULL) && (ctxt->error != NULL))
3441 ctxt->error(ctxt->userData,
3442 "Schemas: base type %s of type %s not found\n",
3443 typeDecl->base, name);
3444 return;
3445 }
3446 xmlSchemaTypeFixup(base, ctxt, NULL);
3447 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
3448 /* 2.1 */
3449 typeDecl->contentType = base->contentType;
3450 } else if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
3451 /* 2.2 imbitable ! */
3452 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3453 } else {
3454 /* 2.3 imbitable pareil ! */
3455 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3456 }
3457 break;
3458 }
3459 case XML_SCHEMA_TYPE_COMPLEX: {
3460 if (typeDecl->subtypes == NULL) {
3461 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3462 } else {
3463 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3464 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3465 else {
3466 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3467 typeDecl->contentType = typeDecl->subtypes->contentType;
3468 }
3469 }
3470 break;
3471 }
3472 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: {
3473 if (typeDecl->subtypes == NULL) {
3474 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
3475 } else {
3476 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
3477 typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED;
3478 else {
3479 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
3480 typeDecl->contentType = typeDecl->subtypes->contentType;
3481 }
3482 }
3483 break;
3484 }
3485 case XML_SCHEMA_TYPE_SEQUENCE:
3486 case XML_SCHEMA_TYPE_GROUP:
3487 case XML_SCHEMA_TYPE_ALL:
3488 case XML_SCHEMA_TYPE_CHOICE:
3489 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
3490 break;
3491 case XML_SCHEMA_TYPE_BASIC:
3492 case XML_SCHEMA_TYPE_ANY:
3493 case XML_SCHEMA_TYPE_FACET:
3494 case XML_SCHEMA_TYPE_SIMPLE:
3495 case XML_SCHEMA_TYPE_UR:
3496 case XML_SCHEMA_TYPE_ELEMENT:
3497 case XML_SCHEMA_TYPE_ATTRIBUTE:
3498 case XML_SCHEMA_TYPE_NOTATION:
3499 case XML_SCHEMA_TYPE_LIST:
3500 case XML_SCHEMA_TYPE_UNION:
3501 case XML_SCHEMA_FACET_MININCLUSIVE:
3502 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3503 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3504 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
3505 case XML_SCHEMA_FACET_TOTALDIGITS:
3506 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3507 case XML_SCHEMA_FACET_PATTERN:
3508 case XML_SCHEMA_FACET_ENUMERATION:
3509 case XML_SCHEMA_FACET_WHITESPACE:
3510 case XML_SCHEMA_FACET_LENGTH:
3511 case XML_SCHEMA_FACET_MAXLENGTH:
3512 case XML_SCHEMA_FACET_MINLENGTH:
3513 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
3514 break;
3515 }
3516 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003517#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00003518 if (typeDecl->node != NULL) {
3519 xmlGenericError(xmlGenericErrorContext,
3520 "Type of %s : %s:%d :", name, typeDecl->node->doc->URL,
3521 xmlGetLineNo(typeDecl->node));
3522 } else {
3523 xmlGenericError(xmlGenericErrorContext,
3524 "Type of %s :", name);
3525 }
Daniel Veillard8651f532002-04-17 09:06:27 +00003526 switch (typeDecl->contentType) {
3527 case XML_SCHEMA_CONTENT_SIMPLE:
3528 xmlGenericError(xmlGenericErrorContext,
3529 "simple\n"); break;
3530 case XML_SCHEMA_CONTENT_ELEMENTS:
3531 xmlGenericError(xmlGenericErrorContext,
3532 "elements\n"); break;
3533 case XML_SCHEMA_CONTENT_UNKNOWN:
3534 xmlGenericError(xmlGenericErrorContext,
3535 "unknown !!!\n"); break;
3536 case XML_SCHEMA_CONTENT_EMPTY:
3537 xmlGenericError(xmlGenericErrorContext,
3538 "empty\n"); break;
3539 case XML_SCHEMA_CONTENT_MIXED:
3540 xmlGenericError(xmlGenericErrorContext,
3541 "mixed\n"); break;
3542 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
3543 xmlGenericError(xmlGenericErrorContext,
3544 "mixed or elems\n"); break;
3545 case XML_SCHEMA_CONTENT_BASIC:
3546 xmlGenericError(xmlGenericErrorContext,
3547 "basic\n"); break;
3548 default:
3549 xmlGenericError(xmlGenericErrorContext,
3550 "not registered !!!\n"); break;
3551 }
3552#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00003553}
3554
3555/**
3556 * xmlSchemaCheckDefaults:
3557 * @typeDecl: the schema type definition
3558 * @ctxt: the schema parser context
3559 *
3560 * Checks the default values types, especially for facets
3561 */
3562static void
3563xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
3564 xmlSchemaParserCtxtPtr ctxt,
3565 const xmlChar *name)
3566{
3567 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
3568 if (name == NULL)
3569 name = typeDecl->name;
3570 if (nonNegativeIntegerType == NULL) {
3571 nonNegativeIntegerType = xmlSchemaGetPredefinedType(
3572 BAD_CAST "nonNegativeInteger", xmlSchemaNs);
3573 }
3574 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
3575 if (typeDecl->facets != NULL) {
3576 xmlSchemaFacetPtr facet = typeDecl->facets;
3577 while (facet != NULL) {
3578 switch (facet->type) {
3579 case XML_SCHEMA_FACET_MININCLUSIVE:
3580 case XML_SCHEMA_FACET_MINEXCLUSIVE:
3581 case XML_SCHEMA_FACET_MAXINCLUSIVE:
3582 case XML_SCHEMA_FACET_MAXEXCLUSIVE: {
3583 /*
3584 * Okay we need to validate the value
3585 * at that point.
3586 */
3587 xmlSchemaValidCtxtPtr vctxt;
3588
3589 vctxt = xmlSchemaNewValidCtxt(NULL);
3590 if (vctxt == NULL)
3591 break;
3592 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3593 facet->value);
3594 facet->val = vctxt->value;
3595 vctxt->value = NULL;
3596 if (facet->val == NULL) {
3597 /* error code */
3598 xmlSchemaErrorContext(ctxt, NULL,
3599 facet->node, NULL);
3600 ctxt->error(ctxt->userData,
3601 "Schemas: type %s facet value %s invalid\n",
3602 name, facet->value);
3603 }
3604 xmlSchemaFreeValidCtxt(vctxt);
3605 break;
3606 }
3607 case XML_SCHEMA_FACET_ENUMERATION: {
3608 /*
3609 * Okay we need to validate the value
3610 * at that point.
3611 */
3612 xmlSchemaValidCtxtPtr vctxt;
3613 int ret;
3614
3615 vctxt = xmlSchemaNewValidCtxt(NULL);
3616 if (vctxt == NULL)
3617 break;
3618 ret = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
3619 facet->value);
3620 if (ret != 0) {
3621 xmlSchemaErrorContext(ctxt, NULL,
3622 facet->node, NULL);
3623 ctxt->error(ctxt->userData,
3624 "Schemas: type %s enumeration value %s invalid\n",
3625 name, facet->value);
3626 }
3627 xmlSchemaFreeValidCtxt(vctxt);
3628 break;
3629 }
3630 case XML_SCHEMA_FACET_PATTERN:
3631 facet->regexp = xmlRegexpCompile(facet->value);
3632 if (facet->regexp == NULL) {
3633 /* error code */
3634 ctxt->error(ctxt->userData,
3635 "Schemas: type %s facet regexp %s invalid\n",
3636 name, facet->value);
3637 }
3638 break;
3639 case XML_SCHEMA_FACET_TOTALDIGITS:
3640 case XML_SCHEMA_FACET_FRACTIONDIGITS:
3641 case XML_SCHEMA_FACET_LENGTH:
3642 case XML_SCHEMA_FACET_MAXLENGTH:
3643 case XML_SCHEMA_FACET_MINLENGTH: {
3644 int ret;
3645
3646 ret = xmlSchemaValidatePredefinedType(
3647 nonNegativeIntegerType, facet->value,
3648 &facet->val);
3649 if (ret != 0) {
3650 /* error code */
3651 xmlSchemaErrorContext(ctxt, NULL,
3652 facet->node, NULL);
3653 ctxt->error(ctxt->userData,
3654 "Schemas: type %s facet value %s invalid\n",
3655 name, facet->value);
3656 }
3657 break;
3658 }
3659 case XML_SCHEMA_FACET_WHITESPACE: {
3660 if (xmlStrEqual(facet->value, BAD_CAST"preserve")) {
3661 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
3662 } else if (xmlStrEqual(facet->value,
3663 BAD_CAST"replace")) {
3664 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
3665 } else if (xmlStrEqual(facet->value,
3666 BAD_CAST"collapse")) {
3667 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
3668 } else {
3669 xmlSchemaErrorContext(ctxt, NULL,
3670 facet->node, NULL);
3671 ctxt->error(ctxt->userData,
3672 "Schemas: type %s whiteSpace value %s invalid\n",
3673 name, facet->value);
3674 }
3675 }
3676 default:
3677 break;
3678 }
3679 facet = facet->next;
3680 }
3681 }
3682 }
3683}
3684
3685/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00003686 * xmlSchemaAttrGrpFixup:
3687 * @attrgrpDecl: the schema attribute definition
3688 * @ctxt: the schema parser context
3689 * @name: the attribute name
3690 *
3691 * Fixes finish doing the computations on the attributes definitions
3692 */
3693static void
3694xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
3695 xmlSchemaParserCtxtPtr ctxt,
3696 const xmlChar *name)
3697{
3698 if (name == NULL)
3699 name = attrgrpDecl->name;
3700 if (attrgrpDecl->attributes != NULL)
3701 return;
3702 if (attrgrpDecl->ref != NULL) {
3703 xmlSchemaAttributeGroupPtr ref;
3704
3705 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
3706 attrgrpDecl->refNs);
3707 if (ref == NULL) {
3708 if ((ctxt != NULL) && (ctxt->error != NULL))
3709 ctxt->error(ctxt->userData,
3710 "Schemas: attribute group %s reference %s not found\n",
3711 name, attrgrpDecl->ref);
3712 return;
3713 }
3714 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
3715 attrgrpDecl->attributes = ref->attributes;
3716 } else {
3717 if ((ctxt != NULL) && (ctxt->error != NULL))
3718 ctxt->error(ctxt->userData,
3719 "Schemas: attribute %s has no attributes nor reference\n",
3720 name);
3721 }
3722}
3723
3724/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003725 * xmlSchemaAttrFixup:
3726 * @attrDecl: the schema attribute definition
3727 * @ctxt: the schema parser context
3728 * @name: the attribute name
3729 *
3730 * Fixes finish doing the computations on the attributes definitions
3731 */
3732static void
3733xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
3734 xmlSchemaParserCtxtPtr ctxt,
3735 const xmlChar *name)
3736{
3737 if (name == NULL)
3738 name = attrDecl->name;
3739 if (attrDecl->subtypes != NULL)
3740 return;
3741 if (attrDecl->typeName != NULL) {
3742 xmlSchemaTypePtr type;
3743
3744 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
3745 attrDecl->typeNs);
3746 if (type == NULL) {
3747 if ((ctxt != NULL) && (ctxt->error != NULL))
3748 ctxt->error(ctxt->userData,
3749 "Schemas: attribute %s type %s not found\n",
3750 name, attrDecl->typeName);
3751 }
3752 attrDecl->subtypes = type;
3753 } else if (attrDecl->ref != NULL) {
3754 xmlSchemaAttributePtr ref;
3755
3756 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
3757 attrDecl->refNs);
3758 if (ref == NULL) {
3759 if ((ctxt != NULL) && (ctxt->error != NULL))
3760 ctxt->error(ctxt->userData,
3761 "Schemas: attribute %s reference %s not found\n",
3762 name, attrDecl->ref);
3763 return;
3764 }
3765 xmlSchemaAttrFixup(ref, ctxt, NULL);
3766 attrDecl->subtypes = ref->subtypes;
3767 } else {
3768 if ((ctxt != NULL) && (ctxt->error != NULL))
3769 ctxt->error(ctxt->userData,
3770 "Schemas: attribute %s has no type nor reference\n",
3771 name);
3772 }
3773}
3774
3775/**
3776 * xmlSchemaParse:
3777 * @ctxt: a schema validation context
3778 * @URL: the location of the schema
3779 *
3780 * Load, XML parse a schema definition resource and build an internal
3781 * XML Shema struture which can be used to validate instances.
3782 * *WARNING* this interface is highly subject to change
3783 *
3784 * Returns the internal XML Schema structure built from the resource or
3785 * NULL in case of error
3786 */
3787xmlSchemaPtr
3788xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
3789{
3790 xmlSchemaPtr ret = NULL;
3791 xmlDocPtr doc;
3792 xmlNodePtr root, cur, delete;
3793
3794 xmlSchemaInitTypes();
3795
3796 if ((ctxt == NULL) || (ctxt->URL == NULL))
3797 return (NULL);
3798
3799 ctxt->counter = 0;
3800 ctxt->container = NULL;
3801
3802 /*
3803 * First step is to parse the input document into an DOM/Infoset
3804 */
3805 doc = xmlParseFile((const char *) ctxt->URL);
3806 if (doc == NULL) {
3807 if (ctxt->error != NULL)
3808 ctxt->error(ctxt->userData,
3809 "xmlSchemaParse: could not load %s\n", ctxt->URL);
3810 return (NULL);
3811 }
3812
3813 /*
3814 * Then extract the root and Schema parse it
3815 */
3816 root = xmlDocGetRootElement(doc);
3817 if (root == NULL) {
3818 if (ctxt->error != NULL)
3819 ctxt->error(ctxt->userData, "xmlSchemaParse: %s is empty\n",
3820 ctxt->URL);
3821 return (NULL);
3822 }
3823
3824 /*
3825 * Remove all the blank text nodes
3826 */
3827 delete = NULL;
3828 cur = root;
3829 while (cur != NULL) {
3830 if (delete != NULL) {
3831 xmlUnlinkNode(delete);
3832 xmlFreeNode(delete);
3833 delete = NULL;
3834 }
3835 if (cur->type == XML_TEXT_NODE) {
3836 if (IS_BLANK_NODE(cur)) {
3837 if (xmlNodeGetSpacePreserve(cur) != 1) {
3838 delete = cur;
3839 }
3840 }
3841 } else if ((cur->type != XML_ELEMENT_NODE) &&
3842 (cur->type != XML_CDATA_SECTION_NODE)) {
3843 delete = cur;
3844 goto skip_children;
3845 }
3846
3847 /*
3848 * Skip to next node
3849 */
3850 if (cur->children != NULL) {
3851 if ((cur->children->type != XML_ENTITY_DECL) &&
3852 (cur->children->type != XML_ENTITY_REF_NODE) &&
3853 (cur->children->type != XML_ENTITY_NODE)) {
3854 cur = cur->children;
3855 continue;
3856 }
3857 }
3858skip_children:
3859 if (cur->next != NULL) {
3860 cur = cur->next;
3861 continue;
3862 }
3863
3864 do {
3865 cur = cur->parent;
3866 if (cur == NULL)
3867 break;
3868 if (cur == root) {
3869 cur = NULL;
3870 break;
3871 }
3872 if (cur->next != NULL) {
3873 cur = cur->next;
3874 break;
3875 }
3876 } while (cur != NULL);
3877 }
3878 if (delete != NULL) {
3879 xmlUnlinkNode(delete);
3880 xmlFreeNode(delete);
3881 delete = NULL;
3882 }
3883
3884 /*
3885 * Then do the parsing for good
3886 */
3887 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillardb4398962002-04-19 07:01:55 +00003888 if (ret == NULL)
3889 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003890 ret->doc = doc;
3891
3892 /*
3893 * Then fix all the references.
3894 */
3895 ctxt->schema = ret;
3896 xmlHashScanFull(ret->elemDecl,
3897 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
3898
3899 /*
3900 * Then fixup all types properties
3901 */
3902 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
3903
3904 /*
3905 * Then build the content model for all elements
3906 */
3907 xmlHashScan(ret->elemDecl,
3908 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
3909
3910 /*
3911 * Then check the defaults part of the type like facets values
3912 */
3913 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, ctxt);
3914
3915 /*
3916 * Then fixup all attributes declarations
3917 */
3918 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
3919
Daniel Veillard13e04c62002-04-23 17:51:29 +00003920 /*
3921 * Then fixup all attributes group declarations
3922 */
3923 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, ctxt);
3924
Daniel Veillard4255d502002-04-16 15:50:10 +00003925 return (ret);
3926}
3927
3928/**
3929 * xmlSchemaParse:
3930 * @ctxt: a schema validation context
3931 * @URL: the location of the schema
3932 *
3933 * Load, XML parse a schema definition resource and build an internal
3934 * XML Shema struture which can be used to validate instances.
3935 * *WARNING* this interface is highly subject to change
3936 *
3937 * Returns the internal XML Schema structure built from the resource or
3938 * NULL in case of error
3939 */
3940void
3941xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
3942 xmlSchemaValidityErrorFunc err,
3943 xmlSchemaValidityWarningFunc warn, void *ctx) {
3944 if (ctxt == NULL)
3945 return;
3946 ctxt->error = err;
3947 ctxt->warning = warn;
3948 ctxt->userData = ctx;
3949}
3950
3951/************************************************************************
3952 * *
3953 * Simple type validation *
3954 * *
3955 ************************************************************************/
3956
3957/**
3958 * xmlSchemaValidateSimpleValue:
3959 * @ctxt: a schema validation context
3960 * @type: the type declaration
3961 * @value: the value to validate
3962 *
3963 * Validate a value against a simple type
3964 *
3965 * Returns 0 if the value is valid, a positive error code
3966 * number otherwise and -1 in case of internal or API error.
3967 */
3968static int
3969xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
3970 xmlSchemaTypePtr type,
3971 xmlChar *value) {
3972 int ret = 0;
3973 /*
3974 * First normalize the value accordingly to Schema Datatype
3975 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
3976 */
3977 /*
3978 * Then check the normalized value against the lexical space of the
3979 * type.
3980 */
3981 if (type->type == XML_SCHEMA_TYPE_BASIC) {
3982 if (ctxt->value != NULL) {
3983 xmlSchemaFreeValue(ctxt->value);
3984 ctxt->value = NULL;
3985 }
3986 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
3987 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
3988 xmlSchemaTypePtr base;
3989 xmlSchemaFacetPtr facet;
3990 int tmp;
3991
3992 base = type->baseType;
3993 if (base != NULL) {
3994 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
3995 } else if (type->subtypes != NULL) {
3996
3997 }
3998 /*
3999 * Do not validate facets when working on building the Schemas
4000 */
4001 if (ctxt->schema != NULL) {
4002 if (ret == 0) {
4003 facet = type->facets;
Daniel Veillard88c58912002-04-23 07:12:20 +00004004 if ((type->type == XML_SCHEMA_TYPE_RESTRICTION) &&
4005 (facet != NULL) &&
4006 (facet->type == XML_SCHEMA_FACET_ENUMERATION)) {
4007 while (facet != NULL) {
4008 ret = 1;
4009
4010 tmp = xmlSchemaValidateFacet(base, facet, value,
4011 ctxt->value);
4012 if (tmp == 0) {
4013 ret = 0;
4014 break;
4015 }
4016 facet = facet->next;
4017 }
4018 } else {
4019 while (facet != NULL) {
4020 tmp = xmlSchemaValidateFacet(base, facet, value,
4021 ctxt->value);
4022 if (tmp != 0)
4023 ret = tmp;
4024 facet = facet->next;
4025 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004026 }
4027 }
4028 }
4029 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
4030 xmlSchemaTypePtr base;
4031
4032 base = type->subtypes;
4033 if (base != NULL) {
4034 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4035 } else {
4036 TODO
4037 }
4038 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
4039 xmlSchemaTypePtr base;
4040 xmlChar *cur, *end, tmp;
4041 int ret2;
4042
4043 base = type->subtypes;
4044 if (base == NULL) {
4045 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4046 if (ctxt->error != NULL) {
4047 xmlSchemaErrorContext(NULL, ctxt->schema, type->node, NULL);
4048 ctxt->error(ctxt->userData,
4049 "Internal: List type %s has no base type\n",
4050 type->name);
4051 }
4052 return(-1);
4053 }
4054 cur = value;
4055 do {
4056 while (IS_BLANK(*cur)) cur++;
4057 end = cur;
4058 while ((*end != 0) && (!(IS_BLANK(*end)))) end++;
4059 if (end == cur)
4060 break;
4061 tmp = *end;
4062 *end = 0;
4063 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, cur);
4064 if (ret2 != 0)
4065 ret = 1;
4066 *end = tmp;
4067 cur = end;
4068 } while (*cur != 0);
4069 } else {
4070 TODO
4071 }
4072 return(ret);
4073}
4074
4075/************************************************************************
4076 * *
4077 * DOM Validation code *
4078 * *
4079 ************************************************************************/
4080
4081static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
4082 xmlNodePtr node);
4083static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
4084 xmlNodePtr elem, xmlSchemaAttributePtr attributes);
4085static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
4086 xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type);
4087
4088/**
4089 * xmlSchemaRegisterAttributes:
4090 * @ctxt: a schema validation context
4091 * @attrs: a list of attributes
4092 *
4093 * Register the list of attributes as the set to be validated on that element
4094 *
4095 * Returns -1 in case of error, 0 otherwise
4096 */
4097static int
4098xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt,
4099 xmlAttrPtr attrs) {
4100 while (attrs != NULL) {
Daniel Veillard441bc322002-04-20 17:38:48 +00004101 if ((attrs->ns != NULL) &&
4102 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
4103 attrs = attrs->next;
4104 continue;
4105 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004106 if (ctxt->attrNr >= ctxt->attrMax) {
4107 xmlSchemaAttrStatePtr tmp;
4108
4109 ctxt->attrMax *= 2;
4110 tmp = (xmlSchemaAttrStatePtr)
4111 xmlRealloc(ctxt->attr, ctxt->attrMax *
4112 sizeof(xmlSchemaAttrState));
4113 if (tmp == NULL) {
4114 ctxt->attrMax /= 2;
4115 return(-1);
4116 }
4117 ctxt->attr = tmp;
4118 }
4119 ctxt->attr[ctxt->attrNr].attr = attrs;
4120 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
4121 ctxt->attrNr++;
4122 attrs = attrs->next;
4123 }
4124 return(0);
4125}
4126
4127/**
4128 * xmlSchemaCheckAttributes:
4129 * @ctxt: a schema validation context
4130 * @node: the node carrying it.
4131 *
4132 * Check that the registered set of attributes on the current node
4133 * has been properly validated.
4134 *
4135 * Returns 0 if validity constraints are met, 1 otherwise.
4136 */
4137static int
4138xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4139 int ret = 0;
4140 int i;
4141
4142 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4143 if (ctxt->attr[i].attr == NULL)
4144 break;
4145 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
4146 ret = 1;
4147 ctxt->err = XML_SCHEMAS_ERR_ATTRUNKNOWN;
4148 if (ctxt->error != NULL)
4149 ctxt->error(ctxt->userData,
4150 "Attribute %s on %s is unknown\n",
4151 ctxt->attr[i].attr->name,
4152 node->name);
4153 }
4154 }
4155 return(ret);
4156}
4157
4158/**
4159 * xmlSchemaValidateSimpleContent:
4160 * @ctxt: a schema validation context
4161 * @elem: an element
4162 * @type: the type declaration
4163 *
4164 * Validate the content of an element expected to be a simple type
4165 *
4166 * Returns 0 if the element is schemas valid, a positive error code
4167 * number otherwise and -1 in case of internal or API error.
4168 */
4169static int
4170xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
4171 ATTRIBUTE_UNUSED xmlNodePtr node) {
4172 xmlNodePtr child;
4173 xmlSchemaTypePtr type, base;
4174 xmlChar *value;
4175 int ret = 0, tmp;
4176
4177 child = ctxt->node;
4178 type = ctxt->type;
4179
4180 /*
4181 * Validation Rule: Element Locally Valid (Type): 3.1.3
4182 */
4183 value = xmlNodeGetContent(child);
4184 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
4185 switch (type->type) {
4186 case XML_SCHEMA_TYPE_RESTRICTION: {
4187 xmlSchemaFacetPtr facet;
4188
4189 base = type->baseType;
4190 if (base != NULL) {
4191 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
4192 } else {
4193 TODO
4194 }
4195 if (ret == 0) {
4196 facet = type->facets;
4197 while (facet != NULL) {
4198 tmp = xmlSchemaValidateFacet(base, facet, value,
4199 ctxt->value);
4200 if (tmp != 0)
4201 ret = tmp;
4202 facet = facet->next;
4203 }
4204 }
4205 break;
4206 }
4207 default:
4208 TODO
4209 }
4210 if (value != NULL)
4211 xmlFree(value);
4212
4213 return(ret);
4214}
4215
4216/**
4217 * xmlSchemaValidateCheckNodeList
4218 * @nodelist: the list of nodes
4219 *
4220 * Check the node list is only made of text nodes and entities pointing
4221 * to text nodes
4222 *
4223 * Returns 1 if true, 0 if false and -1 in case of error
4224 */
4225static int
4226xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) {
4227 while (nodelist != NULL) {
4228 if (nodelist->type == XML_ENTITY_REF_NODE) {
4229 TODO /* implement recursion in the entity content */
4230 }
4231 if ((nodelist->type != XML_TEXT_NODE) &&
4232 (nodelist->type != XML_COMMENT_NODE) &&
4233 (nodelist->type != XML_PI_NODE) &&
4234 (nodelist->type != XML_PI_NODE)) {
4235 return(0);
4236 }
4237 nodelist = nodelist->next;
4238 }
4239 return(1);
4240}
4241
4242/**
4243 * xmlSchemaSkipIgnored:
4244 * @ctxt: a schema validation context
4245 * @type: the current type context
4246 * @node: the top node.
4247 *
4248 * Skip ignorable nodes in that context
4249 *
4250 * Returns the new sibling
4251 * number otherwise and -1 in case of internal or API error.
4252 */
4253static xmlNodePtr
4254xmlSchemaSkipIgnored(ATTRIBUTE_UNUSED xmlSchemaValidCtxtPtr ctxt,
4255 xmlSchemaTypePtr type,
4256 xmlNodePtr node) {
4257 int mixed = 0;
4258 /*
4259 * TODO complete and handle entities
4260 */
4261 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
4262 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
4263 while ((node != NULL) &&
4264 ((node->type == XML_COMMENT_NODE) ||
4265 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
4266 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
4267 (node->type == XML_TEXT_NODE) &&
4268 (IS_BLANK_NODE(node)))))) {
4269 node = node->next;
4270 }
4271 return(node);
4272}
4273
4274/**
4275 * xmlSchemaValidateCallback:
4276 * @ctxt: a schema validation context
4277 * @name: the name of the element detected (might be NULL)
4278 * @type: the type
4279 *
4280 * A transition has been made in the automata associated to an element
4281 * content model
4282 */
4283static void
4284xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
4285 ATTRIBUTE_UNUSED const xmlChar *name,
4286 xmlSchemaTypePtr type,
4287 xmlNodePtr node) {
4288 xmlSchemaTypePtr oldtype = ctxt->type;
4289 xmlNodePtr oldnode = ctxt->node;
4290#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00004291 xmlGenericError(xmlGenericErrorContext,
4292 "xmlSchemaValidateCallback: %s, %s, %s\n",
4293 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00004294#endif
4295 ctxt->type = type;
4296 ctxt->node = node;
4297 xmlSchemaValidateContent(ctxt, node);
4298 ctxt->type = oldtype;
4299 ctxt->node = oldnode;
4300}
4301
4302
4303#if 0
4304/**
4305 * xmlSchemaValidateSimpleRestrictionType:
4306 * @ctxt: a schema validation context
4307 * @node: the top node.
4308 *
4309 * Validate the content of a restriction type.
4310 *
4311 * Returns 0 if the element is schemas valid, a positive error code
4312 * number otherwise and -1 in case of internal or API error.
4313 */
4314static int
4315xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
4316 xmlNodePtr node)
4317{
4318 xmlNodePtr child;
4319 xmlSchemaTypePtr type;
4320 int ret;
4321
4322 child = ctxt->node;
4323 type = ctxt->type;
4324
4325 if ((ctxt == NULL) || (type == NULL)) {
4326 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4327 if (ctxt->error != NULL)
4328 ctxt->error(ctxt->userData,
4329 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n",
4330 node->name);
4331 return (-1);
4332 }
4333 /*
4334 * Only text and text based entities references shall be found there
4335 */
4336 ret = xmlSchemaValidateCheckNodeList(child);
4337 if (ret < 0) {
4338 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4339 if (ctxt->error != NULL)
4340 ctxt->error(ctxt->userData,
4341 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4342 node->name);
4343 return (-1);
4344 } else if (ret == 0) {
4345 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4346 if (ctxt->error != NULL)
4347 ctxt->error(ctxt->userData,
4348 "Element %s content is not a simple type\n",
4349 node->name);
4350 return (-1);
4351 }
4352 ctxt->type = type->subtypes;
4353 xmlSchemaValidateContent(ctxt, node);
4354 ctxt->type = type;
4355 return (ret);
4356}
4357#endif
4358
4359/**
4360 * xmlSchemaValidateSimpleType:
4361 * @ctxt: a schema validation context
4362 * @node: the top node.
4363 *
4364 * Validate the content of an simple type.
4365 *
4366 * Returns 0 if the element is schemas valid, a positive error code
4367 * number otherwise and -1 in case of internal or API error.
4368 */
4369static int
4370xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4371 xmlNodePtr child;
4372 xmlSchemaTypePtr type;
4373 xmlAttrPtr attr;
4374 int ret;
4375
4376 child = ctxt->node;
4377 type = ctxt->type;
4378
4379 if ((ctxt == NULL) || (type == NULL)) {
4380 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4381 if (ctxt->error != NULL)
4382 ctxt->error(ctxt->userData,
4383 "Internal error: xmlSchemaValidateSimpleType %s\n",
4384 node->name);
4385 return(-1);
4386 }
4387 /*
4388 * Only text and text based entities references shall be found there
4389 */
4390 ret = xmlSchemaValidateCheckNodeList(child);
4391 if (ret < 0) {
4392 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4393 if (ctxt->error != NULL)
4394 ctxt->error(ctxt->userData,
4395 "Internal error: xmlSchemaValidateSimpleType %s content\n",
4396 node->name);
4397 return(-1);
4398 } else if (ret == 0) {
4399 ctxt->err = XML_SCHEMAS_ERR_NOTSIMPLE;
4400 if (ctxt->error != NULL)
4401 ctxt->error(ctxt->userData,
4402 "Element %s content is not a simple type\n",
4403 node->name);
4404 return(-1);
4405 }
4406 /*
4407 * Validation Rule: Element Locally Valid (Type): 3.1.1
4408 */
4409 attr = node->properties;
4410 while (attr != NULL) {
4411 if ((attr->ns == NULL) ||
4412 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
4413 ((!xmlStrEqual(attr->name, BAD_CAST"type")) &&
4414 (!xmlStrEqual(attr->name, BAD_CAST"nil")) &&
4415 (!xmlStrEqual(attr->name, BAD_CAST"schemasLocation")) &&
4416 (!xmlStrEqual(attr->name, BAD_CAST"noNamespaceSchemaLocation")))) {
4417 ctxt->err = XML_SCHEMAS_ERR_INVALIDATTR;
4418 if (ctxt->error != NULL)
4419 ctxt->error(ctxt->userData,
4420 "Element %s: attribute %s should not be present\n",
4421 child->name, attr->name);
4422 return(ctxt->err);
4423 }
4424 }
4425
4426 ctxt->type = type->subtypes;
4427 ret = xmlSchemaValidateSimpleContent(ctxt, node);
4428 ctxt->type = type;
4429 return(ret);
4430}
4431
4432/**
4433 * xmlSchemaValidateElementType:
4434 * @ctxt: a schema validation context
4435 * @node: the top node.
4436 *
4437 * Validate the content of an element type.
4438 * Validation Rule: Element Locally Valid (Complex Type)
4439 *
4440 * Returns 0 if the element is schemas valid, a positive error code
4441 * number otherwise and -1 in case of internal or API error.
4442 */
4443static int
4444xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4445 xmlNodePtr child;
4446 xmlSchemaTypePtr type;
4447 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
4448 xmlSchemaElementPtr decl;
4449 int ret, attrBase;
4450
4451 oldregexp = ctxt->regexp;
4452
4453 child = ctxt->node;
4454 type = ctxt->type;
4455
4456 if ((ctxt == NULL) || (type == NULL)) {
4457 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4458 if (ctxt->error != NULL)
4459 ctxt->error(ctxt->userData,
4460 "Internal error: xmlSchemaValidateElementType\n",
4461 node->name);
4462 return(-1);
4463 }
4464 if (child == NULL) {
4465 if (type->minOccurs > 0) {
4466 ctxt->err = XML_SCHEMAS_ERR_MISSING;
4467 if (ctxt->error != NULL)
4468 ctxt->error(ctxt->userData,
4469 "Element %s: missing child %s\n",
4470 node->name, type->name);
4471 }
4472 return(ctxt->err);
4473 }
4474
4475 /*
4476 * Verify the element matches
4477 */
4478 if (!xmlStrEqual(child->name, type->name)) {
4479 ctxt->err = XML_SCHEMAS_ERR_WRONGELEM;
4480 if (ctxt->error != NULL)
4481 ctxt->error(ctxt->userData,
4482 "Element %s: missing child %s found %s\n",
4483 node->name, type->name, child->name);
4484 return(ctxt->err);
4485 }
4486 /*
4487 * Verify the attributes
4488 */
4489 attrBase = ctxt->attrBase;
4490 ctxt->attrBase = ctxt->attrNr;
4491 xmlSchemaRegisterAttributes(ctxt, child->properties);
4492 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
4493 /*
4494 * Verify the element content recursively
4495 */
4496 decl = (xmlSchemaElementPtr) type;
4497 oldregexp = ctxt->regexp;
4498 if (decl->contModel != NULL) {
4499 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
4500 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
4501 ctxt);
4502#ifdef DEBUG_AUTOMATA
4503 xmlGenericError(xmlGenericErrorContext,
4504 "====> %s\n", node->name);
4505#endif
4506 }
4507 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr)type,
4508 type->subtypes);
4509
4510 if (decl->contModel != NULL) {
4511 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
4512#ifdef DEBUG_AUTOMATA
4513 xmlGenericError(xmlGenericErrorContext,
4514 "====> %s : %d\n", node->name, ret);
4515#endif
4516 if (ret == 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004517 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004518 if (ctxt->error != NULL)
4519 ctxt->error(ctxt->userData, "Element %s content check failed\n",
4520 node->name);
4521 } else if (ret < 0) {
Daniel Veillard8651f532002-04-17 09:06:27 +00004522 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
Daniel Veillard4255d502002-04-16 15:50:10 +00004523 if (ctxt->error != NULL)
4524 ctxt->error(ctxt->userData, "Element %s content check failure\n",
4525 node->name);
4526#ifdef DEBUG_CONTENT
4527 } else {
4528 xmlGenericError(xmlGenericErrorContext,
4529 "Element %s content check succeeded\n", node->name);
4530
4531#endif
4532 }
4533 xmlRegFreeExecCtxt(ctxt->regexp);
4534 }
4535 /*
4536 * Verify that all attributes were Schemas-validated
4537 */
4538 xmlSchemaCheckAttributes(ctxt, node);
4539 ctxt->attrNr = ctxt->attrBase;
4540 ctxt->attrBase = attrBase;
4541
4542 ctxt->regexp = oldregexp;
4543
4544 ctxt->node = child;
4545 ctxt->type = type;
4546 return(ctxt->err);
4547}
4548
4549/**
4550 * xmlSchemaValidateBasicType:
4551 * @ctxt: a schema validation context
4552 * @node: the top node.
4553 *
4554 * Validate the content of an element expected to be a basic type type
4555 *
4556 * Returns 0 if the element is schemas valid, a positive error code
4557 * number otherwise and -1 in case of internal or API error.
4558 */
4559static int
4560xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4561 int ret;
4562 xmlNodePtr child, cur;
4563 xmlSchemaTypePtr type;
4564 xmlChar *value; /* lexical representation */
4565
4566 child = ctxt->node;
4567 type = ctxt->type;
4568
4569 if ((ctxt == NULL) || (type == NULL)) {
4570 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4571 if (ctxt->error != NULL)
4572 ctxt->error(ctxt->userData,
4573 "Internal error: xmlSchemaValidateBasicType\n",
4574 node->name);
4575 return(-1);
4576 }
4577 /*
4578 * First check the content model of the node.
4579 */
4580 cur = child;
4581 while (cur != NULL) {
4582 switch (cur->type) {
4583 case XML_TEXT_NODE:
4584 case XML_CDATA_SECTION_NODE:
4585 case XML_PI_NODE:
4586 case XML_COMMENT_NODE:
4587 case XML_XINCLUDE_START:
4588 case XML_XINCLUDE_END:
4589 break;
4590 case XML_ENTITY_REF_NODE:
4591 case XML_ENTITY_NODE:
4592 TODO
4593 break;
4594 case XML_ELEMENT_NODE:
4595 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4596 if (ctxt->error != NULL)
4597 ctxt->error(ctxt->userData,
4598 "Element %s: child %s should not be present\n",
4599 node->name, cur->name);
4600 return(ctxt->err);
4601 case XML_ATTRIBUTE_NODE:
4602 case XML_DOCUMENT_NODE:
4603 case XML_DOCUMENT_TYPE_NODE:
4604 case XML_DOCUMENT_FRAG_NODE:
4605 case XML_NOTATION_NODE:
4606 case XML_HTML_DOCUMENT_NODE:
4607 case XML_DTD_NODE:
4608 case XML_ELEMENT_DECL:
4609 case XML_ATTRIBUTE_DECL:
4610 case XML_ENTITY_DECL:
4611 case XML_NAMESPACE_DECL:
4612#ifdef LIBXML_DOCB_ENABLED
4613 case XML_DOCB_DOCUMENT_NODE:
4614#endif
4615 ctxt->err = XML_SCHEMAS_ERR_INVALIDELEM;
4616 if (ctxt->error != NULL)
4617 ctxt->error(ctxt->userData,
4618 "Element %s: node type %d unexpected here\n",
4619 node->name, cur->type);
4620 return(ctxt->err);
4621 }
4622 cur = cur->next;
4623 }
4624 if (child == NULL)
4625 value = NULL;
4626 else
4627 value = xmlNodeGetContent(child->parent);
4628
4629 if (ctxt->value != NULL) {
4630 xmlSchemaFreeValue(ctxt->value);
4631 ctxt->value = NULL;
4632 }
4633 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
4634 if (value != NULL)
4635 xmlFree(value);
4636 if (ret != 0) {
4637 ctxt->error(ctxt->userData,
4638 "Element %s: failed to validate basic type %s\n",
4639 node->name, type->name);
4640 }
4641 return(ret);
4642}
4643
4644/**
4645 * xmlSchemaValidateComplexType:
4646 * @ctxt: a schema validation context
4647 * @node: the top node.
4648 *
4649 * Validate the content of an element expected to be a complex type type
4650 * xmlschema-1.html#cvc-complex-type
4651 * Validation Rule: Element Locally Valid (Complex Type)
4652 *
4653 * Returns 0 if the element is schemas valid, a positive error code
4654 * number otherwise and -1 in case of internal or API error.
4655 */
4656static int
4657xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4658 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00004659 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00004660 int ret;
4661
4662 child = ctxt->node;
4663 type = ctxt->type;
4664
Daniel Veillard4255d502002-04-16 15:50:10 +00004665 switch (type->contentType) {
4666 case XML_SCHEMA_CONTENT_EMPTY:
4667 if (child != NULL) {
4668 if (ctxt->error != NULL)
4669 ctxt->error(ctxt->userData,
4670 "Element %s is supposed to be empty\n",
4671 node->name);
4672 }
Daniel Veillarde19fc232002-04-22 16:01:24 +00004673 if (type->attributes != NULL) {
4674 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4675 }
4676 subtype = type->subtypes;
4677 while (subtype != NULL) {
4678 ctxt->type = subtype;
4679 xmlSchemaValidateComplexType(ctxt, node);
4680 subtype = subtype->next;
4681 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004682 break;
4683 case XML_SCHEMA_CONTENT_ELEMENTS:
4684 case XML_SCHEMA_CONTENT_MIXED:
4685 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
4686 /*
4687 * Skip ignorable nodes in that context
4688 */
4689 child = xmlSchemaSkipIgnored(ctxt, type, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00004690 while (child != NULL) {
4691 if (child->type == XML_ELEMENT_NODE) {
4692 ret = xmlRegExecPushString(ctxt->regexp,
4693 child->name, child);
4694#ifdef DEBUG_AUTOMATA
4695 if (ret < 0)
4696 xmlGenericError(xmlGenericErrorContext,
4697 " --> %s Error\n", child->name);
4698 else
4699 xmlGenericError(xmlGenericErrorContext,
4700 " --> %s\n", child->name);
4701#endif
4702 }
4703 child = child->next;
4704 /*
4705 * Skip ignorable nodes in that context
4706 */
4707 child = xmlSchemaSkipIgnored(ctxt, type, child);
4708 }
4709 break;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004710 case XML_SCHEMA_CONTENT_BASIC: {
4711 if (type->subtypes != NULL) {
4712 ctxt->type = type->subtypes;
4713 xmlSchemaValidateComplexType(ctxt, node);
4714 }
4715 if (type->baseType != NULL) {
4716 ctxt->type = type->baseType;
4717 xmlSchemaValidateBasicType(ctxt, node);
4718 }
4719 if (type->attributes != NULL) {
4720 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4721 }
4722 ctxt->type = type;
4723 break;
4724 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004725 default:
4726 TODO
4727 xmlGenericError(xmlGenericErrorContext,
4728 "unimplemented content type %d\n",
4729 type->contentType);
4730 }
4731 return(ctxt->err);
4732}
4733
4734/**
4735 * xmlSchemaValidateContent:
4736 * @ctxt: a schema validation context
4737 * @elem: an element
4738 * @type: the type declaration
4739 *
4740 * Validate the content of an element against the type.
4741 *
4742 * Returns 0 if the element is schemas valid, a positive error code
4743 * number otherwise and -1 in case of internal or API error.
4744 */
4745static int
4746xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) {
4747 xmlNodePtr child;
4748 xmlSchemaTypePtr type;
4749
4750 child = ctxt->node;
4751 type = ctxt->type;
4752
Daniel Veillarde19fc232002-04-22 16:01:24 +00004753 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4754
Daniel Veillard4255d502002-04-16 15:50:10 +00004755 switch (type->type) {
4756 case XML_SCHEMA_TYPE_ANY:
4757 /* Any type will do it, fine */
4758 TODO /* handle recursivity */
4759 break;
4760 case XML_SCHEMA_TYPE_COMPLEX:
4761 xmlSchemaValidateComplexType(ctxt, node);
4762 break;
4763 case XML_SCHEMA_TYPE_ELEMENT: {
4764 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
4765 /*
4766 * Handle element reference here
4767 */
4768 if (decl->ref != NULL) {
4769 if (decl->refDecl == NULL) {
4770 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
4771 if (ctxt->error != NULL)
4772 ctxt->error(ctxt->userData,
4773 "Internal error: element reference %s not resolved\n",
4774 decl->ref);
4775 return(-1);
4776 }
4777 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
4778 decl = decl->refDecl;
4779 }
4780 xmlSchemaValidateElementType(ctxt, node);
4781 ctxt->type = type;
4782 break;
4783 }
4784 case XML_SCHEMA_TYPE_BASIC:
4785 xmlSchemaValidateBasicType(ctxt, node);
4786 break;
4787 case XML_SCHEMA_TYPE_FACET:
4788 TODO
4789 break;
4790 case XML_SCHEMA_TYPE_SIMPLE:
4791 xmlSchemaValidateSimpleType(ctxt, node);
4792 break;
4793 case XML_SCHEMA_TYPE_SEQUENCE:
4794 TODO
4795 break;
4796 case XML_SCHEMA_TYPE_CHOICE:
4797 TODO
4798 break;
4799 case XML_SCHEMA_TYPE_ALL:
4800 TODO
4801 break;
4802 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
4803 TODO
4804 break;
4805 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4806 TODO
4807 break;
4808 case XML_SCHEMA_TYPE_UR:
4809 TODO
4810 break;
4811 case XML_SCHEMA_TYPE_RESTRICTION:
4812 /*xmlSchemaValidateRestrictionType(ctxt, node); */
4813 TODO
4814 break;
4815 case XML_SCHEMA_TYPE_EXTENSION:
4816 TODO
4817 break;
4818 case XML_SCHEMA_TYPE_ATTRIBUTE:
4819 TODO
4820 break;
4821 case XML_SCHEMA_TYPE_GROUP:
4822 TODO
4823 break;
4824 case XML_SCHEMA_TYPE_NOTATION:
4825 TODO
4826 break;
4827 case XML_SCHEMA_TYPE_LIST:
4828 TODO
4829 break;
4830 case XML_SCHEMA_TYPE_UNION:
4831 TODO
4832 break;
4833 case XML_SCHEMA_FACET_MININCLUSIVE:
4834 TODO
4835 break;
4836 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4837 TODO
4838 break;
4839 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4840 TODO
4841 break;
4842 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4843 TODO
4844 break;
4845 case XML_SCHEMA_FACET_TOTALDIGITS:
4846 TODO
4847 break;
4848 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4849 TODO
4850 break;
4851 case XML_SCHEMA_FACET_PATTERN:
4852 TODO
4853 break;
4854 case XML_SCHEMA_FACET_ENUMERATION:
4855 TODO
4856 break;
4857 case XML_SCHEMA_FACET_WHITESPACE:
4858 TODO
4859 break;
4860 case XML_SCHEMA_FACET_LENGTH:
4861 TODO
4862 break;
4863 case XML_SCHEMA_FACET_MAXLENGTH:
4864 TODO
4865 break;
4866 case XML_SCHEMA_FACET_MINLENGTH:
4867 TODO
4868 break;
4869 }
4870 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
4871
4872 if (ctxt->node == NULL)
4873 return(ctxt->err);
4874 ctxt->node = ctxt->node->next;
4875 ctxt->type = type->next;
4876 return(ctxt->err);
4877}
4878
4879/**
4880 * xmlSchemaValidateType:
4881 * @ctxt: a schema validation context
4882 * @elem: an element
4883 * @type: the list of type declarations
4884 *
4885 * Validate the content of an element against the types.
4886 *
4887 * Returns 0 if the element is schemas valid, a positive error code
4888 * number otherwise and -1 in case of internal or API error.
4889 */
4890static int
4891xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4892 xmlSchemaElementPtr elemDecl,
4893 xmlSchemaTypePtr type) {
4894 xmlChar *nil;
4895
4896 if ((elem->content == NULL) || (type == NULL) || (elemDecl == NULL))
4897 return(0);
4898 /*
4899 * 3.3.4 : 2
4900 */
4901 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
4902 ctxt->err = XML_SCHEMAS_ERR_ISABSTRACT;
4903 if (ctxt->error != NULL)
4904 ctxt->error(ctxt->userData, "Element %s is abstract\n", elem->name);
4905 return(ctxt->err);
4906 }
4907 /*
4908 * 3.3.4: 3
4909 */
4910 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
4911 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
4912 /* 3.3.4: 3.2 */
4913 if (xmlStrEqual(nil, BAD_CAST "true")) {
4914 if (elem->children != NULL) {
4915 ctxt->err = XML_SCHEMAS_ERR_NOTEMPTY;
4916 if (ctxt->error != NULL)
4917 ctxt->error(ctxt->userData, "Element %s is not empty\n",
4918 elem->name);
4919 return(ctxt->err);
4920 }
4921 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
4922 (elemDecl->value != NULL)) {
4923 ctxt->err = XML_SCHEMAS_ERR_HAVEDEFAULT;
4924 if (ctxt->error != NULL)
4925 ctxt->error(ctxt->userData,
4926 "Empty element %s cannot get a fixed value\n",
4927 elem->name);
4928 return(ctxt->err);
4929 }
4930 }
4931 } else {
4932 /* 3.3.4: 3.1 */
4933 if (nil != NULL) {
4934 ctxt->err = XML_SCHEMAS_ERR_NOTNILLABLE;
4935 if (ctxt->error != NULL)
4936 ctxt->error(ctxt->userData,
4937 "Element %s with xs:nil but not nillable\n",
4938 elem->name);
4939 xmlFree(nil);
4940 return(ctxt->err);
4941 }
4942 }
4943
4944 /* TODO 3.3.4: 4 if the element carries xs:type*/
4945
4946 ctxt->type = elemDecl->subtypes;
4947 ctxt->node = elem->children;
4948 xmlSchemaValidateContent(ctxt, elem);
4949 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
4950
4951 return(ctxt->err);
4952}
4953
4954
4955/**
4956 * xmlSchemaValidateAttributes:
4957 * @ctxt: a schema validation context
4958 * @elem: an element
4959 * @attributes: the list of attribute declarations
4960 *
4961 * Validate the attributes of an element.
4962 *
4963 * Returns 0 if the element is schemas valid, a positive error code
4964 * number otherwise and -1 in case of internal or API error.
4965 */
4966static int
4967xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
4968 xmlSchemaAttributePtr attributes) {
4969 int i, ret;
4970 xmlAttrPtr attr;
4971 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004972 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00004973
4974 if (attributes == NULL)
4975 return(0);
4976 while (attributes != NULL) {
Daniel Veillard13e04c62002-04-23 17:51:29 +00004977 /*
4978 * Handle attribute groups
4979 */
4980 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
4981 group = (xmlSchemaAttributeGroupPtr) attributes;
4982 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
4983 attributes = group->next;
4984 continue;
4985 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004986 for (i = ctxt->attrBase;i < ctxt->attrNr;i++) {
4987 attr = ctxt->attr[i].attr;
4988 if (attr == NULL)
4989 continue;
4990 if (!xmlStrEqual(attr->name, attributes->name))
4991 continue;
4992 /*
4993 * TODO: handle the mess about namespaces here.
4994 */
4995 if ((attr->ns != NULL) /* || (attributes->ns != NULL) */) {
4996 TODO
4997 }
4998 if (attributes->subtypes == NULL) {
4999 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
5000 if (ctxt->error != NULL)
5001 ctxt->error(ctxt->userData,
5002 "Internal error: attribute %s type not resolved\n",
5003 attr->name);
5004 continue;
5005 }
5006 value = xmlNodeListGetString(elem->doc, attr->children, 1);
5007 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
Daniel Veillard13e04c62002-04-23 17:51:29 +00005008 value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005009 if (ret != 0) {
5010 ctxt->err = XML_SCHEMAS_ERR_ATTRINVALID;
5011 if (ctxt->error != NULL)
5012 ctxt->error(ctxt->userData,
5013 "attribute %s on %s does not match type\n",
5014 attr->name, elem->name);
5015 } else {
5016 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
5017 }
5018 if (value != NULL) {
5019 xmlFree(value);
5020 }
5021 }
5022 attributes = attributes->next;
5023 }
5024 return(ctxt->err);
5025}
5026
5027/**
5028 * xmlSchemaValidateElement:
5029 * @ctxt: a schema validation context
5030 * @elem: an element
5031 *
5032 * Validate an element in a tree
5033 *
5034 * Returns 0 if the element is schemas valid, a positive error code
5035 * number otherwise and -1 in case of internal or API error.
5036 */
5037static int
5038xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) {
5039 xmlSchemaElementPtr elemDecl;
5040 int ret, attrBase;
5041
5042 if (elem->ns != NULL)
5043 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5044 elem->name, elem->ns->href, NULL);
5045 else
5046 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5047 elem->name, NULL, NULL);
5048 /*
5049 * 3.3.4 : 1
5050 */
5051 if (elemDecl == NULL) {
5052 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5053 if (ctxt->error != NULL)
5054 ctxt->error(ctxt->userData, "Element %s not declared\n",
5055 elem->name);
5056 return(ctxt->err);
5057 }
5058 if (elemDecl->subtypes == NULL) {
5059 ctxt->err = XML_SCHEMAS_ERR_NOTYPE;
5060 if (ctxt->error != NULL)
5061 ctxt->error(ctxt->userData, "Element %s has no type\n",
5062 elem->name);
5063 return(ctxt->err);
5064 }
5065 /*
5066 * Verify the attributes
5067 */
5068 attrBase = ctxt->attrBase;
5069 ctxt->attrBase = ctxt->attrNr;
5070 xmlSchemaRegisterAttributes(ctxt, elem->properties);
5071 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
5072 /*
5073 * Verify the element content recursively
5074 */
5075 if (elemDecl->contModel != NULL) {
5076 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
5077 (xmlRegExecCallbacks) xmlSchemaValidateCallback,
5078 ctxt);
5079#ifdef DEBUG_AUTOMATA
5080 xmlGenericError(xmlGenericErrorContext,
5081 "====> %s\n", elem->name);
5082#endif
5083 }
5084 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005085 if (elemDecl->contModel != NULL) {
5086 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005087#ifdef DEBUG_AUTOMATA
Daniel Veillard4255d502002-04-16 15:50:10 +00005088 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005089 "====> %s : %d\n", elem->name, ret);
5090#endif
5091 if (ret == 0) {
5092 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5093 if (ctxt->error != NULL)
5094 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5095 elem->name);
5096 } else if (ret < 0) {
5097 ctxt->err = XML_SCHEMAS_ERR_ELEMCONT;
5098 if (ctxt->error != NULL)
5099 ctxt->error(ctxt->userData, "Element %s content check failed\n",
5100 elem->name);
5101#ifdef DEBUG_CONTENT
5102 } else {
5103 xmlGenericError(xmlGenericErrorContext,
5104 "Element %s content check succeeded\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005105
5106#endif
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005107 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005108 xmlRegFreeExecCtxt(ctxt->regexp);
5109 }
5110 /*
5111 * Verify that all attributes were Schemas-validated
5112 */
5113 xmlSchemaCheckAttributes(ctxt, elem);
5114 ctxt->attrNr = ctxt->attrBase;
5115 ctxt->attrBase = attrBase;
5116
5117 return(ctxt->err);
5118}
5119
5120/**
5121 * xmlSchemaValidateDocument:
5122 * @ctxt: a schema validation context
5123 * @doc: a parsed document tree
5124 *
5125 * Validate a document tree in memory.
5126 *
5127 * Returns 0 if the document is schemas valid, a positive error code
5128 * number otherwise and -1 in case of internal or API error.
5129 */
5130static int
5131xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5132 xmlNodePtr root;
5133 xmlSchemaElementPtr elemDecl;
5134
5135 root = xmlDocGetRootElement(doc);
5136 if (root == NULL) {
5137 ctxt->err = XML_SCHEMAS_ERR_NOROOT;
5138 if (ctxt->error != NULL)
5139 ctxt->error(ctxt->userData, "document has no root\n");
5140 return(ctxt->err);
5141 }
5142 if (root->ns != NULL)
5143 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5144 root->name, root->ns->href, NULL);
5145 else
5146 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
5147 root->name, NULL, NULL);
5148 if (elemDecl == NULL) {
5149 ctxt->err = XML_SCHEMAS_ERR_UNDECLAREDELEM;
5150 if (ctxt->error != NULL)
5151 ctxt->error(ctxt->userData, "Element %s not declared\n",
5152 root->name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00005153 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillard4255d502002-04-16 15:50:10 +00005154 ctxt->err = XML_SCHEMAS_ERR_NOTTOPLEVEL;
5155 if (ctxt->error != NULL)
5156 ctxt->error(ctxt->userData, "Root element %s not toplevel\n",
5157 root->name);
5158 }
5159 /*
5160 * Okay, start the recursive validation
5161 */
5162 xmlSchemaValidateElement(ctxt, root);
5163
5164 return(ctxt->err);
5165}
5166
5167/************************************************************************
5168 * *
5169 * SAX Validation code *
5170 * *
5171 ************************************************************************/
5172
5173/************************************************************************
5174 * *
5175 * Validation interfaces *
5176 * *
5177 ************************************************************************/
5178
5179/**
5180 * xmlSchemaNewValidCtxt:
5181 * @schema: a precompiled XML Schemas
5182 *
5183 * Create an XML Schemas validation context based on the given schema
5184 *
5185 * Returns the validation context or NULL in case of error
5186 */
5187xmlSchemaValidCtxtPtr
5188xmlSchemaNewValidCtxt(xmlSchemaPtr schema) {
5189 xmlSchemaValidCtxtPtr ret;
5190
5191 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
5192 if (ret == NULL) {
5193 xmlGenericError(xmlGenericErrorContext,
5194 "Failed to allocate new schama validation context\n");
5195 return (NULL);
5196 }
5197 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
5198 ret->schema = schema;
5199 ret->attrNr = 0;
5200 ret->attrMax = 10;
5201 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
5202 sizeof(xmlSchemaAttrState));
5203 if (ret->attr == NULL) {
5204 free(ret);
5205 return(NULL);
5206 }
5207 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
5208 return (ret);
5209}
5210
5211/**
5212 * xmlSchemaFreeValidCtxt:
5213 * @ctxt: the schema validation context
5214 *
5215 * Free the resources associated to the schema validation context
5216 */
5217void
5218xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) {
5219 if (ctxt == NULL)
5220 return;
5221 if (ctxt->attr != NULL)
5222 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00005223 if (ctxt->value != NULL)
5224 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005225 xmlFree(ctxt);
5226}
5227
5228/**
5229 * xmlSchemaSetValidErrors:
5230 * @ctxt: a schema validation context
5231 * @err: the error function
5232 * @warn: the warning function
5233 * @ctxt: the functions context
5234 *
5235 * Set the error and warning callback informations
5236 */
5237void
5238xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
5239 xmlSchemaValidityErrorFunc err,
5240 xmlSchemaValidityWarningFunc warn, void *ctx) {
5241 if (ctxt == NULL)
5242 return;
5243 ctxt->error = err;
5244 ctxt->warning = warn;
5245 ctxt->userData = ctx;
5246}
5247
5248/**
5249 * xmlSchemaValidateDoc:
5250 * @ctxt: a schema validation context
5251 * @doc: a parsed document tree
5252 *
5253 * Validate a document tree in memory.
5254 *
5255 * Returns 0 if the document is schemas valid, a positive error code
5256 * number otherwise and -1 in case of internal or API error.
5257 */
5258int
5259xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) {
5260 int ret;
5261
5262 if ((ctxt == NULL) || (doc == NULL))
5263 return(-1);
5264
5265 ctxt->doc = doc;
5266 ret = xmlSchemaValidateDocument(ctxt, doc);
5267 return(ret);
5268}
5269
5270/**
5271 * xmlSchemaValidateStream:
5272 * @ctxt: a schema validation context
5273 * @input: the input to use for reading the data
5274 * @enc: an optional encoding information
5275 * @sax: a SAX handler for the resulting events
5276 * @user_data: the context to provide to the SAX handler.
5277 *
5278 * Validate a document tree in memory.
5279 *
5280 * Returns 0 if the document is schemas valid, a positive error code
5281 * number otherwise and -1 in case of internal or API error.
5282 */
5283int
5284xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
5285 xmlParserInputBufferPtr input, xmlCharEncoding enc,
5286 xmlSAXHandlerPtr sax, void *user_data) {
5287 if ((ctxt == NULL) || (input == NULL))
5288 return(-1);
5289 ctxt->input = input;
5290 ctxt->enc = enc;
5291 ctxt->sax = sax;
5292 ctxt->user_data = user_data;
5293 TODO
5294 return(0);
5295}
5296
5297#endif /* LIBXML_SCHEMAS_ENABLED */