blob: d084f1e1146f3449bc985a8d463c4bc0224bd473 [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
Daniel Veillardb0f397e2003-12-23 23:30:53 +000010/*
11 * TODO:
12 * - when types are redefined in includes, check that all
13 * types in the redef list are equal
14 * -> need a type equality operation.
15 */
Daniel Veillard4255d502002-04-16 15:50:10 +000016#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <libxml/xmlmemory.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/hash.h>
Daniel Veillard5a872412002-05-22 06:40:27 +000026#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000027
28#include <libxml/xmlschemas.h>
29#include <libxml/schemasInternals.h>
30#include <libxml/xmlschemastypes.h>
31#include <libxml/xmlautomata.h>
32#include <libxml/xmlregexp.h>
Daniel Veillardbe9c6322003-11-22 20:37:51 +000033#include <libxml/dict.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000034
Daniel Veillarda84c0b32003-06-02 16:58:46 +000035/* #define DEBUG 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000036
Daniel Veillard82bbbd42003-05-11 20:16:09 +000037/* #define DEBUG_CONTENT 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000038
Daniel Veillard82bbbd42003-05-11 20:16:09 +000039/* #define DEBUG_TYPE 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000040
Daniel Veillard118aed72002-09-24 14:13:13 +000041/* #define DEBUG_CONTENT_REGEXP 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000042
Daniel Veillard4255d502002-04-16 15:50:10 +000043/* #define DEBUG_AUTOMATA 1 */
44
45#define UNBOUNDED (1 << 30)
46#define TODO \
47 xmlGenericError(xmlGenericErrorContext, \
48 "Unimplemented block at %s:%d\n", \
49 __FILE__, __LINE__);
50
Daniel Veillard5a872412002-05-22 06:40:27 +000051#define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar *)"the default namespace"
52
Daniel Veillard4255d502002-04-16 15:50:10 +000053/*
54 * The XML Schemas namespaces
55 */
56static const xmlChar *xmlSchemaNs = (const xmlChar *)
57 "http://www.w3.org/2001/XMLSchema";
58
59static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
60 "http://www.w3.org/2001/XMLSchema-instance";
61
62#define IS_SCHEMA(node, type) \
63 ((node != NULL) && (node->ns != NULL) && \
64 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
65 (xmlStrEqual(node->ns->href, xmlSchemaNs)))
66
67#define XML_SCHEMAS_PARSE_ERROR 1
68
Daniel Veillardbd2904b2003-11-25 15:38:59 +000069#define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT
70
Daniel Veillard4255d502002-04-16 15:50:10 +000071struct _xmlSchemaParserCtxt {
Daniel Veillardd0c9c322003-10-10 00:49:42 +000072 void *userData; /* user specific data block */
73 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
74 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillarde19fc232002-04-22 16:01:24 +000075 xmlSchemaValidError err;
Daniel Veillardd0c9c322003-10-10 00:49:42 +000076 int nberrors;
Daniel Veillard659e71e2003-10-10 14:10:40 +000077 xmlStructuredErrorFunc serror;
Daniel Veillard4255d502002-04-16 15:50:10 +000078
Daniel Veillardbe9c6322003-11-22 20:37:51 +000079 xmlSchemaPtr topschema; /* The main schema */
80 xmlHashTablePtr namespaces; /* Hash table of namespaces to schemas */
81
Daniel Veillardd0c9c322003-10-10 00:49:42 +000082 xmlSchemaPtr schema; /* The schema in use */
Daniel Veillardbe9c6322003-11-22 20:37:51 +000083 const xmlChar *container; /* the current element, group, ... */
Daniel Veillard4255d502002-04-16 15:50:10 +000084 int counter;
85
Daniel Veillardbe9c6322003-11-22 20:37:51 +000086 const xmlChar *URL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +000087 xmlDocPtr doc;
Daniel Veillard4255d502002-04-16 15:50:10 +000088
Daniel Veillardd0c9c322003-10-10 00:49:42 +000089 const char *buffer;
90 int size;
Daniel Veillard6045c902002-10-09 21:13:59 +000091
Daniel Veillard4255d502002-04-16 15:50:10 +000092 /*
93 * Used to build complex element content models
94 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000095 xmlAutomataPtr am;
Daniel Veillard4255d502002-04-16 15:50:10 +000096 xmlAutomataStatePtr start;
97 xmlAutomataStatePtr end;
98 xmlAutomataStatePtr state;
Daniel Veillardbe9c6322003-11-22 20:37:51 +000099
100 xmlDictPtr dict; /* dictionnary for interned string names */
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000101 int includes; /* the inclusion level, 0 for root or imports */
Daniel Veillard4255d502002-04-16 15:50:10 +0000102};
103
104
105#define XML_SCHEMAS_ATTR_UNKNOWN 1
106#define XML_SCHEMAS_ATTR_CHECKED 2
107
108typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
109typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
110struct _xmlSchemaAttrState {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000111 xmlAttrPtr attr;
112 int state;
Daniel Veillard4255d502002-04-16 15:50:10 +0000113};
114
115/**
116 * xmlSchemaValidCtxt:
117 *
118 * A Schemas validation context
119 */
120
121struct _xmlSchemaValidCtxt {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000122 void *userData; /* user specific data block */
123 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
124 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000125 xmlStructuredErrorFunc serror;
Daniel Veillard4255d502002-04-16 15:50:10 +0000126
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000127 xmlSchemaPtr schema; /* The schema in use */
128 xmlDocPtr doc;
Daniel Veillard4255d502002-04-16 15:50:10 +0000129 xmlParserInputBufferPtr input;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000130 xmlCharEncoding enc;
131 xmlSAXHandlerPtr sax;
132 void *user_data;
Daniel Veillard4255d502002-04-16 15:50:10 +0000133
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000134 xmlDocPtr myDoc;
135 int err;
136 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +0000137
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000138 xmlNodePtr node;
139 xmlNodePtr cur;
140 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000141
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000142 xmlRegExecCtxtPtr regexp;
143 xmlSchemaValPtr value;
Daniel Veillard4255d502002-04-16 15:50:10 +0000144
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000145 int attrNr;
146 int attrBase;
147 int attrMax;
148 xmlSchemaAttrStatePtr attr;
Daniel Veillard4255d502002-04-16 15:50:10 +0000149};
150
Daniel Veillard1d913862003-11-21 00:28:39 +0000151/*
152 * These are the entries in the schemas importSchemas hash table
153 */
154typedef struct _xmlSchemaImport xmlSchemaImport;
155typedef xmlSchemaImport *xmlSchemaImportPtr;
156struct _xmlSchemaImport {
157 const xmlChar *schemaLocation;
158 xmlSchemaPtr schema;
159};
Daniel Veillard4255d502002-04-16 15:50:10 +0000160
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000161/*
162 * These are the entries associated to includes in a schemas
163 */
164typedef struct _xmlSchemaInclude xmlSchemaInclude;
165typedef xmlSchemaInclude *xmlSchemaIncludePtr;
166struct _xmlSchemaInclude {
167 xmlSchemaIncludePtr next;
168
169 const xmlChar *schemaLocation;
170 xmlDocPtr doc;
171};
172
Daniel Veillard4255d502002-04-16 15:50:10 +0000173/************************************************************************
174 * *
175 * Some predeclarations *
176 * *
177 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000178static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
179 xmlSchemaTypePtr type,
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000180 const xmlChar * value);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000181
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000182static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt,
183 xmlSchemaPtr schema,
184 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000185/************************************************************************
186 * *
187 * Datatype error handlers *
188 * *
189 ************************************************************************/
190
191/**
192 * xmlSchemaPErrMemory:
193 * @node: a context node
194 * @extra: extra informations
195 *
196 * Handle an out of memory condition
197 */
198static void
199xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt,
200 const char *extra, xmlNodePtr node)
201{
202 if (ctxt != NULL)
203 ctxt->nberrors++;
204 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
205 extra);
206}
207
208/**
209 * xmlSchemaPErr:
210 * @ctxt: the parsing context
211 * @node: the context node
212 * @error: the error code
213 * @msg: the error message
214 * @str1: extra data
215 * @str2: extra data
216 *
217 * Handle a parser error
218 */
219static void
220xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error,
221 const char *msg, const xmlChar * str1, const xmlChar * str2)
222{
223 xmlGenericErrorFunc channel = NULL;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000224 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000225 void *data = NULL;
226
227 if (ctxt != NULL) {
228 ctxt->nberrors++;
229 channel = ctxt->error;
230 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000231 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000232 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000233 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000234 error, XML_ERR_ERROR, NULL, 0,
235 (const char *) str1, (const char *) str2, NULL, 0, 0,
236 msg, str1, str2);
237}
238
239/**
240 * xmlSchemaPErr2:
241 * @ctxt: the parsing context
242 * @node: the context node
243 * @node: the current child
244 * @error: the error code
245 * @msg: the error message
246 * @str1: extra data
247 * @str2: extra data
248 *
249 * Handle a parser error
250 */
251static void
252xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
253 xmlNodePtr child, int error,
254 const char *msg, const xmlChar * str1, const xmlChar * str2)
255{
256 if (child != NULL)
257 xmlSchemaPErr(ctxt, child, error, msg, str1, str2);
258 else
259 xmlSchemaPErr(ctxt, node, error, msg, str1, str2);
260}
261
262/**
263 * xmlSchemaVTypeErrMemory:
264 * @node: a context node
265 * @extra: extra informations
266 *
267 * Handle an out of memory condition
268 */
269static void
270xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt,
271 const char *extra, xmlNodePtr node)
272{
273 if (ctxt != NULL) {
274 ctxt->nberrors++;
275 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
276 }
277 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
278 extra);
279}
280
281/**
282 * xmlSchemaVErr3:
283 * @ctxt: the validation context
284 * @node: the context node
285 * @error: the error code
286 * @msg: the error message
287 * @str1: extra data
288 * @str2: extra data
289 * @str3: extra data
290 *
291 * Handle a validation error
292 */
293static void
294xmlSchemaVErr3(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
295 const char *msg, const xmlChar *str1, const xmlChar *str2,
296 const xmlChar *str3)
297{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000298 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000299 xmlGenericErrorFunc channel = NULL;
300 void *data = NULL;
301
302 if (ctxt != NULL) {
303 ctxt->nberrors++;
304 ctxt->err = error;
305 channel = ctxt->error;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000306 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000307 data = ctxt->userData;
308 }
309 /* reajust to global error numbers */
310 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000311 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000312 error, XML_ERR_ERROR, NULL, 0,
313 (const char *) str1, (const char *) str2,
314 (const char *) str3, 0, 0,
315 msg, str1, str2, str3);
316}
317/**
318 * xmlSchemaVErr:
319 * @ctxt: the validation context
320 * @node: the context node
321 * @error: the error code
322 * @msg: the error message
323 * @str1: extra data
324 * @str2: extra data
325 *
326 * Handle a validation error
327 */
328static void
329xmlSchemaVErr(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
330 const char *msg, const xmlChar * str1, const xmlChar * str2)
331{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000332 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000333 xmlGenericErrorFunc channel = NULL;
334 void *data = NULL;
335
336 if (ctxt != NULL) {
337 ctxt->nberrors++;
338 ctxt->err = error;
339 channel = ctxt->error;
340 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000341 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000342 }
343 /* reajust to global error numbers */
344 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000345 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000346 error, XML_ERR_ERROR, NULL, 0,
347 (const char *) str1, (const char *) str2, NULL, 0, 0,
348 msg, str1, str2);
349}
Daniel Veillard4255d502002-04-16 15:50:10 +0000350
351/************************************************************************
352 * *
353 * Allocation functions *
354 * *
355 ************************************************************************/
356
357/**
358 * xmlSchemaNewSchema:
359 * @ctxt: a schema validation context (optional)
360 *
361 * Allocate a new Schema structure.
362 *
363 * Returns the newly allocated structure or NULL in case or error
364 */
365static xmlSchemaPtr
366xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
367{
368 xmlSchemaPtr ret;
369
370 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
371 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000372 xmlSchemaPErrMemory(ctxt, "allocating schema", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +0000373 return (NULL);
374 }
375 memset(ret, 0, sizeof(xmlSchema));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000376 xmlDictReference(ctxt->dict);
377 ret->dict = ctxt->dict;
Daniel Veillard4255d502002-04-16 15:50:10 +0000378
379 return (ret);
380}
381
382/**
383 * xmlSchemaNewFacet:
Daniel Veillard4255d502002-04-16 15:50:10 +0000384 *
385 * Allocate a new Facet structure.
386 *
387 * Returns the newly allocated structure or NULL in case or error
388 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000389xmlSchemaFacetPtr
390xmlSchemaNewFacet(void)
Daniel Veillard4255d502002-04-16 15:50:10 +0000391{
392 xmlSchemaFacetPtr ret;
393
394 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
395 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000396 return (NULL);
397 }
398 memset(ret, 0, sizeof(xmlSchemaFacet));
399
400 return (ret);
401}
402
403/**
404 * xmlSchemaNewAnnot:
405 * @ctxt: a schema validation context (optional)
406 * @node: a node
407 *
408 * Allocate a new annotation structure.
409 *
410 * Returns the newly allocated structure or NULL in case or error
411 */
412static xmlSchemaAnnotPtr
413xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
414{
415 xmlSchemaAnnotPtr ret;
416
417 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
418 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000419 xmlSchemaPErrMemory(ctxt, "allocating annotation", node);
Daniel Veillard4255d502002-04-16 15:50:10 +0000420 return (NULL);
421 }
422 memset(ret, 0, sizeof(xmlSchemaAnnot));
423 ret->content = node;
424 return (ret);
425}
426
427/**
Daniel Veillardfdc91562002-07-01 21:52:03 +0000428 * xmlSchemaFreeAnnot:
429 * @annot: a schema type structure
430 *
431 * Deallocate a annotation structure
432 */
433static void
434xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
435{
436 if (annot == NULL)
437 return;
438 xmlFree(annot);
439}
440
441/**
Daniel Veillard1d913862003-11-21 00:28:39 +0000442 * xmlSchemaFreeImport:
443 * @import: a schema import structure
444 *
445 * Deallocate an import structure
446 */
447static void
448xmlSchemaFreeImport(xmlSchemaImportPtr import)
449{
450 if (import == NULL)
451 return;
452
453 xmlSchemaFree(import->schema);
Daniel Veillard1d913862003-11-21 00:28:39 +0000454 xmlFree(import);
455}
456
457/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000458 * xmlSchemaFreeInclude:
459 * @include: a schema include structure
460 *
461 * Deallocate an include structure
462 */
463static void
464xmlSchemaFreeInclude(xmlSchemaIncludePtr include)
465{
466 if (include == NULL)
467 return;
468
469 xmlFreeDoc(include->doc);
470 xmlFree(include);
471}
472
473/**
474 * xmlSchemaFreeIncludeList:
475 * @includes: a schema include list
476 *
477 * Deallocate an include structure
478 */
479static void
480xmlSchemaFreeIncludeList(xmlSchemaIncludePtr includes)
481{
482 xmlSchemaIncludePtr next;
483
484 while (includes != NULL) {
485 next = includes->next;
486 xmlSchemaFreeInclude(includes);
487 includes = next;
488 }
489}
490
491/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000492 * xmlSchemaFreeNotation:
493 * @schema: a schema notation structure
494 *
495 * Deallocate a Schema Notation structure.
496 */
497static void
498xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
499{
500 if (nota == NULL)
501 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000502 xmlFree(nota);
503}
504
505/**
506 * xmlSchemaFreeAttribute:
507 * @schema: a schema attribute structure
508 *
509 * Deallocate a Schema Attribute structure.
510 */
511static void
512xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
513{
514 if (attr == NULL)
515 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000516 xmlFree(attr);
517}
518
519/**
520 * xmlSchemaFreeAttributeGroup:
521 * @schema: a schema attribute group structure
522 *
523 * Deallocate a Schema Attribute Group structure.
524 */
525static void
526xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
527{
528 if (attr == NULL)
529 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000530 xmlFree(attr);
531}
532
533/**
534 * xmlSchemaFreeElement:
535 * @schema: a schema element structure
536 *
537 * Deallocate a Schema Element structure.
538 */
539static void
540xmlSchemaFreeElement(xmlSchemaElementPtr elem)
541{
542 if (elem == NULL)
543 return;
Daniel Veillard32370232002-10-16 14:08:14 +0000544 if (elem->annot != NULL)
545 xmlSchemaFreeAnnot(elem->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000546 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000547 xmlRegFreeRegexp(elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +0000548 xmlFree(elem);
549}
550
551/**
552 * xmlSchemaFreeFacet:
553 * @facet: a schema facet structure
554 *
555 * Deallocate a Schema Facet structure.
556 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000557void
Daniel Veillard4255d502002-04-16 15:50:10 +0000558xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
559{
560 if (facet == NULL)
561 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000562 if (facet->val != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000563 xmlSchemaFreeValue(facet->val);
Daniel Veillard4255d502002-04-16 15:50:10 +0000564 if (facet->regexp != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000565 xmlRegFreeRegexp(facet->regexp);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000566 if (facet->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000567 xmlSchemaFreeAnnot(facet->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000568 xmlFree(facet);
569}
570
571/**
572 * xmlSchemaFreeType:
573 * @type: a schema type structure
574 *
575 * Deallocate a Schema Type structure.
576 */
577void
578xmlSchemaFreeType(xmlSchemaTypePtr type)
579{
580 if (type == NULL)
581 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000582 if (type->annot != NULL)
Daniel Veillard32370232002-10-16 14:08:14 +0000583 xmlSchemaFreeAnnot(type->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000584 if (type->facets != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000585 xmlSchemaFacetPtr facet, next;
Daniel Veillard4255d502002-04-16 15:50:10 +0000586
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000587 facet = type->facets;
588 while (facet != NULL) {
589 next = facet->next;
590 xmlSchemaFreeFacet(facet);
591 facet = next;
592 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000593 }
594 xmlFree(type);
595}
596
597/**
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000598 * xmlSchemaFreeTypeList:
599 * @type: a schema type structure
600 *
601 * Deallocate a Schema Type structure.
602 */
603static void
604xmlSchemaFreeTypeList(xmlSchemaTypePtr type)
605{
606 xmlSchemaTypePtr next;
607
608 while (type != NULL) {
609 next = type->redef;
610 xmlSchemaFreeType(type);
611 type = next;
612 }
613}
614
615/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000616 * xmlSchemaFree:
617 * @schema: a schema structure
618 *
619 * Deallocate a Schema structure.
620 */
621void
622xmlSchemaFree(xmlSchemaPtr schema)
623{
624 if (schema == NULL)
625 return;
626
Daniel Veillard4255d502002-04-16 15:50:10 +0000627 if (schema->notaDecl != NULL)
628 xmlHashFree(schema->notaDecl,
629 (xmlHashDeallocator) xmlSchemaFreeNotation);
630 if (schema->attrDecl != NULL)
631 xmlHashFree(schema->attrDecl,
632 (xmlHashDeallocator) xmlSchemaFreeAttribute);
633 if (schema->attrgrpDecl != NULL)
634 xmlHashFree(schema->attrgrpDecl,
635 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup);
636 if (schema->elemDecl != NULL)
637 xmlHashFree(schema->elemDecl,
638 (xmlHashDeallocator) xmlSchemaFreeElement);
639 if (schema->typeDecl != NULL)
640 xmlHashFree(schema->typeDecl,
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000641 (xmlHashDeallocator) xmlSchemaFreeTypeList);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000642 if (schema->groupDecl != NULL)
643 xmlHashFree(schema->groupDecl,
644 (xmlHashDeallocator) xmlSchemaFreeType);
Daniel Veillard1d913862003-11-21 00:28:39 +0000645 if (schema->schemasImports != NULL)
646 xmlHashFree(schema->schemasImports,
647 (xmlHashDeallocator) xmlSchemaFreeImport);
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000648 if (schema->includes != NULL) {
649 xmlSchemaFreeIncludeList((xmlSchemaIncludePtr) schema->includes);
650 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000651 if (schema->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000652 xmlSchemaFreeAnnot(schema->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000653 if (schema->doc != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000654 xmlFreeDoc(schema->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000655 xmlDictFree(schema->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +0000656
657 xmlFree(schema);
658}
659
660/************************************************************************
661 * *
Daniel Veillard4255d502002-04-16 15:50:10 +0000662 * Debug functions *
663 * *
664 ************************************************************************/
665
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000666#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000667
Daniel Veillard4255d502002-04-16 15:50:10 +0000668/**
669 * xmlSchemaElementDump:
670 * @elem: an element
671 * @output: the file output
672 *
673 * Dump the element
674 */
675static void
676xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000677 const xmlChar * name ATTRIBUTE_UNUSED,
678 const xmlChar * context ATTRIBUTE_UNUSED,
679 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +0000680{
681 if (elem == NULL)
682 return;
683
684 fprintf(output, "Element ");
685 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000686 fprintf(output, "toplevel ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000687 fprintf(output, ": %s ", elem->name);
688 if (namespace != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000689 fprintf(output, "namespace '%s' ", namespace);
690
Daniel Veillard4255d502002-04-16 15:50:10 +0000691 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000692 fprintf(output, "nillable ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000693 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000694 fprintf(output, "global ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000695 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000696 fprintf(output, "default ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000697 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000698 fprintf(output, "fixed ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000699 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000700 fprintf(output, "abstract ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000701 if (elem->flags & XML_SCHEMAS_ELEM_REF)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000702 fprintf(output, "ref '%s' ", elem->ref);
Daniel Veillard4255d502002-04-16 15:50:10 +0000703 if (elem->id != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000704 fprintf(output, "id '%s' ", elem->id);
Daniel Veillard4255d502002-04-16 15:50:10 +0000705 fprintf(output, "\n");
706 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000707 fprintf(output, " ");
708 if (elem->minOccurs != 1)
709 fprintf(output, "min: %d ", elem->minOccurs);
710 if (elem->maxOccurs >= UNBOUNDED)
711 fprintf(output, "max: unbounded\n");
712 else if (elem->maxOccurs != 1)
713 fprintf(output, "max: %d\n", elem->maxOccurs);
714 else
715 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000716 }
717 if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000718 fprintf(output, " type: %s", elem->namedType);
719 if (elem->namedTypeNs != NULL)
720 fprintf(output, " ns %s\n", elem->namedTypeNs);
721 else
722 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000723 }
724 if (elem->substGroup != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000725 fprintf(output, " substitutionGroup: %s", elem->substGroup);
726 if (elem->substGroupNs != NULL)
727 fprintf(output, " ns %s\n", elem->substGroupNs);
728 else
729 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000730 }
731 if (elem->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000732 fprintf(output, " default: %s", elem->value);
Daniel Veillard4255d502002-04-16 15:50:10 +0000733}
734
735/**
736 * xmlSchemaAnnotDump:
737 * @output: the file output
738 * @annot: a annotation
739 *
740 * Dump the annotation
741 */
742static void
743xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
744{
745 xmlChar *content;
746
747 if (annot == NULL)
748 return;
749
750 content = xmlNodeGetContent(annot->content);
751 if (content != NULL) {
752 fprintf(output, " Annot: %s\n", content);
753 xmlFree(content);
754 } else
755 fprintf(output, " Annot: empty\n");
756}
757
758/**
759 * xmlSchemaTypeDump:
760 * @output: the file output
761 * @type: a type structure
762 *
763 * Dump a SchemaType structure
764 */
765static void
766xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
767{
768 if (type == NULL) {
769 fprintf(output, "Type: NULL\n");
770 return;
771 }
772 fprintf(output, "Type: ");
773 if (type->name != NULL)
774 fprintf(output, "%s, ", type->name);
775 else
776 fprintf(output, "no name");
777 switch (type->type) {
778 case XML_SCHEMA_TYPE_BASIC:
779 fprintf(output, "basic ");
780 break;
781 case XML_SCHEMA_TYPE_SIMPLE:
782 fprintf(output, "simple ");
783 break;
784 case XML_SCHEMA_TYPE_COMPLEX:
785 fprintf(output, "complex ");
786 break;
787 case XML_SCHEMA_TYPE_SEQUENCE:
788 fprintf(output, "sequence ");
789 break;
790 case XML_SCHEMA_TYPE_CHOICE:
791 fprintf(output, "choice ");
792 break;
793 case XML_SCHEMA_TYPE_ALL:
794 fprintf(output, "all ");
795 break;
796 case XML_SCHEMA_TYPE_UR:
797 fprintf(output, "ur ");
798 break;
799 case XML_SCHEMA_TYPE_RESTRICTION:
800 fprintf(output, "restriction ");
801 break;
802 case XML_SCHEMA_TYPE_EXTENSION:
803 fprintf(output, "extension ");
804 break;
805 default:
806 fprintf(output, "unknowntype%d ", type->type);
807 break;
808 }
809 if (type->base != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000810 fprintf(output, "base %s, ", type->base);
Daniel Veillard4255d502002-04-16 15:50:10 +0000811 }
812 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000813 case XML_SCHEMA_CONTENT_UNKNOWN:
814 fprintf(output, "unknown ");
815 break;
816 case XML_SCHEMA_CONTENT_EMPTY:
817 fprintf(output, "empty ");
818 break;
819 case XML_SCHEMA_CONTENT_ELEMENTS:
820 fprintf(output, "element ");
821 break;
822 case XML_SCHEMA_CONTENT_MIXED:
823 fprintf(output, "mixed ");
824 break;
825 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
826 fprintf(output, "mixed_or_elems ");
827 break;
828 case XML_SCHEMA_CONTENT_BASIC:
829 fprintf(output, "basic ");
830 break;
831 case XML_SCHEMA_CONTENT_SIMPLE:
832 fprintf(output, "simple ");
833 break;
834 case XML_SCHEMA_CONTENT_ANY:
835 fprintf(output, "any ");
836 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000837 }
838 fprintf(output, "\n");
839 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000840 fprintf(output, " ");
841 if (type->minOccurs != 1)
842 fprintf(output, "min: %d ", type->minOccurs);
843 if (type->maxOccurs >= UNBOUNDED)
844 fprintf(output, "max: unbounded\n");
845 else if (type->maxOccurs != 1)
846 fprintf(output, "max: %d\n", type->maxOccurs);
847 else
848 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000849 }
850 if (type->annot != NULL)
851 xmlSchemaAnnotDump(output, type->annot);
852 if (type->subtypes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000853 xmlSchemaTypePtr sub = type->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +0000854
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000855 fprintf(output, " subtypes: ");
856 while (sub != NULL) {
857 fprintf(output, "%s ", sub->name);
858 sub = sub->next;
859 }
860 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000861 }
862
863}
864
865/**
866 * xmlSchemaDump:
867 * @output: the file output
868 * @schema: a schema structure
869 *
870 * Dump a Schema structure.
871 */
872void
873xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
874{
875 if (schema == NULL) {
876 fprintf(output, "Schemas: NULL\n");
877 return;
878 }
879 fprintf(output, "Schemas: ");
880 if (schema->name != NULL)
881 fprintf(output, "%s, ", schema->name);
882 else
883 fprintf(output, "no name, ");
884 if (schema->targetNamespace != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000885 fprintf(output, "%s", (const char *) schema->targetNamespace);
Daniel Veillard4255d502002-04-16 15:50:10 +0000886 else
887 fprintf(output, "no target namespace");
888 fprintf(output, "\n");
889 if (schema->annot != NULL)
890 xmlSchemaAnnotDump(output, schema->annot);
891
892 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
893 output);
894 xmlHashScanFull(schema->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000895 (xmlHashScannerFull) xmlSchemaElementDump, output);
Daniel Veillard4255d502002-04-16 15:50:10 +0000896}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000897#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard4255d502002-04-16 15:50:10 +0000898
899/************************************************************************
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000900 * *
901 * Utilities *
902 * *
903 ************************************************************************/
904/**
905 * numberedString:
906 * @prefix: the string prefix
907 * @number: the number
908 *
909 * Build a new numbered string
910 *
911 * Returns the new string
912 */
913
914/**
915 * xmlSchemaGetProp:
916 * @ctxt: the parser context
917 * @node: the node
918 * @name: the property name
919 *
920 * Read a attribute value and internalize the string
921 *
922 * Returns the string or NULL if not present.
923 */
924static const xmlChar *
925xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
926 const char *name)
927{
928 xmlChar *val;
929 const xmlChar *ret;
930
931 val = xmlGetProp(node, BAD_CAST name);
932 if (val == NULL)
933 return(NULL);
934 ret = xmlDictLookup(ctxt->dict, val, -1);
935 xmlFree(val);
936 return(ret);
937}
938
939/**
940 * xmlSchemaGetNamespace:
941 * @ctxt: the parser context
942 * @schema: the schemas containing the declaration
943 * @node: the node
944 * @qname: the QName to analyze
945 *
946 * Find the namespace name for the given declaration.
947 *
948 * Returns the local name for that declaration, as well as the namespace name
949 */
950static const xmlChar *
951xmlSchemaGetNamespace(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
952 xmlNodePtr node, const xmlChar *qname,
953 const xmlChar **namespace) {
954 int len;
955 const xmlChar *name, *prefix, *def = NULL;
956 xmlNsPtr ns;
957
958 *namespace = NULL;
959
960 if (xmlStrEqual(node->name, BAD_CAST "element") ||
961 xmlStrEqual(node->name, BAD_CAST "attribute") ||
962 xmlStrEqual(node->name, BAD_CAST "simpleType") ||
963 xmlStrEqual(node->name, BAD_CAST "complexType")) {
964 def = xmlSchemaGetProp(ctxt, node, "targetNamespace");
965 }
966
967 qname = xmlDictLookup(ctxt->dict, qname, -1); /* intern the string */
968 name = xmlSplitQName3(qname, &len);
969 if (name == NULL) {
970 if (def == NULL) {
971 if (xmlStrEqual(node->name, BAD_CAST "element")) {
972 if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
973 *namespace = schema->targetNamespace;
974 } else if (xmlStrEqual(node->name, BAD_CAST "attribute")) {
975 if (schema->flags & XML_SCHEMAS_QUALIF_ATTR)
976 *namespace = schema->targetNamespace;
977 } else if ((xmlStrEqual(node->name, BAD_CAST "simpleType")) ||
978 (xmlStrEqual(node->name, BAD_CAST "complexType"))) {
979 *namespace = schema->targetNamespace;
980 }
981 } else {
982 *namespace = def;
983 }
984 return(qname);
985 }
986 name = xmlDictLookup(ctxt->dict, name, -1);
987 prefix = xmlDictLookup(ctxt->dict, qname, len);
988 if (def != NULL) {
989 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_DEF_AND_PREFIX,
990 "%s: presence of both prefix %s and targetNamespace\n",
991 node->name, prefix);
992 }
993 ns = xmlSearchNs(node->doc, node, prefix);
994 if (ns == NULL) {
995 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
996 "%s: the QName prefix %s is undefined\n",
997 node->name, prefix);
998 return(name);
999 }
1000 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
1001 return(name);
1002}
1003
1004/************************************************************************
Daniel Veillard4255d502002-04-16 15:50:10 +00001005 * *
1006 * Parsing functions *
1007 * *
1008 ************************************************************************/
1009
1010/**
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001011 * xmlSchemaGetElem:
1012 * @schema: the schemas context
1013 * @name: the element name
1014 * @ns: the element namespace
Daniel Veillardf2a12832003-11-24 13:04:35 +00001015 * @level: how deep is the request
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001016 *
1017 * Lookup a an element in the schemas or the accessible schemas
1018 *
1019 * Returns the element definition or NULL if not found.
1020 */
1021static xmlSchemaElementPtr
1022xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardf2a12832003-11-24 13:04:35 +00001023 const xmlChar * namespace, int level)
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001024{
1025 xmlSchemaElementPtr ret;
Daniel Veillardf2a12832003-11-24 13:04:35 +00001026 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001027
1028 if ((name == NULL) || (schema == NULL))
1029 return (NULL);
1030
1031 if (namespace == NULL) {
1032 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001033 if ((ret != NULL) &&
1034 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001035 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001036 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001037 } else if ((schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0) {
1038 if (xmlStrEqual(namespace, schema->targetNamespace))
1039 ret = xmlHashLookup2(schema->elemDecl, name, NULL);
1040 else
1041 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001042 if ((ret != NULL) &&
1043 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001044 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001045 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001046 } else {
1047 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001048 if ((ret != NULL) &&
1049 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001050 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001051 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001052 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00001053 if (level > 0)
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001054 import = xmlHashLookup(schema->schemasImports, namespace);
1055 if (import != NULL)
Daniel Veillardf2a12832003-11-24 13:04:35 +00001056 ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001057#ifdef DEBUG
1058 if (ret == NULL) {
1059 if (namespace == NULL)
1060 fprintf(stderr, "Unable to lookup type %s", name);
1061 else
1062 fprintf(stderr, "Unable to lookup type %s:%s", name,
1063 namespace);
1064 }
1065#endif
1066 return (ret);
1067}
1068
1069/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001070 * xmlSchemaGetType:
1071 * @schema: the schemas context
1072 * @name: the type name
1073 * @ns: the type namespace
1074 *
1075 * Lookup a type in the schemas or the predefined types
1076 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001077 * Returns the group definition or NULL if not found.
Daniel Veillard4255d502002-04-16 15:50:10 +00001078 */
1079static xmlSchemaTypePtr
1080xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001081 const xmlChar * namespace)
1082{
Daniel Veillard4255d502002-04-16 15:50:10 +00001083 xmlSchemaTypePtr ret;
Daniel Veillard1d913862003-11-21 00:28:39 +00001084 xmlSchemaImportPtr import;
Daniel Veillard4255d502002-04-16 15:50:10 +00001085
1086 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001087 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001088 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001089 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
1090 if (ret != NULL)
1091 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001092 }
1093 ret = xmlSchemaGetPredefinedType(name, namespace);
Daniel Veillard1d913862003-11-21 00:28:39 +00001094 if (ret != NULL)
1095 return (ret);
1096 import = xmlHashLookup(schema->schemasImports, namespace);
1097 if (import != NULL)
1098 ret = xmlSchemaGetType(import->schema, name, namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001099#ifdef DEBUG
1100 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001101 if (namespace == NULL)
1102 fprintf(stderr, "Unable to lookup type %s", name);
1103 else
1104 fprintf(stderr, "Unable to lookup type %s:%s", name,
1105 namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001106 }
1107#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001108 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001109}
1110
1111/************************************************************************
1112 * *
1113 * Parsing functions *
1114 * *
1115 ************************************************************************/
1116
1117#define IS_BLANK_NODE(n) \
1118 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
1119
1120/**
1121 * xmlSchemaIsBlank:
1122 * @str: a string
1123 *
1124 * Check if a string is ignorable
1125 *
1126 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
1127 */
1128static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001129xmlSchemaIsBlank(xmlChar * str)
1130{
Daniel Veillard4255d502002-04-16 15:50:10 +00001131 if (str == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001132 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001133 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001134 if (!(IS_BLANK_CH(*str)))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001135 return (0);
1136 str++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001137 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001138 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001139}
1140
1141/**
1142 * xmlSchemaAddNotation:
1143 * @ctxt: a schema validation context
1144 * @schema: the schema being built
1145 * @name: the item name
1146 *
1147 * Add an XML schema Attrribute declaration
1148 * *WARNING* this interface is highly subject to change
1149 *
1150 * Returns the new struture or NULL in case of error
1151 */
1152static xmlSchemaNotationPtr
1153xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001154 const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001155{
1156 xmlSchemaNotationPtr ret = NULL;
1157 int val;
1158
1159 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1160 return (NULL);
1161
1162 if (schema->notaDecl == NULL)
1163 schema->notaDecl = xmlHashCreate(10);
1164 if (schema->notaDecl == NULL)
1165 return (NULL);
1166
1167 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
1168 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001169 xmlSchemaPErrMemory(ctxt, "add annotation", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001170 return (NULL);
1171 }
1172 memset(ret, 0, sizeof(xmlSchemaNotation));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001173 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001174 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
1175 ret);
1176 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001177 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1178 XML_SCHEMAP_REDEFINED_NOTATION,
1179 "Notation %s already defined\n",
1180 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001181 xmlFree(ret);
1182 return (NULL);
1183 }
1184 return (ret);
1185}
1186
1187
1188/**
1189 * xmlSchemaAddAttribute:
1190 * @ctxt: a schema validation context
1191 * @schema: the schema being built
1192 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001193 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001194 *
1195 * Add an XML schema Attrribute declaration
1196 * *WARNING* this interface is highly subject to change
1197 *
1198 * Returns the new struture or NULL in case of error
1199 */
1200static xmlSchemaAttributePtr
1201xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001202 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001203{
1204 xmlSchemaAttributePtr ret = NULL;
1205 int val;
1206
1207 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1208 return (NULL);
1209
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001210#ifdef DEBUG
1211 fprintf(stderr, "Adding attribute %s\n", name);
1212 if (namespace != NULL)
1213 fprintf(stderr, " target namespace %s\n", namespace);
1214#endif
1215
Daniel Veillard4255d502002-04-16 15:50:10 +00001216 if (schema->attrDecl == NULL)
1217 schema->attrDecl = xmlHashCreate(10);
1218 if (schema->attrDecl == NULL)
1219 return (NULL);
1220
1221 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
1222 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001223 xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001224 return (NULL);
1225 }
1226 memset(ret, 0, sizeof(xmlSchemaAttribute));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001227 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1228 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001229 val = xmlHashAddEntry3(schema->attrDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001230 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001231 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001232 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1233 XML_SCHEMAP_REDEFINED_ATTR,
1234 "Attribute %s already defined\n",
1235 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001236 xmlFree(ret);
1237 return (NULL);
1238 }
1239 return (ret);
1240}
1241
1242/**
1243 * xmlSchemaAddAttributeGroup:
1244 * @ctxt: a schema validation context
1245 * @schema: the schema being built
1246 * @name: the item name
1247 *
1248 * Add an XML schema Attrribute Group declaration
1249 *
1250 * Returns the new struture or NULL in case of error
1251 */
1252static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001253xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1254 xmlSchemaPtr schema, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001255{
1256 xmlSchemaAttributeGroupPtr ret = NULL;
1257 int val;
1258
1259 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1260 return (NULL);
1261
1262 if (schema->attrgrpDecl == NULL)
1263 schema->attrgrpDecl = xmlHashCreate(10);
1264 if (schema->attrgrpDecl == NULL)
1265 return (NULL);
1266
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001267 ret =
1268 (xmlSchemaAttributeGroupPtr)
1269 xmlMalloc(sizeof(xmlSchemaAttributeGroup));
Daniel Veillard4255d502002-04-16 15:50:10 +00001270 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001271 xmlSchemaPErrMemory(ctxt, "allocating attribute group", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001272 return (NULL);
1273 }
1274 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001275 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001276 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001277 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001278 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001279 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1280 XML_SCHEMAP_REDEFINED_ATTRGROUP,
1281 "Attribute group %s already defined\n",
1282 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001283 xmlFree(ret);
1284 return (NULL);
1285 }
1286 return (ret);
1287}
1288
1289/**
1290 * xmlSchemaAddElement:
1291 * @ctxt: a schema validation context
1292 * @schema: the schema being built
1293 * @name: the type name
1294 * @namespace: the type namespace
1295 *
1296 * Add an XML schema Element declaration
1297 * *WARNING* this interface is highly subject to change
1298 *
1299 * Returns the new struture or NULL in case of error
1300 */
1301static xmlSchemaElementPtr
1302xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1303 const xmlChar * name, const xmlChar * namespace)
1304{
1305 xmlSchemaElementPtr ret = NULL;
1306 int val;
1307
1308 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1309 return (NULL);
1310
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001311#ifdef DEBUG
1312 fprintf(stderr, "Adding element %s\n", name);
1313 if (namespace != NULL)
1314 fprintf(stderr, " target namespace %s\n", namespace);
1315#endif
1316
Daniel Veillard4255d502002-04-16 15:50:10 +00001317 if (schema->elemDecl == NULL)
1318 schema->elemDecl = xmlHashCreate(10);
1319 if (schema->elemDecl == NULL)
1320 return (NULL);
1321
1322 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
1323 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001324 xmlSchemaPErrMemory(ctxt, "allocating element", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001325 return (NULL);
1326 }
1327 memset(ret, 0, sizeof(xmlSchemaElement));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001328 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1329 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001330 val = xmlHashAddEntry3(schema->elemDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001331 namespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001332 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001333 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00001334
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001335 snprintf(buf, 99, "privatieelem %d", ctxt->counter++ + 1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001336 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
1337 namespace, ret);
1338 if (val != 0) {
1339 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1340 XML_SCHEMAP_REDEFINED_ELEMENT,
1341 "Element %s already defined\n",
1342 name, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001343 xmlFree(ret);
1344 return (NULL);
1345 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001346 }
1347 return (ret);
1348}
1349
1350/**
1351 * xmlSchemaAddType:
1352 * @ctxt: a schema validation context
1353 * @schema: the schema being built
1354 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001355 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001356 *
1357 * Add an XML schema Simple Type definition
1358 * *WARNING* this interface is highly subject to change
1359 *
1360 * Returns the new struture or NULL in case of error
1361 */
1362static xmlSchemaTypePtr
1363xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001364 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001365{
1366 xmlSchemaTypePtr ret = NULL;
1367 int val;
1368
1369 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1370 return (NULL);
1371
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001372#ifdef DEBUG
1373 fprintf(stderr, "Adding type %s\n", name);
1374 if (namespace != NULL)
1375 fprintf(stderr, " target namespace %s\n", namespace);
1376#endif
1377
Daniel Veillard4255d502002-04-16 15:50:10 +00001378 if (schema->typeDecl == NULL)
1379 schema->typeDecl = xmlHashCreate(10);
1380 if (schema->typeDecl == NULL)
1381 return (NULL);
1382
1383 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1384 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001385 xmlSchemaPErrMemory(ctxt, "allocating type", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001386 return (NULL);
1387 }
1388 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001389 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00001390 ret->redef = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001391 val = xmlHashAddEntry2(schema->typeDecl, name, namespace, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001392 if (val != 0) {
Daniel Veillardb0f397e2003-12-23 23:30:53 +00001393 if (ctxt->includes == 0) {
1394 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1395 XML_SCHEMAP_REDEFINED_TYPE,
1396 "Type %s already defined\n",
1397 name, NULL);
1398 xmlFree(ret);
1399 return (NULL);
1400 } else {
1401 xmlSchemaTypePtr prev;
1402
1403 prev = xmlHashLookup2(schema->typeDecl, name, namespace);
1404 if (prev == NULL) {
1405 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1406 XML_ERR_INTERNAL_ERROR,
1407 "Internal error on type %s definition\n",
1408 name, NULL);
1409 xmlFree(ret);
1410 return (NULL);
1411 }
1412 ret->redef = prev->redef;
1413 prev->redef = ret;
1414 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001415 }
1416 ret->minOccurs = 1;
1417 ret->maxOccurs = 1;
1418
1419 return (ret);
1420}
1421
1422/**
1423 * xmlSchemaAddGroup:
1424 * @ctxt: a schema validation context
1425 * @schema: the schema being built
1426 * @name: the group name
1427 *
1428 * Add an XML schema Group definition
1429 *
1430 * Returns the new struture or NULL in case of error
1431 */
1432static xmlSchemaTypePtr
1433xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001434 const xmlChar * name)
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001435{
1436 xmlSchemaTypePtr ret = NULL;
1437 int val;
1438
1439 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1440 return (NULL);
1441
1442 if (schema->groupDecl == NULL)
1443 schema->groupDecl = xmlHashCreate(10);
1444 if (schema->groupDecl == NULL)
1445 return (NULL);
1446
1447 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1448 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001449 xmlSchemaPErrMemory(ctxt, "adding group", NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001450 return (NULL);
1451 }
1452 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001453 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001454 val =
1455 xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace,
1456 ret);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001457 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001458 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1459 XML_SCHEMAP_REDEFINED_GROUP,
1460 "Group %s already defined\n",
1461 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001462 xmlFree(ret);
1463 return (NULL);
1464 }
1465 ret->minOccurs = 1;
1466 ret->maxOccurs = 1;
1467
1468 return (ret);
1469}
1470
1471/************************************************************************
1472 * *
1473 * Utilities for parsing *
1474 * *
1475 ************************************************************************/
1476
1477/**
1478 * xmlGetQNameProp:
1479 * @ctxt: a schema validation context
1480 * @node: a subtree containing XML Schema informations
1481 * @name: the attribute name
1482 * @namespace: the result namespace if any
1483 *
1484 * Extract a QName Attribute value
1485 *
1486 * Returns the NCName or NULL if not found, and also update @namespace
1487 * with the namespace URI
1488 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001489static const xmlChar *
Daniel Veillard4255d502002-04-16 15:50:10 +00001490xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001491 const char *name, const xmlChar ** namespace)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001492{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001493 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001494 xmlNsPtr ns;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001495 const xmlChar *ret, *prefix;
1496 int len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001497
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001498 *namespace = NULL;
1499 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001500 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001501 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001502
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001503 ret = xmlSplitQName3(val, &len);
1504 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001505 return (val);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001506 }
1507 ret = xmlDictLookup(ctxt->dict, ret, -1);
1508 prefix = xmlDictLookup(ctxt->dict, val, len);
Daniel Veillard4255d502002-04-16 15:50:10 +00001509
1510 ns = xmlSearchNs(node->doc, node, prefix);
1511 if (ns == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001512 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
1513 "Attribute %s: the QName prefix %s is undefined\n",
1514 (const xmlChar *) name, prefix);
Daniel Veillard4255d502002-04-16 15:50:10 +00001515 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001516 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001517 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001518 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001519}
1520
1521/**
1522 * xmlGetMaxOccurs:
1523 * @ctxt: a schema validation context
1524 * @node: a subtree containing XML Schema informations
1525 *
1526 * Get the maxOccurs property
1527 *
1528 * Returns the default if not found, or the value
1529 */
1530static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001531xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1532{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001533 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001534 int ret = 0;
1535
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001536 val = xmlSchemaGetProp(ctxt, node, "maxOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001537 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001538 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001539
1540 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001541 return (UNBOUNDED); /* encoding it with -1 might be another option */
Daniel Veillard4255d502002-04-16 15:50:10 +00001542 }
1543
1544 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001545 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001546 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001547 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001548 ret = ret * 10 + (*cur - '0');
1549 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001550 }
William M. Brack76e95df2003-10-18 16:20:14 +00001551 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001552 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001553 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001554 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS,
1555 "invalid value for maxOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001556 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001557 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001558 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001559}
1560
1561/**
1562 * xmlGetMinOccurs:
1563 * @ctxt: a schema validation context
1564 * @node: a subtree containing XML Schema informations
1565 *
1566 * Get the minOccurs property
1567 *
1568 * Returns the default if not found, or the value
1569 */
1570static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001571xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1572{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001573 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001574 int ret = 0;
1575
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001576 val = xmlSchemaGetProp(ctxt, node, "minOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001577 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001578 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001579
1580 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001581 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001582 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001583 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001584 ret = ret * 10 + (*cur - '0');
1585 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001586 }
William M. Brack76e95df2003-10-18 16:20:14 +00001587 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001588 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001589 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001590 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS,
1591 "invalid value for minOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001592 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001593 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001594 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001595}
1596
1597/**
1598 * xmlGetBooleanProp:
1599 * @ctxt: a schema validation context
1600 * @node: a subtree containing XML Schema informations
1601 * @name: the attribute name
1602 * @def: the default value
1603 *
1604 * Get is a bolean property is set
1605 *
1606 * Returns the default if not found, 0 if found to be false,
1607 * 1 if found to be true
1608 */
1609static int
1610xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001611 const char *name, int def)
1612{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001613 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001614
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001615 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001616 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001617 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001618
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001619 if (xmlStrEqual(val, BAD_CAST "true"))
1620 def = 1;
1621 else if (xmlStrEqual(val, BAD_CAST "false"))
1622 def = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001623 else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001624 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_BOOLEAN,
1625 "Attribute %s: the value %s is not boolean\n",
1626 (const xmlChar *) name, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001627 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001628 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001629}
1630
1631/************************************************************************
1632 * *
1633 * Shema extraction from an Infoset *
1634 * *
1635 ************************************************************************/
1636static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1637 ctxt, xmlSchemaPtr schema,
1638 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001639static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr
1640 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001641 xmlSchemaPtr schema,
1642 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001643static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr
1644 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001645 xmlSchemaPtr schema,
1646 xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001647 int simple);
Daniel Veillard4255d502002-04-16 15:50:10 +00001648static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1649 xmlSchemaPtr schema,
1650 xmlNodePtr node);
1651static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1652 xmlSchemaPtr schema,
1653 xmlNodePtr node);
1654static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1655 ctxt,
1656 xmlSchemaPtr schema,
1657 xmlNodePtr node);
1658static xmlSchemaAttributeGroupPtr
1659xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1660 xmlSchemaPtr schema, xmlNodePtr node);
1661static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1662 xmlSchemaPtr schema,
1663 xmlNodePtr node);
1664static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1665 xmlSchemaPtr schema,
1666 xmlNodePtr node);
1667static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001668xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1669 xmlSchemaPtr schema, xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00001670
1671/**
1672 * xmlSchemaParseAttrDecls:
1673 * @ctxt: a schema validation context
1674 * @schema: the schema being built
1675 * @node: a subtree containing XML Schema informations
1676 * @type: the hosting type
1677 *
1678 * parse a XML schema attrDecls declaration corresponding to
1679 * <!ENTITY % attrDecls
1680 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1681 */
1682static xmlNodePtr
1683xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1684 xmlNodePtr child, xmlSchemaTypePtr type)
1685{
1686 xmlSchemaAttributePtr lastattr, attr;
1687
1688 lastattr = NULL;
1689 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001690 (IS_SCHEMA(child, "attributeGroup"))) {
1691 attr = NULL;
1692 if (IS_SCHEMA(child, "attribute")) {
1693 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1694 } else if (IS_SCHEMA(child, "attributeGroup")) {
1695 attr = (xmlSchemaAttributePtr)
1696 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1697 }
1698 if (attr != NULL) {
1699 if (lastattr == NULL) {
1700 type->attributes = attr;
1701 lastattr = attr;
1702 } else {
1703 lastattr->next = attr;
1704 lastattr = attr;
1705 }
1706 }
1707 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001708 }
1709 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001710 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1711 if (attr != NULL) {
1712 if (lastattr == NULL) {
1713 type->attributes = attr;
1714 lastattr = attr;
1715 } else {
1716 lastattr->next = attr;
1717 lastattr = attr;
1718 }
1719 }
1720 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001721 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001722 return (child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001723}
1724
1725/**
1726 * xmlSchemaParseAnnotation:
1727 * @ctxt: a schema validation context
1728 * @schema: the schema being built
1729 * @node: a subtree containing XML Schema informations
1730 *
1731 * parse a XML schema Attrribute declaration
1732 * *WARNING* this interface is highly subject to change
1733 *
1734 * Returns -1 in case of error, 0 if the declaration is inproper and
1735 * 1 in case of success.
1736 */
1737static xmlSchemaAnnotPtr
1738xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1739 xmlNodePtr node)
1740{
1741 xmlSchemaAnnotPtr ret;
1742
1743 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1744 return (NULL);
1745 ret = xmlSchemaNewAnnot(ctxt, node);
1746
1747 return (ret);
1748}
1749
1750/**
1751 * xmlSchemaParseFacet:
1752 * @ctxt: a schema validation context
1753 * @schema: the schema being built
1754 * @node: a subtree containing XML Schema informations
1755 *
1756 * parse a XML schema Facet declaration
1757 * *WARNING* this interface is highly subject to change
1758 *
1759 * Returns the new type structure or NULL in case of error
1760 */
1761static xmlSchemaFacetPtr
1762xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001763 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001764{
1765 xmlSchemaFacetPtr facet;
1766 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001767 const xmlChar *value;
Daniel Veillard4255d502002-04-16 15:50:10 +00001768
1769 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1770 return (NULL);
1771
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001772 facet = xmlSchemaNewFacet();
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001773 if (facet == NULL) {
1774 xmlSchemaPErrMemory(ctxt, "allocating facet", node);
1775 return (NULL);
1776 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001777 facet->node = node;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001778 value = xmlSchemaGetProp(ctxt, node, "value");
Daniel Veillard4255d502002-04-16 15:50:10 +00001779 if (value == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001780 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE,
1781 "Facet %s has no value\n", node->name, NULL);
1782 xmlSchemaFreeFacet(facet);
Daniel Veillard4255d502002-04-16 15:50:10 +00001783 return (NULL);
1784 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001785 if (IS_SCHEMA(node, "minInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001786 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001787 } else if (IS_SCHEMA(node, "minExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001788 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001789 } else if (IS_SCHEMA(node, "maxInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001790 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001791 } else if (IS_SCHEMA(node, "maxExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001792 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001793 } else if (IS_SCHEMA(node, "totalDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001794 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001795 } else if (IS_SCHEMA(node, "fractionDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001796 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001797 } else if (IS_SCHEMA(node, "pattern")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001798 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001799 } else if (IS_SCHEMA(node, "enumeration")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001800 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001801 } else if (IS_SCHEMA(node, "whiteSpace")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001802 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001803 } else if (IS_SCHEMA(node, "length")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001804 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001805 } else if (IS_SCHEMA(node, "maxLength")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001806 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1807 } else if (IS_SCHEMA(node, "minLength")) {
1808 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1809 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001810 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE,
1811 "Unknown facet type %s\n", node->name, NULL);
1812 xmlSchemaFreeFacet(facet);
1813 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001814 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001815 facet->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00001816 facet->value = value;
1817 child = node->children;
1818
1819 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001820 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1821 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001822 }
1823 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001824 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD,
1825 "Facet %s has unexpected child content\n",
1826 node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001827 }
1828 return (facet);
1829}
1830
1831/**
1832 * xmlSchemaParseAny:
1833 * @ctxt: a schema validation context
1834 * @schema: the schema being built
1835 * @node: a subtree containing XML Schema informations
1836 *
1837 * parse a XML schema Any declaration
1838 * *WARNING* this interface is highly subject to change
1839 *
1840 * Returns the new type structure or NULL in case of error
1841 */
1842static xmlSchemaTypePtr
1843xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1844 xmlNodePtr node)
1845{
1846 xmlSchemaTypePtr type;
1847 xmlNodePtr child = NULL;
1848 xmlChar name[30];
1849
1850 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1851 return (NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001852 snprintf((char *) name, 30, "any %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001853 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001854 if (type == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001855 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001856 type->node = node;
1857 type->type = XML_SCHEMA_TYPE_ANY;
1858 child = node->children;
1859 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1860 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1861
1862 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001863 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1864 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001865 }
1866 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001867 xmlSchemaPErr2(ctxt, node, child,
1868 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
1869 "Sequence %s has unexpected content\n", type->name,
1870 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001871 }
1872
1873 return (type);
1874}
1875
1876/**
1877 * xmlSchemaParseNotation:
1878 * @ctxt: a schema validation context
1879 * @schema: the schema being built
1880 * @node: a subtree containing XML Schema informations
1881 *
1882 * parse a XML schema Notation declaration
1883 *
1884 * Returns the new structure or NULL in case of error
1885 */
1886static xmlSchemaNotationPtr
1887xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001888 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001889{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001890 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00001891 xmlSchemaNotationPtr ret;
1892 xmlNodePtr child = NULL;
1893
1894 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1895 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001896 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00001897 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001898 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME,
1899 "Notation has no name\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001900 return (NULL);
1901 }
1902 ret = xmlSchemaAddNotation(ctxt, schema, name);
1903 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001904 return (NULL);
1905 }
1906 child = node->children;
1907 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001908 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1909 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001910 }
1911 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001912 xmlSchemaPErr2(ctxt, node, child,
1913 XML_SCHEMAP_UNKNOWN_NOTATION_CHILD,
1914 "notation %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001915 }
1916
1917 return (ret);
1918}
1919
1920/**
1921 * xmlSchemaParseAnyAttribute:
1922 * @ctxt: a schema validation context
1923 * @schema: the schema being built
1924 * @node: a subtree containing XML Schema informations
1925 *
1926 * parse a XML schema AnyAttrribute declaration
1927 * *WARNING* this interface is highly subject to change
1928 *
1929 * Returns an attribute def structure or NULL
1930 */
1931static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001932xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1933 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001934{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001935 const xmlChar *processContents;
Daniel Veillard4255d502002-04-16 15:50:10 +00001936 xmlSchemaAttributePtr ret;
1937 xmlNodePtr child = NULL;
1938 char name[100];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001939 const xmlChar *local, *ns;
1940
Daniel Veillard4255d502002-04-16 15:50:10 +00001941
1942 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1943 return (NULL);
1944
1945 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001946 local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns);
1947 ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00001948 if (ret == NULL) {
1949 return (NULL);
1950 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001951 ret->id = xmlSchemaGetProp(ctxt, node, "id");
1952 processContents = xmlSchemaGetProp(ctxt, node, "processContents");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001953 if ((processContents == NULL)
1954 || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) {
1955 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1956 } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) {
1957 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1958 } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) {
1959 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
Daniel Veillard4255d502002-04-16 15:50:10 +00001960 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001961 xmlSchemaPErr2(ctxt, node, child,
1962 XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD,
1963 "anyAttribute has unexpected content for processContents: %s\n",
1964 processContents, NULL);
1965 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
Daniel Veillard4255d502002-04-16 15:50:10 +00001966 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001967
1968 child = node->children;
1969 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001970 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1971 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001972 }
1973 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001974 xmlSchemaPErr2(ctxt, node, child,
1975 XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD,
1976 "anyAttribute %s has unexpected content\n",
1977 (const xmlChar *) name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001978 }
1979
1980 return (ret);
1981}
1982
1983
1984/**
1985 * xmlSchemaParseAttribute:
1986 * @ctxt: a schema validation context
1987 * @schema: the schema being built
1988 * @node: a subtree containing XML Schema informations
1989 *
1990 * parse a XML schema Attrribute declaration
1991 * *WARNING* this interface is highly subject to change
1992 *
1993 * Returns -1 in case of error, 0 if the declaration is inproper and
1994 * 1 in case of success.
1995 */
1996static xmlSchemaAttributePtr
1997xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1998 xmlNodePtr node)
1999{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002000 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002001 xmlSchemaAttributePtr ret;
2002 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002003 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002004
2005 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2006 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002007 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002008 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002009
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002010 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2011 if (ref == NULL) {
2012 xmlSchemaPErr2(ctxt, node, child,
2013 XML_SCHEMAP_ATTR_NONAME_NOREF,
2014 "Attribute has no name nor ref\n", NULL, NULL);
2015 return (NULL);
2016 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002017 if (refNs == NULL)
2018 refNs = schema->targetNamespace;
2019 snprintf(buf, 99, "anonattr %d", ctxt->counter++ + 1);
2020 name = (const xmlChar *) buf;
2021 ret = xmlSchemaAddAttribute(ctxt, schema, name, NULL);
2022 } else {
2023 const xmlChar *local, *ns;
2024
2025 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2026 ret = xmlSchemaAddAttribute(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002027 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002028 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002029 return (NULL);
2030 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002031 ret->ref = ref;
2032 ret->refNs = refNs;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002033 if ((ret->targetNamespace != NULL) &&
2034 ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) &&
2035 (xmlStrEqual(ret->targetNamespace, schema->targetNamespace)))
2036 ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT;
Daniel Veillard4255d502002-04-16 15:50:10 +00002037 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002038 if ((ret->typeName != NULL) && (ret->typeNs == NULL))
2039 ret->typeNs = schema->targetNamespace;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002040 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002041 child = node->children;
2042 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002043 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2044 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002045 }
2046 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002047 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
2048 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002049 }
2050 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002051 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD,
2052 "attribute %s has unexpected content\n", name,
2053 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002054 }
2055
2056 return (ret);
2057}
2058
2059/**
2060 * xmlSchemaParseAttributeGroup:
2061 * @ctxt: a schema validation context
2062 * @schema: the schema being built
2063 * @node: a subtree containing XML Schema informations
2064 *
2065 * parse a XML schema Attribute Group declaration
2066 * *WARNING* this interface is highly subject to change
2067 *
2068 * Returns the attribute group or NULL in case of error.
2069 */
2070static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002071xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
2072 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002073{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002074 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002075 xmlSchemaAttributeGroupPtr ret;
2076 xmlSchemaAttributePtr last = NULL, attr;
2077 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002078 const xmlChar *oldcontainer;
2079 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002080
2081 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2082 return (NULL);
2083 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002084 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002085 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002086
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002087 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2088 if (ref == NULL) {
2089 xmlSchemaPErr2(ctxt, node, child,
2090 XML_SCHEMAP_ATTRGRP_NONAME_NOREF,
2091 "AttributeGroup has no name nor ref\n", NULL,
2092 NULL);
2093 return (NULL);
2094 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002095 if (refNs == NULL)
2096 refNs = schema->targetNamespace;
2097 snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1);
2098 name = (const xmlChar *) buf;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002099 if (name == NULL) {
2100 xmlSchemaPErrMemory(ctxt, "creating attribute group", node);
2101 return (NULL);
2102 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002103 }
2104 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
2105 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002106 return (NULL);
2107 }
2108 ret->ref = ref;
2109 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00002110 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002111 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002112 child = node->children;
2113 ctxt->container = name;
2114 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002115 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2116 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002117 }
2118 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002119 (IS_SCHEMA(child, "attributeGroup"))) {
2120 attr = NULL;
2121 if (IS_SCHEMA(child, "attribute")) {
2122 attr = xmlSchemaParseAttribute(ctxt, schema, child);
2123 } else if (IS_SCHEMA(child, "attributeGroup")) {
2124 attr = (xmlSchemaAttributePtr)
2125 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2126 }
2127 if (attr != NULL) {
2128 if (last == NULL) {
2129 ret->attributes = attr;
2130 last = attr;
2131 } else {
2132 last->next = attr;
2133 last = attr;
2134 }
2135 }
2136 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002137 }
2138 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002139 TODO
2140 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002141 }
2142 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002143 xmlSchemaPErr2(ctxt, node, child,
2144 XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD,
2145 "attribute group %s has unexpected content\n", name,
2146 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002147 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002148 ctxt->container = oldcontainer;
2149 return (ret);
2150}
2151
2152/**
2153 * xmlSchemaParseElement:
2154 * @ctxt: a schema validation context
2155 * @schema: the schema being built
2156 * @node: a subtree containing XML Schema informations
2157 *
2158 * parse a XML schema Element declaration
2159 * *WARNING* this interface is highly subject to change
2160 *
2161 * Returns -1 in case of error, 0 if the declaration is inproper and
2162 * 1 in case of success.
2163 */
2164static xmlSchemaElementPtr
2165xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2166 xmlNodePtr node, int toplevel)
2167{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002168 const xmlChar *name, *fixed;
2169 const xmlChar *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002170 xmlSchemaElementPtr ret;
2171 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002172 const xmlChar *oldcontainer;
2173 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002174
2175 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2176 return (NULL);
2177 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002178 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002179 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002180
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002181 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2182 if (ref == NULL) {
2183 xmlSchemaPErr2(ctxt, node, child,
2184 XML_SCHEMAP_ELEM_NONAME_NOREF,
2185 "Element has no name nor ref\n", NULL, NULL);
2186 return (NULL);
2187 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002188 if (refNs == NULL)
2189 refNs = schema->targetNamespace;
2190 snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1);
2191 name = (const xmlChar *) buf;
2192 ret = xmlSchemaAddElement(ctxt, schema, name, NULL);
2193 } else {
2194 const xmlChar *local, *ns;
2195
2196 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2197 ret = xmlSchemaAddElement(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002198 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002199 if (ret != NULL)
2200 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002201 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002202 return (NULL);
2203 }
2204 ret->type = XML_SCHEMA_TYPE_ELEMENT;
2205 ret->ref = ref;
2206 ret->refNs = refNs;
2207 if (ref != NULL)
2208 ret->flags |= XML_SCHEMAS_ELEM_REF;
2209 if (toplevel)
2210 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
2211 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
2212 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2213 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
2214 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2215 ctxt->container = name;
2216
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002217 ret->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002218 ret->namedType =
2219 xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002220 if ((ret->namedType != NULL) && (ret->namedTypeNs == NULL))
2221 ret->namedTypeNs = schema->targetNamespace;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002222 ret->substGroup =
2223 xmlGetQNameProp(ctxt, node, "substitutionGroup",
2224 &(ret->substGroupNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002225 fixed = xmlSchemaGetProp(ctxt, node, "fixed");
Daniel Veillard4255d502002-04-16 15:50:10 +00002226 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
2227 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002228
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002229 ret->value = xmlSchemaGetProp(ctxt, node, "default");
Daniel Veillard4255d502002-04-16 15:50:10 +00002230 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002231 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED,
2232 "Element %s has both default and fixed\n",
2233 ret->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002234 } else if (fixed != NULL) {
2235 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002236 ret->value = fixed;
Daniel Veillard4255d502002-04-16 15:50:10 +00002237 }
2238
2239 child = node->children;
2240 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002241 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2242 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002243 }
2244 if (IS_SCHEMA(child, "complexType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002245 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002246 child = child->next;
2247 } else if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002248 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002249 child = child->next;
2250 }
2251 while ((IS_SCHEMA(child, "unique")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002252 (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
2253 TODO child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002254 }
2255 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002256 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD,
2257 "element %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002258 }
2259
2260 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00002261 return (ret);
2262}
2263
2264/**
2265 * xmlSchemaParseUnion:
2266 * @ctxt: a schema validation context
2267 * @schema: the schema being built
2268 * @node: a subtree containing XML Schema informations
2269 *
2270 * parse a XML schema Union definition
2271 * *WARNING* this interface is highly subject to change
2272 *
2273 * Returns -1 in case of error, 0 if the declaration is inproper and
2274 * 1 in case of success.
2275 */
2276static xmlSchemaTypePtr
2277xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002278 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002279{
2280 xmlSchemaTypePtr type, subtype, last = NULL;
2281 xmlNodePtr child = NULL;
2282 xmlChar name[30];
2283
2284 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2285 return (NULL);
2286
2287
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002288 snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002289 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002290 if (type == NULL)
2291 return (NULL);
2292 type->node = node;
2293 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002294 type->id = xmlSchemaGetProp(ctxt, node, "id");
2295 type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes");
Daniel Veillard4255d502002-04-16 15:50:10 +00002296
2297 child = node->children;
2298 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002299 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2300 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002301 }
2302 while (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002303 subtype = (xmlSchemaTypePtr)
2304 xmlSchemaParseSimpleType(ctxt, schema, child);
2305 if (subtype != NULL) {
2306 if (last == NULL) {
2307 type->subtypes = subtype;
2308 last = subtype;
2309 } else {
2310 last->next = subtype;
2311 last = subtype;
2312 }
2313 last->next = NULL;
2314 }
2315 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002316 }
2317 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002318 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD,
2319 "Union %s has unexpected content\n", type->name,
2320 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002321 }
2322 return (type);
2323}
2324
2325/**
2326 * xmlSchemaParseList:
2327 * @ctxt: a schema validation context
2328 * @schema: the schema being built
2329 * @node: a subtree containing XML Schema informations
2330 *
2331 * parse a XML schema List definition
2332 * *WARNING* this interface is highly subject to change
2333 *
2334 * Returns -1 in case of error, 0 if the declaration is inproper and
2335 * 1 in case of success.
2336 */
2337static xmlSchemaTypePtr
2338xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002339 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002340{
2341 xmlSchemaTypePtr type, subtype;
2342 xmlNodePtr child = NULL;
2343 xmlChar name[30];
2344
2345 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2346 return (NULL);
2347
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002348 snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002349 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002350 if (type == NULL)
2351 return (NULL);
2352 type->node = node;
2353 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002354 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002355 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002356 if ((type->ref != NULL) && (type->refNs == NULL))
2357 type->refNs = schema->targetNamespace;
Daniel Veillard4255d502002-04-16 15:50:10 +00002358
2359 child = node->children;
2360 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002361 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2362 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002363 }
2364 subtype = NULL;
2365 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002366 subtype = (xmlSchemaTypePtr)
2367 xmlSchemaParseSimpleType(ctxt, schema, child);
2368 child = child->next;
2369 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002370 }
2371 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002372 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD,
2373 "List %s has unexpected content\n", type->name,
2374 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002375 }
2376 return (type);
2377}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002378
Daniel Veillard4255d502002-04-16 15:50:10 +00002379/**
2380 * xmlSchemaParseSimpleType:
2381 * @ctxt: a schema validation context
2382 * @schema: the schema being built
2383 * @node: a subtree containing XML Schema informations
2384 *
2385 * parse a XML schema Simple Type definition
2386 * *WARNING* this interface is highly subject to change
2387 *
2388 * Returns -1 in case of error, 0 if the declaration is inproper and
2389 * 1 in case of success.
2390 */
2391static xmlSchemaTypePtr
2392xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2393 xmlNodePtr node)
2394{
2395 xmlSchemaTypePtr type, subtype;
2396 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002397 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00002398
2399 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2400 return (NULL);
2401
2402
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002403 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002404 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002405 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002406
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002407 snprintf(buf, 99, "simpletype %d", ctxt->counter++ + 1);
2408 type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL);
2409 } else {
2410 const xmlChar *local, *ns;
2411
2412 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2413 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002414 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002415 if (type == NULL)
2416 return (NULL);
2417 type->node = node;
2418 type->type = XML_SCHEMA_TYPE_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002419 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002420
2421 child = node->children;
2422 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002423 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2424 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002425 }
2426 subtype = NULL;
2427 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002428 subtype = (xmlSchemaTypePtr)
2429 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2430 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002431 } else if (IS_SCHEMA(child, "list")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002432 subtype = (xmlSchemaTypePtr)
2433 xmlSchemaParseList(ctxt, schema, child);
2434 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002435 } else if (IS_SCHEMA(child, "union")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002436 subtype = (xmlSchemaTypePtr)
2437 xmlSchemaParseUnion(ctxt, schema, child);
2438 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002439 }
2440 type->subtypes = subtype;
2441 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002442 xmlSchemaPErr2(ctxt, node, child,
2443 XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD,
2444 "SimpleType %s has unexpected content\n",
2445 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002446 }
2447
2448 return (type);
2449}
2450
2451
2452/**
2453 * xmlSchemaParseGroup:
2454 * @ctxt: a schema validation context
2455 * @schema: the schema being built
2456 * @node: a subtree containing XML Schema informations
2457 *
2458 * parse a XML schema Group definition
2459 * *WARNING* this interface is highly subject to change
2460 *
2461 * Returns -1 in case of error, 0 if the declaration is inproper and
2462 * 1 in case of success.
2463 */
2464static xmlSchemaTypePtr
2465xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002466 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002467{
2468 xmlSchemaTypePtr type, subtype;
2469 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002470 const xmlChar *name;
2471 const xmlChar *ref = NULL, *refNs = NULL;
2472 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002473
2474 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2475 return (NULL);
2476
2477
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002478 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002479 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002480
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002481 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2482 if (ref == NULL) {
2483 xmlSchemaPErr2(ctxt, node, child,
2484 XML_SCHEMAP_GROUP_NONAME_NOREF,
2485 "Group has no name nor ref\n", NULL, NULL);
2486 return (NULL);
2487 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002488 if (refNs == NULL)
2489 refNs = schema->targetNamespace;
2490 snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1);
2491 name = (const xmlChar *) buf;
Daniel Veillard4255d502002-04-16 15:50:10 +00002492 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002493 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002494 if (type == NULL)
2495 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00002496
Daniel Veillard4255d502002-04-16 15:50:10 +00002497 type->node = node;
2498 type->type = XML_SCHEMA_TYPE_GROUP;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002499 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002500 type->ref = ref;
2501 type->refNs = refNs;
2502 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2503 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2504
2505 child = node->children;
2506 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002507 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2508 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002509 }
2510 subtype = NULL;
2511 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002512 subtype = (xmlSchemaTypePtr)
2513 xmlSchemaParseAll(ctxt, schema, child);
2514 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002515 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002516 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2517 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002518 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002519 subtype = (xmlSchemaTypePtr)
2520 xmlSchemaParseSequence(ctxt, schema, child);
2521 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002522 }
2523 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002524 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002525 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002526 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD,
2527 "Group %s has unexpected content\n", type->name,
2528 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002529 }
2530
2531 return (type);
2532}
2533
2534/**
2535 * xmlSchemaParseAll:
2536 * @ctxt: a schema validation context
2537 * @schema: the schema being built
2538 * @node: a subtree containing XML Schema informations
2539 *
2540 * parse a XML schema All definition
2541 * *WARNING* this interface is highly subject to change
2542 *
2543 * Returns -1 in case of error, 0 if the declaration is inproper and
2544 * 1 in case of success.
2545 */
2546static xmlSchemaTypePtr
2547xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002548 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002549{
2550 xmlSchemaTypePtr type, subtype, last = NULL;
2551 xmlNodePtr child = NULL;
2552 xmlChar name[30];
2553
2554 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2555 return (NULL);
2556
2557
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002558 snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002559 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002560 if (type == NULL)
2561 return (NULL);
2562 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002563 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002564 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002565 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2566 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2567
2568 child = node->children;
2569 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002570 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2571 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002572 }
2573 while (IS_SCHEMA(child, "element")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002574 subtype = (xmlSchemaTypePtr)
2575 xmlSchemaParseElement(ctxt, schema, child, 0);
2576 if (subtype != NULL) {
2577 if (last == NULL) {
2578 type->subtypes = subtype;
2579 last = subtype;
2580 } else {
2581 last->next = subtype;
2582 last = subtype;
2583 }
2584 last->next = NULL;
2585 }
2586 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002587 }
2588 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002589 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD,
2590 "All %s has unexpected content\n", type->name,
2591 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002592 }
2593
2594 return (type);
2595}
2596
2597/**
Daniel Veillard1d913862003-11-21 00:28:39 +00002598 * xmlSchemaImportSchema
2599 *
2600 * @ctxt: a schema validation context
2601 * @schemaLocation: an URI defining where to find the imported schema
2602 *
2603 * import a XML schema
2604 * *WARNING* this interface is highly subject to change
2605 *
2606 * Returns -1 in case of error and 1 in case of success.
2607 */
2608static xmlSchemaImportPtr
2609xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt,
2610 const xmlChar *schemaLocation)
2611{
2612 xmlSchemaImportPtr import;
2613 xmlSchemaParserCtxtPtr newctxt;
2614
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002615 newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
Daniel Veillard1d913862003-11-21 00:28:39 +00002616 if (newctxt == NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002617 xmlSchemaPErrMemory(ctxt, "allocating schama parser context",
Daniel Veillard1d913862003-11-21 00:28:39 +00002618 NULL);
2619 return (NULL);
2620 }
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002621 memset(newctxt, 0, sizeof(xmlSchemaParserCtxt));
2622 /* Keep the same dictionnary for parsing, really */
2623 xmlDictReference(ctxt->dict);
2624 newctxt->dict = ctxt->dict;
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002625 newctxt->includes = 0;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002626 newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1);
2627
Daniel Veillard1d913862003-11-21 00:28:39 +00002628 xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning,
2629 ctxt->userData);
2630
2631 import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport));
2632 if (import == NULL) {
2633 xmlSchemaPErrMemory(NULL, "allocating imported schema",
2634 NULL);
2635 xmlSchemaFreeParserCtxt(newctxt);
2636 return (NULL);
2637 }
2638
2639 memset(import, 0, sizeof(xmlSchemaImport));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002640 import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
Daniel Veillard1d913862003-11-21 00:28:39 +00002641 import->schema = xmlSchemaParse(newctxt);
2642
2643 if (import->schema == NULL) {
2644 /* FIXME use another error enum here ? */
2645 xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL,
2646 "failed to import schema at location %s\n",
2647 schemaLocation, NULL);
2648
2649 xmlSchemaFreeParserCtxt(newctxt);
2650 if (import->schemaLocation != NULL)
2651 xmlFree((xmlChar *)import->schemaLocation);
2652 xmlFree(import);
2653 return NULL;
2654 }
2655
2656 xmlSchemaFreeParserCtxt(newctxt);
2657 return import;
2658}
2659
2660
2661/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002662 * xmlSchemaParseImport:
2663 * @ctxt: a schema validation context
2664 * @schema: the schema being built
2665 * @node: a subtree containing XML Schema informations
2666 *
2667 * parse a XML schema Import definition
2668 * *WARNING* this interface is highly subject to change
2669 *
2670 * Returns -1 in case of error, 0 if the declaration is inproper and
2671 * 1 in case of success.
2672 */
2673static int
2674xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002675 xmlNodePtr node)
Daniel Veillard5a872412002-05-22 06:40:27 +00002676{
2677 xmlNodePtr child = NULL;
Daniel Veillard1d913862003-11-21 00:28:39 +00002678 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002679 const xmlChar *namespace;
2680 const xmlChar *schemaLocation;
Daniel Veillard1d913862003-11-21 00:28:39 +00002681 const xmlChar *previous;
Daniel Veillard5a872412002-05-22 06:40:27 +00002682 xmlURIPtr check;
2683
Daniel Veillard1d913862003-11-21 00:28:39 +00002684
Daniel Veillard5a872412002-05-22 06:40:27 +00002685 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2686 return (-1);
2687
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002688 namespace = xmlSchemaGetProp(ctxt, node, "namespace");
Daniel Veillard5a872412002-05-22 06:40:27 +00002689 if (namespace != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002690 check = xmlParseURI((const char *) namespace);
2691 if (check == NULL) {
2692 xmlSchemaPErr2(ctxt, node, child,
2693 XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI,
2694 "Import namespace attribute is not an URI: %s\n",
2695 namespace, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002696 return (-1);
2697 } else {
2698 xmlFreeURI(check);
2699 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002700 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002701 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
Daniel Veillard5a872412002-05-22 06:40:27 +00002702 if (schemaLocation != NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002703 xmlChar *base = NULL;
2704 xmlChar *URI = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002705 check = xmlParseURI((const char *) schemaLocation);
2706 if (check == NULL) {
2707 xmlSchemaPErr2(ctxt, node, child,
2708 XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI,
2709 "Import schemaLocation attribute is not an URI: %s\n",
2710 schemaLocation, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002711 return (-1);
2712 } else {
2713 xmlFreeURI(check);
2714 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002715 base = xmlNodeGetBase(node->doc, node);
2716 if (base == NULL) {
2717 URI = xmlBuildURI(schemaLocation, node->doc->URL);
2718 } else {
2719 URI = xmlBuildURI(schemaLocation, base);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002720 xmlFree(base);
Daniel Veillard1d913862003-11-21 00:28:39 +00002721 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002722 if (URI != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002723 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
2724 xmlFree(URI);
Daniel Veillard1d913862003-11-21 00:28:39 +00002725 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002726 }
2727 if (schema->schemasImports == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002728 schema->schemasImports = xmlHashCreate(10);
2729 if (schema->schemasImports == NULL) {
2730 xmlSchemaPErr2(ctxt, node, child,
2731 XML_SCHEMAP_FAILED_BUILD_IMPORT,
2732 "Internal: failed to build import table\n",
2733 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002734 return (-1);
2735 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002736 }
2737 if (namespace == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002738 import = xmlHashLookup(schema->schemasImports,
2739 XML_SCHEMAS_DEFAULT_NAMESPACE);
2740 if (import != NULL)
2741 previous = import->schemaLocation;
2742 else
2743 previous = NULL;
2744
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002745 if (schemaLocation != NULL) {
2746 if (previous != NULL) {
2747 if (!xmlStrEqual(schemaLocation, previous)) {
2748 xmlSchemaPErr2(ctxt, node, child,
2749 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2750 "Redefining import for default namespace with a different URI: %s\n",
2751 schemaLocation, NULL);
2752 }
2753 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002754 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2755 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002756 return (-1);
2757 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002758 xmlHashAddEntry(schema->schemasImports,
2759 XML_SCHEMAS_DEFAULT_NAMESPACE,
Daniel Veillard1d913862003-11-21 00:28:39 +00002760 import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002761 }
2762 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002763 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002764 import = xmlHashLookup(schema->schemasImports, namespace);
2765 if (import != NULL)
2766 previous = import->schemaLocation;
2767 else
2768 previous = NULL;
2769
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002770 if (schemaLocation != NULL) {
2771 if (previous != NULL) {
2772 if (!xmlStrEqual(schemaLocation, previous)) {
2773 xmlSchemaPErr2(ctxt, node, child,
2774 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2775 "Redefining import for namespace %s with a different URI: %s\n",
2776 namespace, schemaLocation);
2777 }
2778 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002779 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2780 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002781 return (-1);
2782 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002783 xmlHashAddEntry(schema->schemasImports,
Daniel Veillard1d913862003-11-21 00:28:39 +00002784 namespace, import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002785 }
2786 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002787 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002788
2789 child = node->children;
2790 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002791 /*
2792 * the annotations here are simply discarded ...
2793 */
2794 child = child->next;
Daniel Veillard5a872412002-05-22 06:40:27 +00002795 }
2796 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002797 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD,
2798 "Import has unexpected content\n", NULL, NULL);
2799 return (-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002800 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002801 return (1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002802}
2803
2804/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002805 * xmlSchemaCleanupDoc:
2806 * @ctxt: a schema validation context
2807 * @node: the root of the document.
2808 *
2809 * removes unwanted nodes in a schemas document tree
2810 */
2811static void
2812xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root)
2813{
2814 xmlNodePtr delete, cur;
2815
2816 if ((ctxt == NULL) || (root == NULL)) return;
2817
2818 /*
2819 * Remove all the blank text nodes
2820 */
2821 delete = NULL;
2822 cur = root;
2823 while (cur != NULL) {
2824 if (delete != NULL) {
2825 xmlUnlinkNode(delete);
2826 xmlFreeNode(delete);
2827 delete = NULL;
2828 }
2829 if (cur->type == XML_TEXT_NODE) {
2830 if (IS_BLANK_NODE(cur)) {
2831 if (xmlNodeGetSpacePreserve(cur) != 1) {
2832 delete = cur;
2833 }
2834 }
2835 } else if ((cur->type != XML_ELEMENT_NODE) &&
2836 (cur->type != XML_CDATA_SECTION_NODE)) {
2837 delete = cur;
2838 goto skip_children;
2839 }
2840
2841 /*
2842 * Skip to next node
2843 */
2844 if (cur->children != NULL) {
2845 if ((cur->children->type != XML_ENTITY_DECL) &&
2846 (cur->children->type != XML_ENTITY_REF_NODE) &&
2847 (cur->children->type != XML_ENTITY_NODE)) {
2848 cur = cur->children;
2849 continue;
2850 }
2851 }
2852 skip_children:
2853 if (cur->next != NULL) {
2854 cur = cur->next;
2855 continue;
2856 }
2857
2858 do {
2859 cur = cur->parent;
2860 if (cur == NULL)
2861 break;
2862 if (cur == root) {
2863 cur = NULL;
2864 break;
2865 }
2866 if (cur->next != NULL) {
2867 cur = cur->next;
2868 break;
2869 }
2870 } while (cur != NULL);
2871 }
2872 if (delete != NULL) {
2873 xmlUnlinkNode(delete);
2874 xmlFreeNode(delete);
2875 delete = NULL;
2876 }
2877}
2878
2879/**
2880 * xmlSchemaParseSchemaTopLevel:
2881 * @ctxt: a schema validation context
2882 * @schema: the schemas
2883 * @nodes: the list of top level nodes
2884 *
2885 * Returns the internal XML Schema structure built from the resource or
2886 * NULL in case of error
2887 */
2888static void
2889xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt,
2890 xmlSchemaPtr schema, xmlNodePtr nodes)
2891{
2892 xmlNodePtr child;
2893 xmlSchemaAnnotPtr annot;
2894
2895 if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL))
2896 return;
2897
2898 child = nodes;
2899 while ((IS_SCHEMA(child, "include")) ||
2900 (IS_SCHEMA(child, "import")) ||
2901 (IS_SCHEMA(child, "redefine")) ||
2902 (IS_SCHEMA(child, "annotation"))) {
2903 if (IS_SCHEMA(child, "annotation")) {
2904 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2905 if (schema->annot == NULL)
2906 schema->annot = annot;
2907 else
2908 xmlSchemaFreeAnnot(annot);
2909 } else if (IS_SCHEMA(child, "import")) {
2910 xmlSchemaParseImport(ctxt, schema, child);
2911 } else if (IS_SCHEMA(child, "include")) {
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002912 ctxt->includes++;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002913 xmlSchemaParseInclude(ctxt, schema, child);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002914 ctxt->includes--;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002915 } else if (IS_SCHEMA(child, "redefine")) {
2916 TODO
2917 }
2918 child = child->next;
2919 }
2920 while (child != NULL) {
2921 if (IS_SCHEMA(child, "complexType")) {
2922 xmlSchemaParseComplexType(ctxt, schema, child);
2923 child = child->next;
2924 } else if (IS_SCHEMA(child, "simpleType")) {
2925 xmlSchemaParseSimpleType(ctxt, schema, child);
2926 child = child->next;
2927 } else if (IS_SCHEMA(child, "element")) {
2928 xmlSchemaParseElement(ctxt, schema, child, 1);
2929 child = child->next;
2930 } else if (IS_SCHEMA(child, "attribute")) {
2931 xmlSchemaParseAttribute(ctxt, schema, child);
2932 child = child->next;
2933 } else if (IS_SCHEMA(child, "attributeGroup")) {
2934 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2935 child = child->next;
2936 } else if (IS_SCHEMA(child, "group")) {
2937 xmlSchemaParseGroup(ctxt, schema, child);
2938 child = child->next;
2939 } else if (IS_SCHEMA(child, "notation")) {
2940 xmlSchemaParseNotation(ctxt, schema, child);
2941 child = child->next;
2942 } else {
2943 xmlSchemaPErr2(ctxt, NULL, child,
2944 XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD,
2945 "Schemas: unexpected element %s here \n",
2946 child->name, NULL);
2947 child = child->next;
2948 }
2949 while (IS_SCHEMA(child, "annotation")) {
2950 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2951 if (schema->annot == NULL)
2952 schema->annot = annot;
2953 else
2954 xmlSchemaFreeAnnot(annot);
2955 child = child->next;
2956 }
2957 }
2958}
2959
2960/**
2961 * xmlSchemaParseInclude:
2962 * @ctxt: a schema validation context
2963 * @schema: the schema being built
2964 * @node: a subtree containing XML Schema informations
2965 *
2966 * parse a XML schema Include definition
2967 *
2968 * Returns -1 in case of error, 0 if the declaration is inproper and
2969 * 1 in case of success.
2970 */
2971static int
2972xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2973 xmlNodePtr node)
2974{
2975 xmlNodePtr child = NULL;
2976 const xmlChar *schemaLocation;
2977 xmlURIPtr check;
2978 xmlDocPtr doc;
2979 xmlNodePtr root;
2980 xmlSchemaIncludePtr include;
2981
2982
2983 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2984 return (-1);
2985
2986 /*
2987 * Preliminary step, extract the URI-Reference for the include and
2988 * make an URI from the base.
2989 */
2990 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
2991 if (schemaLocation != NULL) {
2992 xmlChar *base = NULL;
2993 xmlChar *URI = NULL;
2994 check = xmlParseURI((const char *) schemaLocation);
2995 if (check == NULL) {
2996 xmlSchemaPErr2(ctxt, node, child,
2997 XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI,
2998 "Include schemaLocation attribute is not an URI: %s\n",
2999 schemaLocation, NULL);
3000 return (-1);
3001 } else {
3002 xmlFreeURI(check);
3003 }
3004 base = xmlNodeGetBase(node->doc, node);
3005 if (base == NULL) {
3006 URI = xmlBuildURI(schemaLocation, node->doc->URL);
3007 } else {
3008 URI = xmlBuildURI(schemaLocation, base);
3009 xmlFree(base);
3010 }
3011 if (URI != NULL) {
3012 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
3013 xmlFree(URI);
3014 }
3015 } else {
3016 xmlSchemaPErr2(ctxt, node, child,
3017 XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI,
3018 "Include schemaLocation attribute missing\n",
3019 NULL, NULL);
3020 return (-1);
3021 }
3022
3023 child = node->children;
3024 while (IS_SCHEMA(child, "annotation")) {
3025 /*
3026 * the annotations here are simply discarded ...
3027 */
3028 child = child->next;
3029 }
3030 if (child != NULL) {
3031 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD,
3032 "Include has unexpected content\n", NULL, NULL);
3033 return (-1);
3034 }
3035
3036 /*
3037 * First step is to parse the input document into an DOM/Infoset
3038 */
3039 doc = xmlReadFile((const char *) schemaLocation, NULL,
3040 SCHEMAS_PARSE_OPTIONS);
3041 if (doc == NULL) {
3042 xmlSchemaPErr(ctxt, NULL,
3043 XML_SCHEMAP_FAILED_LOAD,
3044 "xmlSchemaParse: could not load %s\n",
3045 ctxt->URL, NULL);
3046 return(-1);
3047 }
3048
3049 /*
3050 * Then extract the root of the schema
3051 */
3052 root = xmlDocGetRootElement(doc);
3053 if (root == NULL) {
3054 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3055 XML_SCHEMAP_NOROOT,
3056 "schemas %s has no root", schemaLocation, NULL);
3057 xmlFreeDoc(doc);
3058 return (-1);
3059 }
3060
3061 /*
3062 * Remove all the blank text nodes
3063 */
3064 xmlSchemaCleanupDoc(ctxt, root);
3065
3066 /*
3067 * Check the schemas top level element
3068 */
3069 if (!IS_SCHEMA(root, "schema")) {
3070 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3071 XML_SCHEMAP_NOT_SCHEMA,
3072 "File %s is not a schemas", schemaLocation, NULL);
3073 xmlFreeDoc(doc);
3074 return (-1);
3075 }
3076
3077 /*
3078 * register the include
3079 */
3080 include = (xmlSchemaIncludePtr) xmlMalloc(sizeof(xmlSchemaInclude));
3081 if (include == NULL) {
3082 xmlSchemaPErrMemory(ctxt, "allocating included schema", NULL);
3083 xmlFreeDoc(doc);
3084 return (-1);
3085 }
3086
3087 memset(include, 0, sizeof(xmlSchemaInclude));
3088 include->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
3089 include->doc = doc;
3090 include->next = schema->includes;
3091 schema->includes = include;
3092
3093
3094 /*
3095 * parse the declarations in the included file like if they
3096 * were in the original file.
3097 */
3098 xmlSchemaParseSchemaTopLevel(ctxt, schema, root->children);
3099
3100 return (1);
3101}
3102
3103/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003104 * xmlSchemaParseChoice:
3105 * @ctxt: a schema validation context
3106 * @schema: the schema being built
3107 * @node: a subtree containing XML Schema informations
3108 *
3109 * parse a XML schema Choice definition
3110 * *WARNING* this interface is highly subject to change
3111 *
3112 * Returns -1 in case of error, 0 if the declaration is inproper and
3113 * 1 in case of success.
3114 */
3115static xmlSchemaTypePtr
3116xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003117 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003118{
3119 xmlSchemaTypePtr type, subtype, last = NULL;
3120 xmlNodePtr child = NULL;
3121 xmlChar name[30];
3122
3123 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3124 return (NULL);
3125
3126
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003127 snprintf((char *) name, 30, "choice %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003128 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003129 if (type == NULL)
3130 return (NULL);
3131 type->node = node;
3132 type->type = XML_SCHEMA_TYPE_CHOICE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003133 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003134 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3135 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3136
3137 child = node->children;
3138 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003139 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3140 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003141 }
3142 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003143 (IS_SCHEMA(child, "group")) ||
3144 (IS_SCHEMA(child, "any")) ||
3145 (IS_SCHEMA(child, "choice")) ||
3146 (IS_SCHEMA(child, "sequence"))) {
3147 subtype = NULL;
3148 if (IS_SCHEMA(child, "element")) {
3149 subtype = (xmlSchemaTypePtr)
3150 xmlSchemaParseElement(ctxt, schema, child, 0);
3151 } else if (IS_SCHEMA(child, "group")) {
3152 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3153 } else if (IS_SCHEMA(child, "any")) {
3154 subtype = xmlSchemaParseAny(ctxt, schema, child);
3155 } else if (IS_SCHEMA(child, "sequence")) {
3156 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3157 } else if (IS_SCHEMA(child, "choice")) {
3158 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3159 }
3160 if (subtype != NULL) {
3161 if (last == NULL) {
3162 type->subtypes = subtype;
3163 last = subtype;
3164 } else {
3165 last->next = subtype;
3166 last = subtype;
3167 }
3168 last->next = NULL;
3169 }
3170 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003171 }
3172 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003173 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_CHOICE_CHILD,
3174 "Choice %s has unexpected content\n", type->name,
3175 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003176 }
3177
3178 return (type);
3179}
3180
3181/**
3182 * xmlSchemaParseSequence:
3183 * @ctxt: a schema validation context
3184 * @schema: the schema being built
3185 * @node: a subtree containing XML Schema informations
3186 *
3187 * parse a XML schema Sequence definition
3188 * *WARNING* this interface is highly subject to change
3189 *
3190 * Returns -1 in case of error, 0 if the declaration is inproper and
3191 * 1 in case of success.
3192 */
3193static xmlSchemaTypePtr
3194xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003195 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003196{
3197 xmlSchemaTypePtr type, subtype, last = NULL;
3198 xmlNodePtr child = NULL;
3199 xmlChar name[30];
3200
3201 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3202 return (NULL);
3203
3204
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003205 snprintf((char *) name, 30, "sequence %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003206 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003207 if (type == NULL)
3208 return (NULL);
3209 type->node = node;
3210 type->type = XML_SCHEMA_TYPE_SEQUENCE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003211 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003212 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3213 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3214
3215 child = node->children;
3216 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003217 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3218 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003219 }
3220 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003221 (IS_SCHEMA(child, "group")) ||
3222 (IS_SCHEMA(child, "any")) ||
3223 (IS_SCHEMA(child, "choice")) ||
3224 (IS_SCHEMA(child, "sequence"))) {
3225 subtype = NULL;
3226 if (IS_SCHEMA(child, "element")) {
3227 subtype = (xmlSchemaTypePtr)
3228 xmlSchemaParseElement(ctxt, schema, child, 0);
3229 } else if (IS_SCHEMA(child, "group")) {
3230 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3231 } else if (IS_SCHEMA(child, "any")) {
3232 subtype = xmlSchemaParseAny(ctxt, schema, child);
3233 } else if (IS_SCHEMA(child, "choice")) {
3234 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3235 } else if (IS_SCHEMA(child, "sequence")) {
3236 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3237 }
3238 if (subtype != NULL) {
3239 if (last == NULL) {
3240 type->subtypes = subtype;
3241 last = subtype;
3242 } else {
3243 last->next = subtype;
3244 last = subtype;
3245 }
3246 last->next = NULL;
3247 }
3248 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003249 }
3250 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003251 xmlSchemaPErr2(ctxt, node, child,
3252 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
3253 "Sequence %s has unexpected content\n", type->name,
3254 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003255 }
3256
3257 return (type);
3258}
3259
3260/**
3261 * xmlSchemaParseRestriction:
3262 * @ctxt: a schema validation context
3263 * @schema: the schema being built
3264 * @node: a subtree containing XML Schema informations
3265 * @simple: is that part of a simple type.
3266 *
3267 * parse a XML schema Restriction definition
3268 * *WARNING* this interface is highly subject to change
3269 *
3270 * Returns the type definition or NULL in case of error
3271 */
3272static xmlSchemaTypePtr
3273xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3274 xmlNodePtr node, int simple)
3275{
3276 xmlSchemaTypePtr type, subtype;
3277 xmlSchemaFacetPtr facet, lastfacet = NULL;
3278 xmlNodePtr child = NULL;
3279 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003280 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003281
3282 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3283 return (NULL);
3284
3285 oldcontainer = ctxt->container;
3286
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003287 snprintf((char *) name, 30, "restriction %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003288 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003289 if (type == NULL)
3290 return (NULL);
3291 type->node = node;
3292 type->type = XML_SCHEMA_TYPE_RESTRICTION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003293 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003294 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3295 if ((!simple) && (type->base == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003296 xmlSchemaPErr2(ctxt, node, child,
3297 XML_SCHEMAP_RESTRICTION_NONAME_NOREF,
3298 "Restriction %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003299 }
3300 ctxt->container = name;
3301
3302 child = node->children;
3303 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003304 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3305 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003306 }
3307 subtype = NULL;
3308
3309 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003310 subtype = (xmlSchemaTypePtr)
3311 xmlSchemaParseAll(ctxt, schema, child);
3312 child = child->next;
3313 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003314 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003315 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3316 child = child->next;
3317 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003318 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003319 subtype = (xmlSchemaTypePtr)
3320 xmlSchemaParseSequence(ctxt, schema, child);
3321 child = child->next;
3322 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003323 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003324 subtype = (xmlSchemaTypePtr)
3325 xmlSchemaParseGroup(ctxt, schema, child);
3326 child = child->next;
3327 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003328 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003329 if (IS_SCHEMA(child, "simpleType")) {
3330 subtype = (xmlSchemaTypePtr)
3331 xmlSchemaParseSimpleType(ctxt, schema, child);
3332 child = child->next;
3333 type->baseType = subtype;
3334 }
3335 /*
3336 * Facets
3337 */
Daniel Veillard4255d502002-04-16 15:50:10 +00003338 while ((IS_SCHEMA(child, "minInclusive")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003339 (IS_SCHEMA(child, "minExclusive")) ||
3340 (IS_SCHEMA(child, "maxInclusive")) ||
3341 (IS_SCHEMA(child, "maxExclusive")) ||
3342 (IS_SCHEMA(child, "totalDigits")) ||
3343 (IS_SCHEMA(child, "fractionDigits")) ||
3344 (IS_SCHEMA(child, "pattern")) ||
3345 (IS_SCHEMA(child, "enumeration")) ||
3346 (IS_SCHEMA(child, "whiteSpace")) ||
3347 (IS_SCHEMA(child, "length")) ||
3348 (IS_SCHEMA(child, "maxLength")) ||
3349 (IS_SCHEMA(child, "minLength"))) {
3350 facet = xmlSchemaParseFacet(ctxt, schema, child);
3351 if (facet != NULL) {
3352 if (lastfacet == NULL) {
3353 type->facets = facet;
3354 lastfacet = facet;
3355 } else {
3356 lastfacet->next = facet;
3357 lastfacet = facet;
3358 }
3359 lastfacet->next = NULL;
3360 }
3361 child = child->next;
3362 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003363 }
3364 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3365 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003366 xmlSchemaPErr2(ctxt, node, child,
3367 XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD,
3368 "Restriction %s has unexpected content\n",
3369 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003370 }
3371 ctxt->container = oldcontainer;
3372 return (type);
3373}
3374
3375/**
3376 * xmlSchemaParseExtension:
3377 * @ctxt: a schema validation context
3378 * @schema: the schema being built
3379 * @node: a subtree containing XML Schema informations
3380 *
3381 * parse a XML schema Extension definition
3382 * *WARNING* this interface is highly subject to change
3383 *
3384 * Returns the type definition or NULL in case of error
3385 */
3386static xmlSchemaTypePtr
3387xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003388 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003389{
3390 xmlSchemaTypePtr type, subtype;
3391 xmlNodePtr child = NULL;
3392 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003393 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003394
3395 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3396 return (NULL);
3397
3398 oldcontainer = ctxt->container;
3399
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003400 snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003401 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003402 if (type == NULL)
3403 return (NULL);
3404 type->node = node;
3405 type->type = XML_SCHEMA_TYPE_EXTENSION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003406 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003407 ctxt->container = name;
3408
3409 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3410 if (type->base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003411 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_EXTENSION_NO_BASE,
3412 "Extension %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003413 }
3414 child = node->children;
3415 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003416 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3417 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003418 }
3419 subtype = NULL;
3420
3421 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003422 subtype = xmlSchemaParseAll(ctxt, schema, child);
3423 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003424 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003425 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3426 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003427 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003428 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3429 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003430 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003431 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3432 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003433 }
3434 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003435 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003436 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3437 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003438 xmlSchemaPErr2(ctxt, node, child,
3439 XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD,
3440 "Extension %s has unexpected content\n", type->name,
3441 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003442 }
3443 ctxt->container = oldcontainer;
3444 return (type);
3445}
3446
3447/**
3448 * xmlSchemaParseSimpleContent:
3449 * @ctxt: a schema validation context
3450 * @schema: the schema being built
3451 * @node: a subtree containing XML Schema informations
3452 *
3453 * parse a XML schema SimpleContent definition
3454 * *WARNING* this interface is highly subject to change
3455 *
3456 * Returns the type definition or NULL in case of error
3457 */
3458static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003459xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt,
3460 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003461{
3462 xmlSchemaTypePtr type, subtype;
3463 xmlNodePtr child = NULL;
3464 xmlChar name[30];
3465
3466 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3467 return (NULL);
3468
3469
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003470 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003471 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003472 if (type == NULL)
3473 return (NULL);
3474 type->node = node;
3475 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003476 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003477
3478 child = node->children;
3479 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003480 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3481 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003482 }
3483 subtype = NULL;
3484 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003485 subtype = (xmlSchemaTypePtr)
3486 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3487 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003488 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003489 subtype = (xmlSchemaTypePtr)
3490 xmlSchemaParseExtension(ctxt, schema, child);
3491 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003492 }
3493 type->subtypes = subtype;
3494 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003495 xmlSchemaPErr2(ctxt, node, child,
3496 XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD,
3497 "SimpleContent %s has unexpected content\n",
3498 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003499 }
3500 return (type);
3501}
3502
3503/**
3504 * xmlSchemaParseComplexContent:
3505 * @ctxt: a schema validation context
3506 * @schema: the schema being built
3507 * @node: a subtree containing XML Schema informations
3508 *
3509 * parse a XML schema ComplexContent definition
3510 * *WARNING* this interface is highly subject to change
3511 *
3512 * Returns the type definition or NULL in case of error
3513 */
3514static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003515xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt,
3516 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003517{
3518 xmlSchemaTypePtr type, subtype;
3519 xmlNodePtr child = NULL;
3520 xmlChar name[30];
3521
3522 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3523 return (NULL);
3524
3525
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003526 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003527 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003528 if (type == NULL)
3529 return (NULL);
3530 type->node = node;
3531 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003532 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003533
3534 child = node->children;
3535 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003536 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3537 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003538 }
3539 subtype = NULL;
3540 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003541 subtype = (xmlSchemaTypePtr)
3542 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3543 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003544 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003545 subtype = (xmlSchemaTypePtr)
3546 xmlSchemaParseExtension(ctxt, schema, child);
3547 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003548 }
3549 type->subtypes = subtype;
3550 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003551 xmlSchemaPErr2(ctxt, node, child,
3552 XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD,
3553 "ComplexContent %s has unexpected content\n",
3554 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003555 }
3556 return (type);
3557}
3558
3559/**
3560 * xmlSchemaParseComplexType:
3561 * @ctxt: a schema validation context
3562 * @schema: the schema being built
3563 * @node: a subtree containing XML Schema informations
3564 *
3565 * parse a XML schema Complex Type definition
3566 * *WARNING* this interface is highly subject to change
3567 *
3568 * Returns the type definition or NULL in case of error
3569 */
3570static xmlSchemaTypePtr
3571xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3572 xmlNodePtr node)
3573{
3574 xmlSchemaTypePtr type, subtype;
3575 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003576 const xmlChar *name;
3577 const xmlChar *oldcontainer;
3578 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00003579
3580 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3581 return (NULL);
3582
3583 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003584 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00003585 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003586
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003587 snprintf(buf, 99, "anontype %d", ctxt->counter++ + 1);
3588 name = (const xmlChar *)buf;
3589 type = xmlSchemaAddType(ctxt, schema, name, NULL);
3590 } else {
3591 const xmlChar *local, *ns;
3592
3593 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
3594 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00003595 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003596 if (type == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003597 return (NULL);
3598 }
3599 type->node = node;
3600 type->type = XML_SCHEMA_TYPE_COMPLEX;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003601 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003602 ctxt->container = name;
3603
3604 child = node->children;
3605 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003606 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3607 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003608 }
3609 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003610 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
3611 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003612 } else if (IS_SCHEMA(child, "complexContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003613 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
3614 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003615 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003616 subtype = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003617
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003618 if (IS_SCHEMA(child, "all")) {
3619 subtype = xmlSchemaParseAll(ctxt, schema, child);
3620 child = child->next;
3621 } else if (IS_SCHEMA(child, "choice")) {
3622 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3623 child = child->next;
3624 } else if (IS_SCHEMA(child, "sequence")) {
3625 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3626 child = child->next;
3627 } else if (IS_SCHEMA(child, "group")) {
3628 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3629 child = child->next;
3630 }
3631 if (subtype != NULL)
3632 type->subtypes = subtype;
3633 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
Daniel Veillard4255d502002-04-16 15:50:10 +00003634 }
3635 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003636 xmlSchemaPErr2(ctxt, node, child,
3637 XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD,
3638 "ComplexType %s has unexpected content\n",
3639 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003640 }
3641 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003642 return (type);
3643}
3644
Daniel Veillard4255d502002-04-16 15:50:10 +00003645/**
3646 * xmlSchemaParseSchema:
3647 * @ctxt: a schema validation context
3648 * @node: a subtree containing XML Schema informations
3649 *
3650 * parse a XML schema definition from a node set
3651 * *WARNING* this interface is highly subject to change
3652 *
3653 * Returns the internal XML Schema structure built from the resource or
3654 * NULL in case of error
3655 */
3656static xmlSchemaPtr
3657xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3658{
3659 xmlSchemaPtr schema = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003660 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003661 const xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003662 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003663
3664 if ((ctxt == NULL) || (node == NULL))
3665 return (NULL);
3666
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003667 nberrors = ctxt->nberrors;
3668 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003669 if (IS_SCHEMA(node, "schema")) {
3670 schema = xmlSchemaNewSchema(ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003671 if (schema == NULL)
3672 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003673 val = xmlSchemaGetProp(ctxt, node, "targetNamespace");
3674 if (val != NULL) {
3675 schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1);
3676 } else {
3677 schema->targetNamespace = NULL;
3678 }
3679 schema->id = xmlSchemaGetProp(ctxt, node, "id");
3680 schema->version = xmlSchemaGetProp(ctxt, node, "version");
3681 val = xmlSchemaGetProp(ctxt, node, "elementFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003682 if (val != NULL) {
3683 if (xmlStrEqual(val, BAD_CAST "qualified"))
3684 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3685 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3686 xmlSchemaPErr2(ctxt, node, child,
3687 XML_SCHEMAP_ELEMFORMDEFAULT_VALUE,
3688 "Invalid value %s for elementFormDefault\n",
3689 val, NULL);
3690 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003691 } else {
3692 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3693 }
3694 val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003695 if (val != NULL) {
3696 if (xmlStrEqual(val, BAD_CAST "qualified"))
3697 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3698 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3699 xmlSchemaPErr2(ctxt, node, child,
3700 XML_SCHEMAP_ATTRFORMDEFAULT_VALUE,
3701 "Invalid value %s for attributeFormDefault\n",
3702 val, NULL);
3703 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003704 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003705
Daniel Veillardbd2904b2003-11-25 15:38:59 +00003706 xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children);
3707 } else {
3708 xmlDocPtr doc;
3709
3710 doc = node->doc;
3711
3712 if ((doc != NULL) && (doc->URL != NULL)) {
3713 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3714 XML_SCHEMAP_NOT_SCHEMA,
3715 "File %s is not a schemas", doc->URL, NULL);
3716 } else {
3717 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3718 XML_SCHEMAP_NOT_SCHEMA,
3719 "File is not a schemas", NULL, NULL);
3720 }
3721 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003722 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003723 if (ctxt->nberrors != 0) {
3724 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003725 xmlSchemaFree(schema);
3726 schema = NULL;
3727 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003728 }
3729 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003730#ifdef DEBUG
3731 if (schema == NULL)
3732 xmlGenericError(xmlGenericErrorContext,
3733 "xmlSchemaParse() failed\n");
3734#endif
3735
3736 return (schema);
3737}
3738
3739/************************************************************************
3740 * *
3741 * Validating using Schemas *
3742 * *
3743 ************************************************************************/
3744
3745/************************************************************************
3746 * *
3747 * Reading/Writing Schemas *
3748 * *
3749 ************************************************************************/
3750
3751/**
3752 * xmlSchemaNewParserCtxt:
3753 * @URL: the location of the schema
3754 *
3755 * Create an XML Schemas parse context for that file/resource expected
3756 * to contain an XML Schemas file.
3757 *
3758 * Returns the parser context or NULL in case of error
3759 */
3760xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003761xmlSchemaNewParserCtxt(const char *URL)
3762{
Daniel Veillard4255d502002-04-16 15:50:10 +00003763 xmlSchemaParserCtxtPtr ret;
3764
3765 if (URL == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003766 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003767
3768 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3769 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003770 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3771 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003772 return (NULL);
3773 }
3774 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003775 ret->dict = xmlDictCreate();
3776 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00003777 ret->includes = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003778 return (ret);
3779}
3780
3781/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003782 * xmlSchemaNewMemParserCtxt:
3783 * @buffer: a pointer to a char array containing the schemas
3784 * @size: the size of the array
3785 *
3786 * Create an XML Schemas parse context for that memory buffer expected
3787 * to contain an XML Schemas file.
3788 *
3789 * Returns the parser context or NULL in case of error
3790 */
3791xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003792xmlSchemaNewMemParserCtxt(const char *buffer, int size)
3793{
Daniel Veillard6045c902002-10-09 21:13:59 +00003794 xmlSchemaParserCtxtPtr ret;
3795
3796 if ((buffer == NULL) || (size <= 0))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003797 return (NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003798
3799 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3800 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003801 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3802 NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003803 return (NULL);
3804 }
3805 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3806 ret->buffer = buffer;
3807 ret->size = size;
3808 return (ret);
3809}
3810
3811/**
Daniel Veillard9d751502003-10-29 13:21:47 +00003812 * xmlSchemaNewDocParserCtxt:
3813 * @doc: a preparsed document tree
3814 *
3815 * Create an XML Schemas parse context for that document.
3816 * NB. The document may be modified during the parsing process.
3817 *
3818 * Returns the parser context or NULL in case of error
3819 */
3820xmlSchemaParserCtxtPtr
3821xmlSchemaNewDocParserCtxt(xmlDocPtr doc)
3822{
3823 xmlSchemaParserCtxtPtr ret;
3824
3825 if (doc == NULL)
3826 return (NULL);
3827
3828 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3829 if (ret == NULL) {
3830 xmlSchemaPErrMemory(NULL, "allocating schema parser context",
3831 NULL);
3832 return (NULL);
3833 }
3834 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3835 ret->doc = doc;
3836
3837 return (ret);
3838}
3839
3840/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003841 * xmlSchemaFreeParserCtxt:
3842 * @ctxt: the schema parser context
3843 *
3844 * Free the resources associated to the schema parser context
3845 */
3846void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003847xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt)
3848{
Daniel Veillard4255d502002-04-16 15:50:10 +00003849 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003850 return;
Daniel Veillard6045c902002-10-09 21:13:59 +00003851 if (ctxt->doc != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003852 xmlFreeDoc(ctxt->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003853 xmlDictFree(ctxt->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +00003854 xmlFree(ctxt);
3855}
3856
3857/************************************************************************
3858 * *
3859 * Building the content models *
3860 * *
3861 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003862
Daniel Veillard4255d502002-04-16 15:50:10 +00003863/**
3864 * xmlSchemaBuildAContentModel:
3865 * @type: the schema type definition
3866 * @ctxt: the schema parser context
3867 * @name: the element name whose content is being built
3868 *
3869 * Generate the automata sequence needed for that type
3870 */
3871static void
3872xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003873 xmlSchemaParserCtxtPtr ctxt,
3874 const xmlChar * name)
3875{
Daniel Veillard4255d502002-04-16 15:50:10 +00003876 if (type == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003877 xmlGenericError(xmlGenericErrorContext,
3878 "Found unexpected type = NULL in %s content model\n",
3879 name);
3880 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003881 }
3882 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003883 case XML_SCHEMA_TYPE_ANY:
3884 /* TODO : handle the namespace too */
3885 /* TODO : make that a specific transition type */
3886 TODO ctxt->state =
3887 xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL,
3888 BAD_CAST "*", NULL);
3889 break;
3890 case XML_SCHEMA_TYPE_ELEMENT:{
3891 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard32370232002-10-16 14:08:14 +00003892
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003893 /* TODO : handle the namespace too */
3894 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003895
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003896 if (elem->maxOccurs >= UNBOUNDED) {
3897 if (elem->minOccurs > 1) {
3898 xmlAutomataStatePtr tmp;
3899 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003900
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003901 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3902 oldstate,
3903 NULL);
3904 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003905
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003906 counter = xmlAutomataNewCounter(ctxt->am,
3907 elem->minOccurs -
3908 1, UNBOUNDED);
Daniel Veillard32370232002-10-16 14:08:14 +00003909
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003910 if (elem->refDecl != NULL) {
3911 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3912 elem->refDecl,
3913 ctxt,
3914 elem->refDecl->
3915 name);
3916 } else {
3917 ctxt->state =
3918 xmlAutomataNewTransition(ctxt->am,
3919 ctxt->state, NULL,
3920 elem->name, type);
3921 }
3922 tmp = ctxt->state;
3923 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3924 counter);
3925 ctxt->state =
3926 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
3927 counter);
Daniel Veillard32370232002-10-16 14:08:14 +00003928
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003929 } else {
3930 if (elem->refDecl != NULL) {
3931 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3932 elem->refDecl,
3933 ctxt,
3934 elem->refDecl->
3935 name);
3936 } else {
3937 ctxt->state =
3938 xmlAutomataNewTransition(ctxt->am,
3939 ctxt->state, NULL,
3940 elem->name, type);
3941 }
3942 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3943 oldstate);
3944 if (elem->minOccurs == 0) {
3945 /* basically an elem* */
3946 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3947 ctxt->state);
3948 }
3949 }
3950 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3951 xmlAutomataStatePtr tmp;
3952 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003953
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003954 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3955 oldstate, NULL);
3956 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003957
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003958 counter = xmlAutomataNewCounter(ctxt->am,
3959 elem->minOccurs - 1,
3960 elem->maxOccurs - 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003961
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003962 if (elem->refDecl != NULL) {
3963 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3964 elem->refDecl, ctxt,
3965 elem->refDecl->name);
3966 } else {
3967 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3968 ctxt->state,
3969 NULL,
3970 elem->name,
3971 type);
3972 }
3973 tmp = ctxt->state;
3974 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3975 counter);
3976 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3977 NULL,
3978 counter);
3979 if (elem->minOccurs == 0) {
3980 /* basically an elem? */
3981 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3982 ctxt->state);
3983 }
Daniel Veillardb39bc392002-10-26 19:29:51 +00003984
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003985 } else {
3986 if (elem->refDecl != NULL) {
3987 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3988 elem->refDecl, ctxt,
3989 elem->refDecl->name);
3990 } else {
3991 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3992 ctxt->state,
3993 NULL,
3994 elem->name,
3995 type);
3996 }
3997 if (elem->minOccurs == 0) {
3998 /* basically an elem? */
3999 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4000 ctxt->state);
4001 }
4002 }
4003 break;
4004 }
4005 case XML_SCHEMA_TYPE_SEQUENCE:{
4006 xmlSchemaTypePtr subtypes;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004007
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004008 /*
4009 * If max and min occurances are default (1) then
4010 * simply iterate over the subtypes
4011 */
4012 if ((type->minOccurs == 1) && (type->maxOccurs == 1)) {
4013 subtypes = type->subtypes;
4014 while (subtypes != NULL) {
4015 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4016 subtypes = subtypes->next;
4017 }
4018 } else {
4019 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004020
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004021 if (type->maxOccurs >= UNBOUNDED) {
4022 if (type->minOccurs > 1) {
4023 xmlAutomataStatePtr tmp;
4024 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004025
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004026 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4027 oldstate,
4028 NULL);
4029 oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004030
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004031 counter = xmlAutomataNewCounter(ctxt->am,
4032 type->
4033 minOccurs - 1,
4034 UNBOUNDED);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004035
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004036 subtypes = type->subtypes;
4037 while (subtypes != NULL) {
4038 xmlSchemaBuildAContentModel(subtypes, ctxt,
4039 name);
4040 subtypes = subtypes->next;
4041 }
4042 tmp = ctxt->state;
4043 xmlAutomataNewCountedTrans(ctxt->am, tmp,
4044 oldstate, counter);
4045 ctxt->state =
4046 xmlAutomataNewCounterTrans(ctxt->am, tmp,
4047 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004048
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004049 } else {
4050 subtypes = type->subtypes;
4051 while (subtypes != NULL) {
4052 xmlSchemaBuildAContentModel(subtypes, ctxt,
4053 name);
4054 subtypes = subtypes->next;
4055 }
4056 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
4057 oldstate);
4058 if (type->minOccurs == 0) {
4059 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4060 ctxt->state);
4061 }
4062 }
4063 } else if ((type->maxOccurs > 1)
4064 || (type->minOccurs > 1)) {
4065 xmlAutomataStatePtr tmp;
4066 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004067
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004068 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4069 oldstate,
4070 NULL);
4071 oldstate = ctxt->state;
Daniel Veillard4255d502002-04-16 15:50:10 +00004072
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004073 counter = xmlAutomataNewCounter(ctxt->am,
4074 type->minOccurs -
4075 1,
4076 type->maxOccurs -
4077 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004078
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004079 subtypes = type->subtypes;
4080 while (subtypes != NULL) {
4081 xmlSchemaBuildAContentModel(subtypes, ctxt,
4082 name);
4083 subtypes = subtypes->next;
4084 }
4085 tmp = ctxt->state;
4086 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
4087 counter);
4088 ctxt->state =
4089 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
4090 counter);
4091 if (type->minOccurs == 0) {
4092 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4093 ctxt->state);
4094 }
Daniel Veillardb509f152002-04-17 16:28:10 +00004095
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004096 } else {
4097 subtypes = type->subtypes;
4098 while (subtypes != NULL) {
4099 xmlSchemaBuildAContentModel(subtypes, ctxt,
4100 name);
4101 subtypes = subtypes->next;
4102 }
4103 if (type->minOccurs == 0) {
4104 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4105 ctxt->state);
4106 }
4107 }
4108 }
4109 break;
4110 }
4111 case XML_SCHEMA_TYPE_CHOICE:{
4112 xmlSchemaTypePtr subtypes;
4113 xmlAutomataStatePtr start, end;
Daniel Veillardb509f152002-04-17 16:28:10 +00004114
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004115 start = ctxt->state;
4116 end = xmlAutomataNewState(ctxt->am);
Daniel Veillard7646b182002-04-20 06:41:40 +00004117
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004118 /*
4119 * iterate over the subtypes and remerge the end with an
4120 * epsilon transition
4121 */
4122 if (type->maxOccurs == 1) {
4123 subtypes = type->subtypes;
4124 while (subtypes != NULL) {
4125 ctxt->state = start;
4126 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4127 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
4128 subtypes = subtypes->next;
4129 }
4130 } else {
4131 int counter;
4132 xmlAutomataStatePtr hop;
4133 int maxOccurs = type->maxOccurs == UNBOUNDED ?
4134 UNBOUNDED : type->maxOccurs - 1;
4135 int minOccurs =
4136 type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillard7646b182002-04-20 06:41:40 +00004137
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004138 /*
4139 * use a counter to keep track of the number of transtions
4140 * which went through the choice.
4141 */
4142 counter =
4143 xmlAutomataNewCounter(ctxt->am, minOccurs,
4144 maxOccurs);
4145 hop = xmlAutomataNewState(ctxt->am);
Daniel Veillard6231e842002-04-18 11:54:04 +00004146
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004147 subtypes = type->subtypes;
4148 while (subtypes != NULL) {
4149 ctxt->state = start;
4150 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4151 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
4152 subtypes = subtypes->next;
4153 }
4154 xmlAutomataNewCountedTrans(ctxt->am, hop, start,
4155 counter);
4156 xmlAutomataNewCounterTrans(ctxt->am, hop, end,
4157 counter);
4158 }
4159 if (type->minOccurs == 0) {
4160 xmlAutomataNewEpsilon(ctxt->am, start, end);
4161 }
4162 ctxt->state = end;
4163 break;
4164 }
4165 case XML_SCHEMA_TYPE_ALL:{
4166 xmlAutomataStatePtr start;
4167 xmlSchemaTypePtr subtypes;
4168 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
4169 int lax;
4170
4171 subtypes = type->subtypes;
4172 if (subtypes == NULL)
4173 break;
4174 start = ctxt->state;
4175 while (subtypes != NULL) {
4176 ctxt->state = start;
4177 elem = (xmlSchemaElementPtr) subtypes;
4178
4179 /* TODO : handle the namespace too */
4180 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
4181 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state,
4182 ctxt->state, elem->name, 1,
4183 1, subtypes);
4184 } else {
4185 xmlAutomataNewCountTrans(ctxt->am, ctxt->state,
4186 ctxt->state, elem->name,
4187 elem->minOccurs,
4188 elem->maxOccurs,
4189 subtypes);
4190 }
4191 subtypes = subtypes->next;
4192 }
4193 lax = type->minOccurs == 0;
4194 ctxt->state =
4195 xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
4196 lax);
4197 break;
4198 }
4199 case XML_SCHEMA_TYPE_RESTRICTION:
4200 if (type->subtypes != NULL)
4201 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4202 break;
4203 case XML_SCHEMA_TYPE_EXTENSION:
4204 if (type->baseType != NULL) {
4205 xmlSchemaTypePtr subtypes;
4206
4207 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
4208 subtypes = type->subtypes;
4209 while (subtypes != NULL) {
4210 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4211 subtypes = subtypes->next;
4212 }
4213 } else if (type->subtypes != NULL)
4214 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4215 break;
4216 case XML_SCHEMA_TYPE_GROUP:
4217 if (type->subtypes == NULL) {
4218 }
4219 case XML_SCHEMA_TYPE_COMPLEX:
4220 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4221 if (type->subtypes != NULL)
4222 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4223 break;
4224 default:
4225 xmlGenericError(xmlGenericErrorContext,
4226 "Found unexpected type %d in %s content model\n",
4227 type->type, name);
4228 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004229 }
4230}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004231
Daniel Veillard4255d502002-04-16 15:50:10 +00004232/**
4233 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004234 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00004235 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004236 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00004237 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004238 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00004239 */
4240static void
4241xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004242 xmlSchemaParserCtxtPtr ctxt,
4243 const xmlChar * name)
4244{
Daniel Veillard4255d502002-04-16 15:50:10 +00004245 xmlAutomataStatePtr start;
4246
Daniel Veillard4255d502002-04-16 15:50:10 +00004247 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004248 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004249 if (elem->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004250 elem->contentType = XML_SCHEMA_CONTENT_ANY;
4251 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004252 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004253 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004254 return;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004255 if ((elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC) ||
4256 (elem->subtypes->contentType == XML_SCHEMA_CONTENT_SIMPLE))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004257 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004258
4259#ifdef DEBUG_CONTENT
4260 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004261 "Building content model for %s\n", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004262#endif
4263
Daniel Veillard4255d502002-04-16 15:50:10 +00004264 ctxt->am = xmlNewAutomata();
4265 if (ctxt->am == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004266 xmlGenericError(xmlGenericErrorContext,
4267 "Cannot create automata for elem %s\n", name);
4268 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004269 }
4270 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
4271 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
4272 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00004273 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004274 if (elem->contModel == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004275 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_INTERNAL,
4276 "failed to compile %s content model\n", name, NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004277 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004278 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_NOTDETERMINIST,
4279 "Content model of %s is not determinist:\n", name,
4280 NULL);
Daniel Veillarde19fc232002-04-22 16:01:24 +00004281 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00004282#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004283 xmlGenericError(xmlGenericErrorContext,
4284 "Content model of %s:\n", name);
4285 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00004286#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00004287 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004288 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00004289 xmlFreeAutomata(ctxt->am);
4290 ctxt->am = NULL;
4291}
4292
4293/**
4294 * xmlSchemaRefFixupCallback:
4295 * @elem: the schema element context
4296 * @ctxt: the schema parser context
4297 *
4298 * Free the resources associated to the schema parser context
4299 */
4300static void
4301xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004302 xmlSchemaParserCtxtPtr ctxt,
4303 const xmlChar * name,
4304 const xmlChar * context ATTRIBUTE_UNUSED,
4305 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00004306{
4307 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004308 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004309 if (elem->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004310 xmlSchemaElementPtr elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004311
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004312 if (elem->subtypes != NULL) {
4313 xmlSchemaPErr(ctxt, elem->node,
4314 XML_SCHEMAP_INVALID_REF_AND_SUBTYPE,
4315 "Schemas: element %s have both ref and subtype\n",
4316 name, NULL);
4317 return;
4318 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004319 elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00004320
4321 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004322 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF,
4323 "Schemas: element %s ref to %s not found\n",
4324 name, elem->ref);
4325 return;
4326 }
4327 elem->refDecl = elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004328 } else if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004329 xmlSchemaTypePtr typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004330
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004331 if (elem->subtypes != NULL) {
4332 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE,
4333 "Schemas: element %s have both type and subtype\n",
4334 name, NULL);
4335 return;
4336 }
4337 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
4338 elem->namedTypeNs);
Daniel Veillard4255d502002-04-16 15:50:10 +00004339
4340 if (typeDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004341 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE,
4342 "Schemas: element %s type %s not found\n", name,
4343 elem->namedType);
4344 return;
4345 }
4346 elem->subtypes = typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004347 }
4348}
4349
4350/**
4351 * xmlSchemaTypeFixup:
4352 * @typeDecl: the schema type definition
4353 * @ctxt: the schema parser context
4354 *
4355 * Fixes the content model of the type.
4356 */
4357static void
4358xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004359 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004360{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004361 if (typeDecl == NULL)
4362 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004363 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004364 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004365 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004366 switch (typeDecl->type) {
4367 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{
4368 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
4369 if (typeDecl->subtypes != NULL)
4370 typeDecl->contentType =
4371 typeDecl->subtypes->contentType;
4372 break;
4373 }
4374 case XML_SCHEMA_TYPE_RESTRICTION:{
4375 if (typeDecl->subtypes != NULL)
4376 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004377
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004378 if (typeDecl->base != NULL) {
4379 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004380
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004381 baseType =
4382 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4383 typeDecl->baseNs);
4384 if (baseType == NULL) {
4385 xmlSchemaPErr(ctxt, typeDecl->node,
4386 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004387 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004388 name, typeDecl->base);
4389 }
4390 typeDecl->baseType = baseType;
4391 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004392 if (typeDecl->subtypes == NULL)
4393 if (typeDecl->baseType != NULL)
4394 typeDecl->contentType =
4395 typeDecl->baseType->contentType;
4396 else
4397 /* 1.1.1 */
4398 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004399 else if ((typeDecl->subtypes->subtypes == NULL) &&
4400 ((typeDecl->subtypes->type ==
4401 XML_SCHEMA_TYPE_ALL)
4402 || (typeDecl->subtypes->type ==
4403 XML_SCHEMA_TYPE_SEQUENCE)))
4404 /* 1.1.2 */
4405 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4406 else if ((typeDecl->subtypes->type ==
4407 XML_SCHEMA_TYPE_CHOICE)
4408 && (typeDecl->subtypes->subtypes == NULL))
4409 /* 1.1.3 */
4410 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4411 else {
4412 /* 1.2 and 2.X are applied at the other layer */
4413 typeDecl->contentType =
4414 XML_SCHEMA_CONTENT_ELEMENTS;
4415 }
4416 break;
4417 }
4418 case XML_SCHEMA_TYPE_EXTENSION:{
4419 xmlSchemaContentType explicitContentType;
4420 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00004421
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004422 if (typeDecl->base != NULL) {
4423 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004424
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004425 baseType =
4426 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4427 typeDecl->baseNs);
4428 if (baseType == NULL) {
4429 xmlSchemaPErr(ctxt, typeDecl->node,
4430 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004431 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004432 name, typeDecl->base);
4433 }
4434 typeDecl->baseType = baseType;
4435 }
4436 if (typeDecl->subtypes != NULL)
4437 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004438
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004439 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
4440 if (typeDecl->subtypes == NULL)
4441 /* 1.1.1 */
4442 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4443 else if ((typeDecl->subtypes->subtypes == NULL) &&
4444 ((typeDecl->subtypes->type ==
4445 XML_SCHEMA_TYPE_ALL)
4446 || (typeDecl->subtypes->type ==
4447 XML_SCHEMA_TYPE_SEQUENCE)))
4448 /* 1.1.2 */
4449 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4450 else if ((typeDecl->subtypes->type ==
4451 XML_SCHEMA_TYPE_CHOICE)
4452 && (typeDecl->subtypes->subtypes == NULL))
4453 /* 1.1.3 */
4454 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard4255d502002-04-16 15:50:10 +00004455
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004456 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
4457 typeDecl->baseNs);
4458 if (base == NULL) {
4459 xmlSchemaPErr(ctxt, typeDecl->node,
4460 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
4461 "Schemas: base type %s of type %s not found\n",
4462 typeDecl->base, name);
4463 return;
4464 }
4465 xmlSchemaTypeFixup(base, ctxt, NULL);
4466 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
4467 /* 2.1 */
4468 typeDecl->contentType = base->contentType;
4469 } else if (base->contentType ==
4470 XML_SCHEMA_CONTENT_EMPTY) {
4471 /* 2.2 imbitable ! */
4472 typeDecl->contentType =
4473 XML_SCHEMA_CONTENT_ELEMENTS;
4474 } else {
4475 /* 2.3 imbitable pareil ! */
4476 typeDecl->contentType =
4477 XML_SCHEMA_CONTENT_ELEMENTS;
4478 }
4479 break;
4480 }
4481 case XML_SCHEMA_TYPE_COMPLEX:{
4482 if (typeDecl->subtypes == NULL) {
4483 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4484 } else {
4485 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4486 typeDecl->contentType =
4487 XML_SCHEMA_CONTENT_MIXED;
4488 else {
4489 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4490 NULL);
4491 if (typeDecl->subtypes != NULL)
4492 typeDecl->contentType =
4493 typeDecl->subtypes->contentType;
4494 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004495 if (typeDecl->attributes == NULL)
4496 typeDecl->attributes =
4497 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004498 }
4499 break;
4500 }
4501 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{
4502 if (typeDecl->subtypes == NULL) {
4503 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4504 } else {
4505 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4506 typeDecl->contentType =
4507 XML_SCHEMA_CONTENT_MIXED;
4508 else {
4509 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4510 NULL);
4511 if (typeDecl->subtypes != NULL)
4512 typeDecl->contentType =
4513 typeDecl->subtypes->contentType;
4514 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004515 if (typeDecl->attributes == NULL)
4516 typeDecl->attributes =
4517 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004518 }
4519 break;
4520 }
4521 case XML_SCHEMA_TYPE_SEQUENCE:
4522 case XML_SCHEMA_TYPE_GROUP:
4523 case XML_SCHEMA_TYPE_ALL:
4524 case XML_SCHEMA_TYPE_CHOICE:
4525 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
4526 break;
4527 case XML_SCHEMA_TYPE_BASIC:
4528 case XML_SCHEMA_TYPE_ANY:
4529 case XML_SCHEMA_TYPE_FACET:
4530 case XML_SCHEMA_TYPE_SIMPLE:
4531 case XML_SCHEMA_TYPE_UR:
4532 case XML_SCHEMA_TYPE_ELEMENT:
4533 case XML_SCHEMA_TYPE_ATTRIBUTE:
4534 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4535 case XML_SCHEMA_TYPE_NOTATION:
4536 case XML_SCHEMA_TYPE_LIST:
4537 case XML_SCHEMA_TYPE_UNION:
4538 case XML_SCHEMA_FACET_MININCLUSIVE:
4539 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4540 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4541 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4542 case XML_SCHEMA_FACET_TOTALDIGITS:
4543 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4544 case XML_SCHEMA_FACET_PATTERN:
4545 case XML_SCHEMA_FACET_ENUMERATION:
4546 case XML_SCHEMA_FACET_WHITESPACE:
4547 case XML_SCHEMA_FACET_LENGTH:
4548 case XML_SCHEMA_FACET_MAXLENGTH:
4549 case XML_SCHEMA_FACET_MINLENGTH:
4550 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004551 if (typeDecl->subtypes != NULL)
4552 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004553 break;
4554 }
4555 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004556#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004557 if (typeDecl->node != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004558 xmlGenericError(xmlGenericErrorContext,
4559 "Type of %s : %s:%d :", name,
4560 typeDecl->node->doc->URL,
4561 xmlGetLineNo(typeDecl->node));
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004562 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004563 xmlGenericError(xmlGenericErrorContext, "Type of %s :", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004564 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004565 switch (typeDecl->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004566 case XML_SCHEMA_CONTENT_SIMPLE:
4567 xmlGenericError(xmlGenericErrorContext, "simple\n");
4568 break;
4569 case XML_SCHEMA_CONTENT_ELEMENTS:
4570 xmlGenericError(xmlGenericErrorContext, "elements\n");
4571 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004572 case XML_SCHEMA_CONTENT_UNKNOWN:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004573 xmlGenericError(xmlGenericErrorContext, "unknown !!!\n");
4574 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004575 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004576 xmlGenericError(xmlGenericErrorContext, "empty\n");
4577 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004578 case XML_SCHEMA_CONTENT_MIXED:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004579 xmlGenericError(xmlGenericErrorContext, "mixed\n");
4580 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004581 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004582 xmlGenericError(xmlGenericErrorContext, "mixed or elems\n");
4583 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004584 case XML_SCHEMA_CONTENT_BASIC:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004585 xmlGenericError(xmlGenericErrorContext, "basic\n");
4586 break;
4587 default:
4588 xmlGenericError(xmlGenericErrorContext,
4589 "not registered !!!\n");
4590 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004591 }
4592#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00004593}
4594
4595/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004596 * xmlSchemaCheckFacet:
4597 * @facet: the facet
4598 * @typeDecl: the schema type definition
4599 * @ctxt: the schema parser context or NULL
4600 * @name: name of the type
4601 *
4602 * Checks the default values types, especially for facets
4603 *
4604 * Returns 0 if okay or -1 in cae of error
4605 */
4606int
4607xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004608 xmlSchemaTypePtr typeDecl,
4609 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004610{
4611 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
4612 int ret = 0;
4613
4614 if (nonNegativeIntegerType == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004615 nonNegativeIntegerType =
4616 xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger",
4617 xmlSchemaNs);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004618 }
4619 switch (facet->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004620 case XML_SCHEMA_FACET_MININCLUSIVE:
4621 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4622 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4623 case XML_SCHEMA_FACET_MAXEXCLUSIVE:{
4624 /*
4625 * Okay we need to validate the value
4626 * at that point.
4627 */
4628 xmlSchemaValidCtxtPtr vctxt;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004629
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004630 vctxt = xmlSchemaNewValidCtxt(NULL);
4631 if (vctxt == NULL)
4632 break;
4633 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4634 facet->value);
4635 facet->val = vctxt->value;
4636 vctxt->value = NULL;
4637 if (facet->val == NULL) {
4638 /* error code */
4639 if (ctxt != NULL) {
4640 xmlSchemaPErr(ctxt, facet->node,
4641 XML_SCHEMAP_INVALID_FACET,
4642 "Schemas: type %s facet value %s invalid\n",
4643 name, facet->value);
4644 }
4645 ret = -1;
4646 }
4647 xmlSchemaFreeValidCtxt(vctxt);
4648 break;
4649 }
4650 case XML_SCHEMA_FACET_ENUMERATION:{
4651 /*
4652 * Okay we need to validate the value
4653 * at that point.
4654 */
4655 xmlSchemaValidCtxtPtr vctxt;
4656 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004657
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004658 vctxt = xmlSchemaNewValidCtxt(NULL);
4659 if (vctxt == NULL)
4660 break;
4661 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4662 facet->value);
4663 if (tmp != 0) {
4664 if (ctxt != NULL) {
4665 xmlSchemaPErr(ctxt, facet->node,
4666 XML_SCHEMAP_INVALID_ENUM,
4667 "Schemas: type %s enumeration value %s invalid\n",
4668 name, facet->value);
4669 }
4670 ret = -1;
4671 }
4672 xmlSchemaFreeValidCtxt(vctxt);
4673 break;
4674 }
4675 case XML_SCHEMA_FACET_PATTERN:
4676 facet->regexp = xmlRegexpCompile(facet->value);
4677 if (facet->regexp == NULL) {
4678 xmlSchemaPErr(ctxt, typeDecl->node,
4679 XML_SCHEMAP_REGEXP_INVALID,
4680 "Schemas: type %s facet regexp %s invalid\n",
4681 name, facet->value);
4682 ret = -1;
4683 }
4684 break;
4685 case XML_SCHEMA_FACET_TOTALDIGITS:
4686 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4687 case XML_SCHEMA_FACET_LENGTH:
4688 case XML_SCHEMA_FACET_MAXLENGTH:
4689 case XML_SCHEMA_FACET_MINLENGTH:{
4690 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004691
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004692 tmp =
4693 xmlSchemaValidatePredefinedType(nonNegativeIntegerType,
4694 facet->value,
4695 &facet->val);
4696 if (tmp != 0) {
4697 /* error code */
4698 if (ctxt != NULL) {
4699 xmlSchemaPErr(ctxt, facet->node,
4700 XML_SCHEMAP_INVALID_FACET_VALUE,
4701 "Schemas: type %s facet value %s invalid\n",
4702 name, facet->value);
4703 }
4704 ret = -1;
4705 }
4706 break;
4707 }
4708 case XML_SCHEMA_FACET_WHITESPACE:{
4709 if (xmlStrEqual(facet->value, BAD_CAST "preserve")) {
4710 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4711 } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) {
4712 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4713 } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) {
4714 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4715 } else {
4716 if (ctxt != NULL) {
4717 xmlSchemaPErr(ctxt, facet->node,
4718 XML_SCHEMAP_INVALID_WHITE_SPACE,
4719 "Schemas: type %s whiteSpace value %s invalid\n",
4720 name, facet->value);
4721 }
4722 ret = -1;
4723 }
4724 }
4725 default:
4726 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004727 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004728 return (ret);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004729}
4730
4731/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004732 * xmlSchemaCheckDefaults:
4733 * @typeDecl: the schema type definition
4734 * @ctxt: the schema parser context
4735 *
4736 * Checks the default values types, especially for facets
4737 */
4738static void
4739xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004740 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004741{
Daniel Veillard4255d502002-04-16 15:50:10 +00004742 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004743 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004744 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004745 if (typeDecl->facets != NULL) {
4746 xmlSchemaFacetPtr facet = typeDecl->facets;
4747
4748 while (facet != NULL) {
4749 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
4750 facet = facet->next;
4751 }
4752 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004753 }
4754}
4755
4756/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004757 * xmlSchemaAttrGrpFixup:
4758 * @attrgrpDecl: the schema attribute definition
4759 * @ctxt: the schema parser context
4760 * @name: the attribute name
4761 *
4762 * Fixes finish doing the computations on the attributes definitions
4763 */
4764static void
4765xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004766 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard13e04c62002-04-23 17:51:29 +00004767{
4768 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004769 name = attrgrpDecl->name;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004770 if (attrgrpDecl->attributes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004771 return;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004772 if (attrgrpDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004773 xmlSchemaAttributeGroupPtr ref;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004774
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004775 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4776 attrgrpDecl->refNs);
4777 if (ref == NULL) {
4778 xmlSchemaPErr(ctxt, attrgrpDecl->node,
4779 XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP,
4780 "Schemas: attribute group %s reference %s not found\n",
4781 name, attrgrpDecl->ref);
4782 return;
4783 }
4784 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4785 attrgrpDecl->attributes = ref->attributes;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004786 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004787 xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF,
4788 "Schemas: attribute %s has no attributes nor reference\n",
4789 name, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004790 }
4791}
4792
4793/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004794 * xmlSchemaAttrFixup:
4795 * @attrDecl: the schema attribute definition
4796 * @ctxt: the schema parser context
4797 * @name: the attribute name
4798 *
4799 * Fixes finish doing the computations on the attributes definitions
4800 */
4801static void
4802xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004803 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004804{
4805 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004806 name = attrDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004807 if (attrDecl->subtypes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004808 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004809 if (attrDecl->typeName != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004810 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004811
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004812 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4813 attrDecl->typeNs);
4814 if (type == NULL) {
4815 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE,
4816 "Schemas: attribute %s type %s not found\n",
4817 name, attrDecl->typeName);
4818 }
4819 attrDecl->subtypes = type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004820 } else if (attrDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004821 xmlSchemaAttributePtr ref;
Daniel Veillard4255d502002-04-16 15:50:10 +00004822
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004823 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4824 attrDecl->refNs);
4825 if (ref == NULL) {
4826 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF,
4827 "Schemas: attribute %s reference %s not found\n",
4828 name, attrDecl->ref);
4829 return;
4830 }
4831 xmlSchemaAttrFixup(ref, ctxt, NULL);
4832 attrDecl->subtypes = ref->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +00004833 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004834 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF,
4835 "Schemas: attribute %s has no type nor reference\n",
4836 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004837 }
4838}
4839
4840/**
4841 * xmlSchemaParse:
4842 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004843 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004844 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004845 * XML Shema struture which can be used to validate instances.
4846 * *WARNING* this interface is highly subject to change
4847 *
4848 * Returns the internal XML Schema structure built from the resource or
4849 * NULL in case of error
4850 */
4851xmlSchemaPtr
4852xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4853{
4854 xmlSchemaPtr ret = NULL;
4855 xmlDocPtr doc;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004856 xmlNodePtr root;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004857 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00004858
4859 xmlSchemaInitTypes();
4860
Daniel Veillard6045c902002-10-09 21:13:59 +00004861 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004862 return (NULL);
4863
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004864 nberrors = ctxt->nberrors;
4865 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004866 ctxt->counter = 0;
4867 ctxt->container = NULL;
4868
4869 /*
4870 * First step is to parse the input document into an DOM/Infoset
4871 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004872 if (ctxt->URL != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004873 doc = xmlReadFile((const char *) ctxt->URL, NULL,
4874 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004875 if (doc == NULL) {
4876 xmlSchemaPErr(ctxt, NULL,
4877 XML_SCHEMAP_FAILED_LOAD,
4878 "xmlSchemaParse: could not load %s\n",
4879 ctxt->URL, NULL);
4880 return (NULL);
4881 }
Daniel Veillard6045c902002-10-09 21:13:59 +00004882 } else if (ctxt->buffer != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004883 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
4884 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004885 if (doc == NULL) {
4886 xmlSchemaPErr(ctxt, NULL,
4887 XML_SCHEMAP_FAILED_PARSE,
4888 "xmlSchemaParse: could not parse\n",
4889 NULL, NULL);
4890 return (NULL);
4891 }
4892 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4893 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard9d751502003-10-29 13:21:47 +00004894 } else if (ctxt->doc != NULL) {
4895 doc = ctxt->doc;
Daniel Veillard6045c902002-10-09 21:13:59 +00004896 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004897 xmlSchemaPErr(ctxt, NULL,
4898 XML_SCHEMAP_NOTHING_TO_PARSE,
4899 "xmlSchemaParse: could not parse\n",
4900 NULL, NULL);
4901 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004902 }
4903
4904 /*
4905 * Then extract the root and Schema parse it
4906 */
4907 root = xmlDocGetRootElement(doc);
4908 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004909 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
4910 XML_SCHEMAP_NOROOT,
4911 "schemas has no root", NULL, NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00004912 xmlFreeDoc(doc);
Daniel Veillard4255d502002-04-16 15:50:10 +00004913 return (NULL);
4914 }
4915
4916 /*
4917 * Remove all the blank text nodes
4918 */
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004919 xmlSchemaCleanupDoc(ctxt, root);
Daniel Veillard4255d502002-04-16 15:50:10 +00004920
4921 /*
4922 * Then do the parsing for good
4923 */
4924 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillard1d913862003-11-21 00:28:39 +00004925 if (ret == NULL) {
4926 xmlFreeDoc(doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004927 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00004928 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004929 ret->doc = doc;
4930
4931 /*
4932 * Then fix all the references.
4933 */
4934 ctxt->schema = ret;
4935 xmlHashScanFull(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004936 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004937
4938 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00004939 * Then fixup all attributes declarations
4940 */
4941 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4942
4943 /*
4944 * Then fixup all attributes group declarations
4945 */
4946 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup,
4947 ctxt);
4948
4949 /*
Daniel Veillard4255d502002-04-16 15:50:10 +00004950 * Then fixup all types properties
4951 */
4952 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
4953
4954 /*
4955 * Then build the content model for all elements
4956 */
4957 xmlHashScan(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004958 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004959
4960 /*
4961 * Then check the defaults part of the type like facets values
4962 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004963 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults,
4964 ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004965
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004966 if (ctxt->nberrors != 0) {
4967 xmlSchemaFree(ret);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004968 ret = NULL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004969 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004970 return (ret);
4971}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004972
Daniel Veillard4255d502002-04-16 15:50:10 +00004973/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004974 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00004975 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00004976 * @err: the error callback
4977 * @warn: the warning callback
4978 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00004979 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004980 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004981 */
4982void
4983xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004984 xmlSchemaValidityErrorFunc err,
4985 xmlSchemaValidityWarningFunc warn, void *ctx)
4986{
Daniel Veillard4255d502002-04-16 15:50:10 +00004987 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004988 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004989 ctxt->error = err;
4990 ctxt->warning = warn;
4991 ctxt->userData = ctx;
4992}
4993
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004994/**
4995 * xmlSchemaFacetTypeToString:
4996 * @type: the facet type
4997 *
4998 * Convert the xmlSchemaTypeType to a char string.
4999 *
5000 * Returns the char string representation of the facet type if the
5001 * type is a facet and an "Internal Error" string otherwise.
5002 */
5003static const char *
5004xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
5005{
5006 switch (type) {
5007 case XML_SCHEMA_FACET_PATTERN:
5008 return ("pattern");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005009 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005010 return ("maxExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005011 case XML_SCHEMA_FACET_MAXINCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005012 return ("maxInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005013 case XML_SCHEMA_FACET_MINEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005014 return ("minExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005015 case XML_SCHEMA_FACET_MININCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005016 return ("minInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005017 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005018 return ("whiteSpace");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005019 case XML_SCHEMA_FACET_ENUMERATION:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005020 return ("enumeration");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005021 case XML_SCHEMA_FACET_LENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005022 return ("length");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005023 case XML_SCHEMA_FACET_MAXLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005024 return ("maxLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005025 case XML_SCHEMA_FACET_MINLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005026 return ("minLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005027 case XML_SCHEMA_FACET_TOTALDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005028 return ("totalDigits");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005029 case XML_SCHEMA_FACET_FRACTIONDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005030 return ("fractionDigits");
5031 default:
5032 break;
5033 }
5034 return ("Internal Error");
5035}
5036
5037/**
5038 * xmlSchemaValidateFacets:
5039 * @ctxt: a schema validation context
5040 * @base: the base type
5041 * @facets: the list of facets to check
5042 * @value: the lexical repr of the value to validate
5043 * @val: the precomputed value
5044 *
5045 * Check a value against all facet conditions
5046 *
5047 * Returns 0 if the element is schemas valid, a positive error code
5048 * number otherwise and -1 in case of internal or API error.
5049 */
5050static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005051xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
5052 xmlSchemaTypePtr base,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005053 xmlSchemaFacetPtr facets, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005054{
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005055 int ret = 0;
5056 int tmp = 0;
5057 xmlSchemaTypeType type;
5058 xmlSchemaFacetPtr facet = facets;
5059
5060 while (facet != NULL) {
5061 type = facet->type;
5062 if (type == XML_SCHEMA_FACET_ENUMERATION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005063 tmp = 1;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005064
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005065 while (facet != NULL) {
5066 tmp =
5067 xmlSchemaValidateFacet(base, facet, value,
5068 ctxt->value);
5069 if (tmp == 0) {
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005070 return 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005071 }
5072 facet = facet->next;
5073 }
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005074 } else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005075 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005076
5077 if (tmp != 0) {
5078 ret = tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005079 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_FACET, "Failed to validate type with facet %s\n", (const xmlChar *) xmlSchemaFacetTypeToString(type), NULL);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005080 }
5081 if (facet != NULL)
5082 facet = facet->next;
5083 }
5084 return (ret);
5085}
5086
Daniel Veillard4255d502002-04-16 15:50:10 +00005087/************************************************************************
5088 * *
5089 * Simple type validation *
5090 * *
5091 ************************************************************************/
5092
5093/**
5094 * xmlSchemaValidateSimpleValue:
5095 * @ctxt: a schema validation context
5096 * @type: the type declaration
5097 * @value: the value to validate
5098 *
5099 * Validate a value against a simple type
5100 *
5101 * Returns 0 if the value is valid, a positive error code
5102 * number otherwise and -1 in case of internal or API error.
5103 */
5104static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005105xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005106 xmlSchemaTypePtr type, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005107{
Daniel Veillard4255d502002-04-16 15:50:10 +00005108 int ret = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005109
Daniel Veillard4255d502002-04-16 15:50:10 +00005110 /*
5111 * First normalize the value accordingly to Schema Datatype
5112 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
5113 */
5114 /*
5115 * Then check the normalized value against the lexical space of the
5116 * type.
5117 */
5118 if (type->type == XML_SCHEMA_TYPE_BASIC) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005119 if (ctxt->value != NULL) {
5120 xmlSchemaFreeValue(ctxt->value);
5121 ctxt->value = NULL;
5122 }
5123 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
5124 ctxt->cur);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005125 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005126 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, "Failed to validate basic type %s\n", type->name, NULL);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005127 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005128 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005129 xmlSchemaTypePtr base;
5130 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005131
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005132 base = type->baseType;
5133 if (base != NULL) {
5134 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5135 } else if (type->subtypes != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005136 TODO
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005137 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005138
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005139 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005140 * Do not validate facets or attributes when working on
5141 * building the Schemas
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005142 */
5143 if (ctxt->schema != NULL) {
5144 if (ret == 0) {
5145 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005146 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005147 }
5148 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005149 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005150 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00005151
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005152 base = type->subtypes;
5153 if (base != NULL) {
5154 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5155 } else {
5156 TODO}
Daniel Veillard4255d502002-04-16 15:50:10 +00005157 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005158 xmlSchemaTypePtr base;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005159 const xmlChar *cur, *end;
5160 xmlChar *tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005161 int ret2;
Daniel Veillard4255d502002-04-16 15:50:10 +00005162
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005163 base = type->subtypes;
5164 if (base == NULL) {
5165 xmlSchemaVErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL,
5166 "Internal: List type %s has no base type\n",
5167 type->name, NULL);
5168 return (-1);
5169 }
5170 cur = value;
5171 do {
William M. Brack76e95df2003-10-18 16:20:14 +00005172 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005173 cur++;
5174 end = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00005175 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005176 end++;
5177 if (end == cur)
5178 break;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005179 tmp = xmlStrndup(cur, end - cur);
5180 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, tmp);
5181 xmlFree(tmp);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005182 if (ret2 != 0)
5183 ret = 1;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005184 cur = end;
5185 } while (*cur != 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005186 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005187 TODO
5188 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005189 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005190}
5191
5192/************************************************************************
5193 * *
5194 * DOM Validation code *
5195 * *
5196 ************************************************************************/
5197
5198static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005199 xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005200static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005201 xmlNodePtr elem,
5202 xmlSchemaAttributePtr attributes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005203static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005204 xmlNodePtr elem,
5205 xmlSchemaElementPtr elemDecl,
5206 xmlSchemaTypePtr type);
Daniel Veillard4255d502002-04-16 15:50:10 +00005207
5208/**
5209 * xmlSchemaRegisterAttributes:
5210 * @ctxt: a schema validation context
5211 * @attrs: a list of attributes
5212 *
5213 * Register the list of attributes as the set to be validated on that element
5214 *
5215 * Returns -1 in case of error, 0 otherwise
5216 */
5217static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005218xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs)
5219{
Daniel Veillard4255d502002-04-16 15:50:10 +00005220 while (attrs != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005221 if ((attrs->ns != NULL) &&
5222 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
5223 attrs = attrs->next;
5224 continue;
5225 }
5226 if (ctxt->attrNr >= ctxt->attrMax) {
5227 xmlSchemaAttrStatePtr tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00005228
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005229 ctxt->attrMax *= 2;
5230 tmp = (xmlSchemaAttrStatePtr)
5231 xmlRealloc(ctxt->attr, ctxt->attrMax *
5232 sizeof(xmlSchemaAttrState));
5233 if (tmp == NULL) {
5234 xmlSchemaVErrMemory(ctxt, "registering attributes", NULL);
5235 ctxt->attrMax /= 2;
5236 return (-1);
5237 }
5238 ctxt->attr = tmp;
5239 }
5240 ctxt->attr[ctxt->attrNr].attr = attrs;
5241 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
5242 ctxt->attrNr++;
5243 attrs = attrs->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005244 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005245 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005246}
5247
5248/**
5249 * xmlSchemaCheckAttributes:
5250 * @ctxt: a schema validation context
5251 * @node: the node carrying it.
5252 *
5253 * Check that the registered set of attributes on the current node
5254 * has been properly validated.
5255 *
5256 * Returns 0 if validity constraints are met, 1 otherwise.
5257 */
5258static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005259xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5260{
Daniel Veillard4255d502002-04-16 15:50:10 +00005261 int ret = 0;
5262 int i;
5263
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005264 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
5265 if (ctxt->attr[i].attr == NULL)
5266 break;
5267 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
5268 ret = 1;
5269 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, "Attribute %s on %s is unknown\n", ctxt->attr[i].attr->name, node->name);
5270 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005271 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005272 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005273}
5274
5275/**
5276 * xmlSchemaValidateSimpleContent:
5277 * @ctxt: a schema validation context
5278 * @elem: an element
5279 * @type: the type declaration
5280 *
5281 * Validate the content of an element expected to be a simple type
5282 *
5283 * Returns 0 if the element is schemas valid, a positive error code
5284 * number otherwise and -1 in case of internal or API error.
5285 */
5286static int
5287xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005288 xmlNodePtr node ATTRIBUTE_UNUSED)
5289{
Daniel Veillard4255d502002-04-16 15:50:10 +00005290 xmlNodePtr child;
5291 xmlSchemaTypePtr type, base;
5292 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005293 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00005294
5295 child = ctxt->node;
5296 type = ctxt->type;
5297
5298 /*
5299 * Validation Rule: Element Locally Valid (Type): 3.1.3
5300 */
5301 value = xmlNodeGetContent(child);
5302 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
5303 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005304 case XML_SCHEMA_TYPE_RESTRICTION:{
5305 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005306
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005307 base = type->baseType;
5308 if (base != NULL) {
5309 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5310 } else {
5311 TODO}
5312 if (ret == 0) {
5313 facet = type->facets;
5314 ret =
5315 xmlSchemaValidateFacets(ctxt, base, facet, value);
5316 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005317 if ((ret == 0) && (type->attributes != NULL)) {
5318 ret = xmlSchemaValidateAttributes(ctxt, node,
5319 type->attributes);
5320 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005321 break;
5322 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005323 case XML_SCHEMA_TYPE_EXTENSION:{
5324 TODO
5325 break;
5326 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005327 default:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005328 TODO
5329 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005330 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005331 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005332
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005333 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005334}
5335
5336/**
5337 * xmlSchemaValidateCheckNodeList
5338 * @nodelist: the list of nodes
5339 *
5340 * Check the node list is only made of text nodes and entities pointing
5341 * to text nodes
5342 *
5343 * Returns 1 if true, 0 if false and -1 in case of error
5344 */
5345static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005346xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist)
5347{
Daniel Veillard4255d502002-04-16 15:50:10 +00005348 while (nodelist != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005349 if (nodelist->type == XML_ENTITY_REF_NODE) {
5350 TODO /* implement recursion in the entity content */
5351 }
5352 if ((nodelist->type != XML_TEXT_NODE) &&
5353 (nodelist->type != XML_COMMENT_NODE) &&
5354 (nodelist->type != XML_PI_NODE) &&
5355 (nodelist->type != XML_PI_NODE)) {
5356 return (0);
5357 }
5358 nodelist = nodelist->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005359 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005360 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005361}
5362
5363/**
5364 * xmlSchemaSkipIgnored:
5365 * @ctxt: a schema validation context
5366 * @type: the current type context
5367 * @node: the top node.
5368 *
5369 * Skip ignorable nodes in that context
5370 *
5371 * Returns the new sibling
5372 * number otherwise and -1 in case of internal or API error.
5373 */
5374static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00005375xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005376 xmlSchemaTypePtr type, xmlNodePtr node)
5377{
Daniel Veillard4255d502002-04-16 15:50:10 +00005378 int mixed = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005379
Daniel Veillard4255d502002-04-16 15:50:10 +00005380 /*
5381 * TODO complete and handle entities
5382 */
5383 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005384 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
Daniel Veillard4255d502002-04-16 15:50:10 +00005385 while ((node != NULL) &&
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005386 ((node->type == XML_COMMENT_NODE) ||
5387 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
5388 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
5389 (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) {
5390 node = node->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005391 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005392 return (node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005393}
5394
5395/**
5396 * xmlSchemaValidateCallback:
5397 * @ctxt: a schema validation context
5398 * @name: the name of the element detected (might be NULL)
5399 * @type: the type
5400 *
5401 * A transition has been made in the automata associated to an element
5402 * content model
5403 */
5404static void
5405xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005406 const xmlChar * name ATTRIBUTE_UNUSED,
5407 xmlSchemaTypePtr type, xmlNodePtr node)
5408{
Daniel Veillard4255d502002-04-16 15:50:10 +00005409 xmlSchemaTypePtr oldtype = ctxt->type;
5410 xmlNodePtr oldnode = ctxt->node;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005411
Daniel Veillard4255d502002-04-16 15:50:10 +00005412#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00005413 xmlGenericError(xmlGenericErrorContext,
5414 "xmlSchemaValidateCallback: %s, %s, %s\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005415 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005416#endif
5417 ctxt->type = type;
5418 ctxt->node = node;
5419 xmlSchemaValidateContent(ctxt, node);
5420 ctxt->type = oldtype;
5421 ctxt->node = oldnode;
5422}
5423
5424
5425#if 0
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005426
Daniel Veillard4255d502002-04-16 15:50:10 +00005427/**
5428 * xmlSchemaValidateSimpleRestrictionType:
5429 * @ctxt: a schema validation context
5430 * @node: the top node.
5431 *
5432 * Validate the content of a restriction type.
5433 *
5434 * Returns 0 if the element is schemas valid, a positive error code
5435 * number otherwise and -1 in case of internal or API error.
5436 */
5437static int
5438xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
5439 xmlNodePtr node)
5440{
5441 xmlNodePtr child;
5442 xmlSchemaTypePtr type;
5443 int ret;
5444
5445 child = ctxt->node;
5446 type = ctxt->type;
5447
5448 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005449 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005450 return (-1);
5451 }
5452 /*
5453 * Only text and text based entities references shall be found there
5454 */
5455 ret = xmlSchemaValidateCheckNodeList(child);
5456 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005457 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005458 return (-1);
5459 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005460 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, "Element %s content is not a simple type\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005461 return (-1);
5462 }
5463 ctxt->type = type->subtypes;
5464 xmlSchemaValidateContent(ctxt, node);
5465 ctxt->type = type;
5466 return (ret);
5467}
5468#endif
5469
5470/**
5471 * xmlSchemaValidateSimpleType:
5472 * @ctxt: a schema validation context
5473 * @node: the top node.
5474 *
5475 * Validate the content of an simple type.
5476 *
5477 * Returns 0 if the element is schemas valid, a positive error code
5478 * number otherwise and -1 in case of internal or API error.
5479 */
5480static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005481xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5482{
Daniel Veillard4255d502002-04-16 15:50:10 +00005483 xmlNodePtr child;
5484 xmlSchemaTypePtr type;
5485 xmlAttrPtr attr;
5486 int ret;
5487
5488 child = ctxt->node;
5489 type = ctxt->type;
5490
5491 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005492 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s\n", node->name, NULL);
5493 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005494 }
5495 /*
5496 * Only text and text based entities references shall be found there
5497 */
5498 ret = xmlSchemaValidateCheckNodeList(child);
5499 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005500 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
5501 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005502 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005503 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, "Element %s content is not a simple type\n", node->name, NULL);
5504 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005505 }
5506 /*
5507 * Validation Rule: Element Locally Valid (Type): 3.1.1
5508 */
5509 attr = node->properties;
5510 while (attr != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005511 if ((attr->ns == NULL) ||
5512 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
5513 ((!xmlStrEqual(attr->name, BAD_CAST "type")) &&
5514 (!xmlStrEqual(attr->name, BAD_CAST "nil")) &&
5515 (!xmlStrEqual(attr->name, BAD_CAST "schemasLocation")) &&
5516 (!xmlStrEqual
5517 (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) {
5518 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDATTR, "Element %s: attribute %s should not be present\n", node->name, attr->name);
5519 return (ctxt->err);
5520 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005521 }
5522
5523 ctxt->type = type->subtypes;
5524 ret = xmlSchemaValidateSimpleContent(ctxt, node);
5525 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005526 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005527}
5528
5529/**
5530 * xmlSchemaValidateElementType:
5531 * @ctxt: a schema validation context
5532 * @node: the top node.
5533 *
5534 * Validate the content of an element type.
5535 * Validation Rule: Element Locally Valid (Complex Type)
5536 *
5537 * Returns 0 if the element is schemas valid, a positive error code
5538 * number otherwise and -1 in case of internal or API error.
5539 */
5540static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005541xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5542{
Daniel Veillard4255d502002-04-16 15:50:10 +00005543 xmlNodePtr child;
5544 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005545 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
Daniel Veillard4255d502002-04-16 15:50:10 +00005546 xmlSchemaElementPtr decl;
5547 int ret, attrBase;
5548
5549 oldregexp = ctxt->regexp;
5550
5551 child = ctxt->node;
5552 type = ctxt->type;
5553
5554 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005555 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateElementType\n", node->name, NULL);
5556 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005557 }
5558 if (child == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005559 if (type->minOccurs > 0) {
5560 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, "Element %s: missing child %s\n", node->name, type->name);
5561 }
5562 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005563 }
5564
5565 /*
5566 * Verify the element matches
5567 */
5568 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005569 xmlSchemaVErr3(ctxt, node, XML_SCHEMAS_ERR_WRONGELEM, "Element %s: missing child %s found %s\n", node->name, type->name, child->name);
5570 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005571 }
5572 /*
5573 * Verify the attributes
5574 */
5575 attrBase = ctxt->attrBase;
5576 ctxt->attrBase = ctxt->attrNr;
5577 xmlSchemaRegisterAttributes(ctxt, child->properties);
5578 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
5579 /*
5580 * Verify the element content recursively
5581 */
5582 decl = (xmlSchemaElementPtr) type;
5583 oldregexp = ctxt->regexp;
5584 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005585 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5586 (xmlRegExecCallbacks)
5587 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005588#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005589 xmlGenericError(xmlGenericErrorContext, "====> %s\n", node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005590#endif
5591 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005592 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr) type,
5593 type->subtypes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005594
5595 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005596 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005597#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005598 xmlGenericError(xmlGenericErrorContext,
5599 "====> %s : %d\n", node->name, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005600#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005601 if (ret == 0) {
5602 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", node->name, NULL);
5603 } else if (ret < 0) {
5604 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failure\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005605#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005606 } else {
5607 xmlGenericError(xmlGenericErrorContext,
5608 "Element %s content check succeeded\n",
5609 node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005610
5611#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005612 }
5613 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00005614 }
5615 /*
5616 * Verify that all attributes were Schemas-validated
5617 */
5618 xmlSchemaCheckAttributes(ctxt, node);
5619 ctxt->attrNr = ctxt->attrBase;
5620 ctxt->attrBase = attrBase;
5621
5622 ctxt->regexp = oldregexp;
5623
5624 ctxt->node = child;
5625 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005626 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005627}
5628
5629/**
5630 * xmlSchemaValidateBasicType:
5631 * @ctxt: a schema validation context
5632 * @node: the top node.
5633 *
5634 * Validate the content of an element expected to be a basic type type
5635 *
5636 * Returns 0 if the element is schemas valid, a positive error code
5637 * number otherwise and -1 in case of internal or API error.
5638 */
5639static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005640xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5641{
Daniel Veillard4255d502002-04-16 15:50:10 +00005642 int ret;
5643 xmlNodePtr child, cur;
5644 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005645 xmlChar *value; /* lexical representation */
Daniel Veillard4255d502002-04-16 15:50:10 +00005646
5647 child = ctxt->node;
5648 type = ctxt->type;
5649
5650 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005651 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateBasicType\n", node->name, NULL);
5652 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005653 }
5654 /*
5655 * First check the content model of the node.
5656 */
5657 cur = child;
5658 while (cur != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005659 switch (cur->type) {
5660 case XML_TEXT_NODE:
5661 case XML_CDATA_SECTION_NODE:
5662 case XML_PI_NODE:
5663 case XML_COMMENT_NODE:
5664 case XML_XINCLUDE_START:
5665 case XML_XINCLUDE_END:
5666 break;
5667 case XML_ENTITY_REF_NODE:
5668 case XML_ENTITY_NODE:
5669 TODO break;
5670 case XML_ELEMENT_NODE:
5671 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: child %s should not be present\n", node->name, cur->name);
5672 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005673 case XML_ATTRIBUTE_NODE:
5674 case XML_DOCUMENT_NODE:
5675 case XML_DOCUMENT_TYPE_NODE:
5676 case XML_DOCUMENT_FRAG_NODE:
5677 case XML_NOTATION_NODE:
5678 case XML_HTML_DOCUMENT_NODE:
5679 case XML_DTD_NODE:
5680 case XML_ELEMENT_DECL:
5681 case XML_ATTRIBUTE_DECL:
5682 case XML_ENTITY_DECL:
5683 case XML_NAMESPACE_DECL:
5684#ifdef LIBXML_DOCB_ENABLED
5685 case XML_DOCB_DOCUMENT_NODE:
5686#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005687 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: node type of node unexpected here\n", node->name, NULL);
5688 return (ctxt->err);
5689 }
5690 cur = cur->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005691 }
5692 if (child == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005693 value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005694 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005695 value = xmlNodeGetContent(child->parent);
Daniel Veillard4255d502002-04-16 15:50:10 +00005696
5697 if (ctxt->value != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005698 xmlSchemaFreeValue(ctxt->value);
5699 ctxt->value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005700 }
5701 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5702 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005703 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005704 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005705 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_VALUE, "Element %s: failed to validate basic type %s\n", node->name, type->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005706 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005707 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005708}
5709
5710/**
5711 * xmlSchemaValidateComplexType:
5712 * @ctxt: a schema validation context
5713 * @node: the top node.
5714 *
5715 * Validate the content of an element expected to be a complex type type
5716 * xmlschema-1.html#cvc-complex-type
5717 * Validation Rule: Element Locally Valid (Complex Type)
5718 *
5719 * Returns 0 if the element is schemas valid, a positive error code
5720 * number otherwise and -1 in case of internal or API error.
5721 */
5722static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005723xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5724{
Daniel Veillard4255d502002-04-16 15:50:10 +00005725 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005726 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005727 int ret;
5728
5729 child = ctxt->node;
5730 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005731 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005732
Daniel Veillard4255d502002-04-16 15:50:10 +00005733 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005734 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005735 if (type->baseType != NULL) {
5736 } else if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005737 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is supposed to be empty\n", node->name, NULL);
5738 }
5739 if (type->attributes != NULL) {
5740 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5741 }
5742 subtype = type->subtypes;
5743 while (subtype != NULL) {
5744 ctxt->type = subtype;
5745 xmlSchemaValidateComplexType(ctxt, node);
5746 subtype = subtype->next;
5747 }
5748 break;
5749 case XML_SCHEMA_CONTENT_ELEMENTS:
5750 case XML_SCHEMA_CONTENT_MIXED:
5751 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5752 /*
5753 * Skip ignorable nodes in that context
5754 */
5755 child = xmlSchemaSkipIgnored(ctxt, type, child);
5756 while (child != NULL) {
5757 if (child->type == XML_ELEMENT_NODE) {
5758 ret = xmlRegExecPushString(ctxt->regexp,
5759 child->name, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005760#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005761 if (ret < 0)
5762 xmlGenericError(xmlGenericErrorContext,
5763 " --> %s Error\n", child->name);
5764 else
5765 xmlGenericError(xmlGenericErrorContext,
5766 " --> %s\n", child->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005767#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005768 }
5769 child = child->next;
5770 /*
5771 * Skip ignorable nodes in that context
5772 */
5773 child = xmlSchemaSkipIgnored(ctxt, type, child);
5774 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005775 if (type->attributes != NULL) {
5776 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5777 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005778 break;
5779 case XML_SCHEMA_CONTENT_BASIC:{
5780 if (type->subtypes != NULL) {
5781 ctxt->type = type->subtypes;
5782 xmlSchemaValidateComplexType(ctxt, node);
5783 }
5784 if (type->baseType != NULL) {
5785 ctxt->type = type->baseType;
5786 xmlSchemaValidateBasicType(ctxt, node);
5787 }
5788 if (type->attributes != NULL) {
5789 xmlSchemaValidateAttributes(ctxt, node,
5790 type->attributes);
5791 }
5792 ctxt->type = type;
5793 break;
5794 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005795 case XML_SCHEMA_CONTENT_SIMPLE:{
5796 if (type->subtypes != NULL) {
5797 ctxt->type = type->subtypes;
5798 xmlSchemaValidateComplexType(ctxt, node);
5799 }
5800 if (type->baseType != NULL) {
5801 ctxt->type = type->baseType;
5802 xmlSchemaValidateComplexType(ctxt, node);
5803 }
5804 if (type->attributes != NULL) {
5805 xmlSchemaValidateAttributes(ctxt, node,
5806 type->attributes);
5807 }
5808 ctxt->type = type;
5809 break;
5810 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005811 default:
5812 TODO xmlGenericError(xmlGenericErrorContext,
5813 "unimplemented content type %d\n",
5814 type->contentType);
Daniel Veillard4255d502002-04-16 15:50:10 +00005815 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005816 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005817}
5818
5819/**
5820 * xmlSchemaValidateContent:
5821 * @ctxt: a schema validation context
5822 * @elem: an element
5823 * @type: the type declaration
5824 *
5825 * Validate the content of an element against the type.
5826 *
5827 * Returns 0 if the element is schemas valid, a positive error code
5828 * number otherwise and -1 in case of internal or API error.
5829 */
5830static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005831xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5832{
Daniel Veillard4255d502002-04-16 15:50:10 +00005833 xmlNodePtr child;
5834 xmlSchemaTypePtr type;
5835
5836 child = ctxt->node;
5837 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005838 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005839
Daniel Veillarde19fc232002-04-22 16:01:24 +00005840 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005841 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00005842
Daniel Veillard4255d502002-04-16 15:50:10 +00005843 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005844 case XML_SCHEMA_TYPE_ANY:
5845 /* Any type will do it, fine */
5846 TODO /* handle recursivity */
5847 break;
5848 case XML_SCHEMA_TYPE_COMPLEX:
5849 xmlSchemaValidateComplexType(ctxt, node);
5850 break;
5851 case XML_SCHEMA_TYPE_ELEMENT:{
5852 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
5853
5854 /*
5855 * Handle element reference here
5856 */
5857 if (decl->ref != NULL) {
5858 if (decl->refDecl == NULL) {
5859 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: element reference %s not resolved\n", decl->ref, NULL);
5860 return (-1);
5861 }
5862 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
5863 decl = decl->refDecl;
5864 }
5865 xmlSchemaValidateElementType(ctxt, node);
5866 ctxt->type = type;
5867 break;
5868 }
5869 case XML_SCHEMA_TYPE_BASIC:
5870 xmlSchemaValidateBasicType(ctxt, node);
5871 break;
5872 case XML_SCHEMA_TYPE_FACET:
5873 TODO break;
5874 case XML_SCHEMA_TYPE_SIMPLE:
5875 xmlSchemaValidateSimpleType(ctxt, node);
5876 break;
5877 case XML_SCHEMA_TYPE_SEQUENCE:
5878 TODO break;
5879 case XML_SCHEMA_TYPE_CHOICE:
5880 TODO break;
5881 case XML_SCHEMA_TYPE_ALL:
5882 TODO break;
5883 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5884 TODO break;
5885 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5886 TODO break;
5887 case XML_SCHEMA_TYPE_UR:
5888 TODO break;
5889 case XML_SCHEMA_TYPE_RESTRICTION:
5890 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5891 TODO break;
5892 case XML_SCHEMA_TYPE_EXTENSION:
5893 TODO break;
5894 case XML_SCHEMA_TYPE_ATTRIBUTE:
5895 TODO break;
5896 case XML_SCHEMA_TYPE_GROUP:
5897 TODO break;
5898 case XML_SCHEMA_TYPE_NOTATION:
5899 TODO break;
5900 case XML_SCHEMA_TYPE_LIST:
5901 TODO break;
5902 case XML_SCHEMA_TYPE_UNION:
5903 TODO break;
5904 case XML_SCHEMA_FACET_MININCLUSIVE:
5905 TODO break;
5906 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5907 TODO break;
5908 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5909 TODO break;
5910 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5911 TODO break;
5912 case XML_SCHEMA_FACET_TOTALDIGITS:
5913 TODO break;
5914 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5915 TODO break;
5916 case XML_SCHEMA_FACET_PATTERN:
5917 TODO break;
5918 case XML_SCHEMA_FACET_ENUMERATION:
5919 TODO break;
5920 case XML_SCHEMA_FACET_WHITESPACE:
5921 TODO break;
5922 case XML_SCHEMA_FACET_LENGTH:
5923 TODO break;
5924 case XML_SCHEMA_FACET_MAXLENGTH:
5925 TODO break;
5926 case XML_SCHEMA_FACET_MINLENGTH:
5927 TODO break;
5928 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5929 TODO break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005930 }
5931 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5932
5933 if (ctxt->node == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005934 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005935 ctxt->node = ctxt->node->next;
5936 ctxt->type = type->next;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005937 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005938}
5939
5940/**
5941 * xmlSchemaValidateType:
5942 * @ctxt: a schema validation context
5943 * @elem: an element
5944 * @type: the list of type declarations
5945 *
5946 * Validate the content of an element against the types.
5947 *
5948 * Returns 0 if the element is schemas valid, a positive error code
5949 * number otherwise and -1 in case of internal or API error.
5950 */
5951static int
5952xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005953 xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type)
5954{
Daniel Veillard4255d502002-04-16 15:50:10 +00005955 xmlChar *nil;
5956
Daniel Veillard2db8c122003-07-08 12:16:59 +00005957 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005958 return (0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00005959
Daniel Veillard4255d502002-04-16 15:50:10 +00005960 /*
5961 * 3.3.4 : 2
5962 */
5963 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005964 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, "Element %s is abstract\n", elem->name, NULL);
5965 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005966 }
5967 /*
5968 * 3.3.4: 3
5969 */
5970 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5971 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005972 /* 3.3.4: 3.2 */
5973 if (xmlStrEqual(nil, BAD_CAST "true")) {
5974 if (elem->children != NULL) {
5975 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is not empty\n", elem->name, NULL);
5976 return (ctxt->err);
5977 }
5978 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5979 (elemDecl->value != NULL)) {
5980 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_HAVEDEFAULT, "Empty element %s cannot get a fixed value\n", elem->name, NULL);
5981 return (ctxt->err);
5982 }
5983 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005984 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005985 /* 3.3.4: 3.1 */
5986 if (nil != NULL) {
5987 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTNILLABLE, "Element %s with xs:nil but not nillable\n", elem->name, NULL);
5988 xmlFree(nil);
5989 return (ctxt->err);
5990 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005991 }
5992
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005993 /* TODO 3.3.4: 4 if the element carries xs:type */
Daniel Veillard4255d502002-04-16 15:50:10 +00005994
5995 ctxt->type = elemDecl->subtypes;
5996 ctxt->node = elem->children;
5997 xmlSchemaValidateContent(ctxt, elem);
5998 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005999
6000 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006001}
6002
6003
6004/**
6005 * xmlSchemaValidateAttributes:
6006 * @ctxt: a schema validation context
6007 * @elem: an element
6008 * @attributes: the list of attribute declarations
6009 *
6010 * Validate the attributes of an element.
6011 *
6012 * Returns 0 if the element is schemas valid, a positive error code
6013 * number otherwise and -1 in case of internal or API error.
6014 */
6015static int
6016xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006017 xmlSchemaAttributePtr attributes)
6018{
Daniel Veillard4255d502002-04-16 15:50:10 +00006019 int i, ret;
6020 xmlAttrPtr attr;
6021 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00006022 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00006023
6024 if (attributes == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006025 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006026 while (attributes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006027 /*
6028 * Handle attribute groups
6029 */
6030 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
6031 group = (xmlSchemaAttributeGroupPtr) attributes;
6032 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
6033 attributes = group->next;
6034 continue;
6035 }
6036 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
6037 attr = ctxt->attr[i].attr;
6038 if (attr == NULL)
6039 continue;
6040 if (attributes->ref != NULL) {
6041 if (!xmlStrEqual(attr->name, attributes->ref))
6042 continue;
6043 if (attr->ns != NULL) {
6044 if ((attributes->refNs == NULL) ||
6045 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
6046 continue;
6047 } else if (attributes->refNs != NULL) {
6048 continue;
6049 }
6050 } else {
6051 if (!xmlStrEqual(attr->name, attributes->name))
6052 continue;
6053 /*
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006054 * handle the namespaces checks here
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006055 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006056 if (attr->ns == NULL) {
6057 /*
6058 * accept an unqualified attribute only if the declaration
6059 * is unqualified or if the schemas allowed it.
6060 */
6061 if ((attributes->targetNamespace != NULL) &&
6062 ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0))
6063 continue;
6064 } else {
6065 if (attributes->targetNamespace == NULL)
6066 continue;
6067 if (!xmlStrEqual(attributes->targetNamespace,
6068 attr->ns->href))
6069 continue;
6070 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006071 }
6072 ctxt->cur = (xmlNodePtr) attributes;
6073 if (attributes->subtypes == NULL) {
6074 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL);
6075 continue;
6076 }
6077 value = xmlNodeListGetString(elem->doc, attr->children, 1);
6078 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
6079 value);
6080 if (ret != 0) {
6081 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_ATTRINVALID, "attribute %s on %s does not match type\n", attr->name, elem->name);
6082 } else {
6083 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
6084 }
6085 if (value != NULL) {
6086 xmlFree(value);
6087 }
6088 }
6089 attributes = attributes->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00006090 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006091 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006092}
6093
6094/**
6095 * xmlSchemaValidateElement:
6096 * @ctxt: a schema validation context
6097 * @elem: an element
6098 *
6099 * Validate an element in a tree
6100 *
6101 * Returns 0 if the element is schemas valid, a positive error code
6102 * number otherwise and -1 in case of internal or API error.
6103 */
6104static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006105xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem)
6106{
Daniel Veillard4255d502002-04-16 15:50:10 +00006107 xmlSchemaElementPtr elemDecl;
6108 int ret, attrBase;
6109
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006110 if (elem->ns != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006111 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6112 elem->name, elem->ns->href, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006113 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006114 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6115 elem->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006116 }
6117 /*
6118 * special case whe elementFormDefault is unqualified for top-level elem.
6119 */
6120 if ((elemDecl == NULL) && (elem->ns != NULL) &&
6121 (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) &&
6122 (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) &&
6123 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6124 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6125 elem->name, NULL, NULL);
6126 }
6127
Daniel Veillard4255d502002-04-16 15:50:10 +00006128 /*
6129 * 3.3.4 : 1
6130 */
6131 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006132 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", elem->name, NULL);
6133 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006134 }
6135 if (elemDecl->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006136 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTYPE, "Element %s has no type\n", elem->name, NULL);
6137 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006138 }
6139 /*
6140 * Verify the attributes
6141 */
6142 attrBase = ctxt->attrBase;
6143 ctxt->attrBase = ctxt->attrNr;
6144 xmlSchemaRegisterAttributes(ctxt, elem->properties);
6145 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
6146 /*
6147 * Verify the element content recursively
6148 */
6149 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006150 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
6151 (xmlRegExecCallbacks)
6152 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00006153#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006154 xmlGenericError(xmlGenericErrorContext, "====> %s\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006155#endif
6156 }
6157 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006158 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006159 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006160#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006161 xmlGenericError(xmlGenericErrorContext,
6162 "====> %s : %d\n", elem->name, ret);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006163#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006164 if (ret == 0) {
6165 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
6166 } else if (ret < 0) {
6167 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006168#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006169 } else {
6170 xmlGenericError(xmlGenericErrorContext,
6171 "Element %s content check succeeded\n",
6172 elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006173
6174#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006175 }
6176 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00006177 }
6178 /*
6179 * Verify that all attributes were Schemas-validated
6180 */
6181 xmlSchemaCheckAttributes(ctxt, elem);
6182 ctxt->attrNr = ctxt->attrBase;
6183 ctxt->attrBase = attrBase;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006184
6185 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006186}
6187
6188/**
6189 * xmlSchemaValidateDocument:
6190 * @ctxt: a schema validation context
6191 * @doc: a parsed document tree
6192 *
6193 * Validate a document tree in memory.
6194 *
6195 * Returns 0 if the document is schemas valid, a positive error code
6196 * number otherwise and -1 in case of internal or API error.
6197 */
6198static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006199xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6200{
Daniel Veillard4255d502002-04-16 15:50:10 +00006201 xmlNodePtr root;
6202 xmlSchemaElementPtr elemDecl;
6203
6204 root = xmlDocGetRootElement(doc);
6205 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006206 xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, "document has no root\n", NULL, NULL);
6207 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006208 }
6209 if (root->ns != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006210 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6211 root->name, root->ns->href, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006212 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006213 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6214 root->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006215 /*
6216 * special case whe elementFormDefault is unqualified for top-level elem.
6217 */
6218 if ((elemDecl == NULL) && (root->ns != NULL) &&
6219 (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) &&
6220 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6221 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6222 root->name, NULL, NULL);
6223 }
6224
Daniel Veillard4255d502002-04-16 15:50:10 +00006225 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006226 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", root->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006227 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006228 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, "Root element %s not toplevel\n", root->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006229 }
6230 /*
6231 * Okay, start the recursive validation
6232 */
6233 xmlSchemaValidateElement(ctxt, root);
6234
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006235 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006236}
6237
6238/************************************************************************
6239 * *
6240 * SAX Validation code *
6241 * *
6242 ************************************************************************/
6243
6244/************************************************************************
6245 * *
6246 * Validation interfaces *
6247 * *
6248 ************************************************************************/
6249
6250/**
6251 * xmlSchemaNewValidCtxt:
6252 * @schema: a precompiled XML Schemas
6253 *
6254 * Create an XML Schemas validation context based on the given schema
6255 *
6256 * Returns the validation context or NULL in case of error
6257 */
6258xmlSchemaValidCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006259xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
6260{
Daniel Veillard4255d502002-04-16 15:50:10 +00006261 xmlSchemaValidCtxtPtr ret;
6262
6263 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
6264 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006265 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006266 return (NULL);
6267 }
6268 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
6269 ret->schema = schema;
6270 ret->attrNr = 0;
6271 ret->attrMax = 10;
6272 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006273 sizeof
6274 (xmlSchemaAttrState));
Daniel Veillard4255d502002-04-16 15:50:10 +00006275 if (ret->attr == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006276 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
6277 free(ret);
6278 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006279 }
6280 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
6281 return (ret);
6282}
6283
6284/**
6285 * xmlSchemaFreeValidCtxt:
6286 * @ctxt: the schema validation context
6287 *
6288 * Free the resources associated to the schema validation context
6289 */
6290void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006291xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
6292{
Daniel Veillard4255d502002-04-16 15:50:10 +00006293 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006294 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006295 if (ctxt->attr != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006296 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00006297 if (ctxt->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006298 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00006299 xmlFree(ctxt);
6300}
6301
6302/**
6303 * xmlSchemaSetValidErrors:
6304 * @ctxt: a schema validation context
6305 * @err: the error function
6306 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00006307 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00006308 *
6309 * Set the error and warning callback informations
6310 */
6311void
6312xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006313 xmlSchemaValidityErrorFunc err,
6314 xmlSchemaValidityWarningFunc warn, void *ctx)
6315{
Daniel Veillard4255d502002-04-16 15:50:10 +00006316 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006317 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006318 ctxt->error = err;
6319 ctxt->warning = warn;
6320 ctxt->userData = ctx;
6321}
6322
6323/**
6324 * xmlSchemaValidateDoc:
6325 * @ctxt: a schema validation context
6326 * @doc: a parsed document tree
6327 *
6328 * Validate a document tree in memory.
6329 *
6330 * Returns 0 if the document is schemas valid, a positive error code
6331 * number otherwise and -1 in case of internal or API error.
6332 */
6333int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006334xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6335{
Daniel Veillard4255d502002-04-16 15:50:10 +00006336 int ret;
6337
6338 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006339 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006340
6341 ctxt->doc = doc;
6342 ret = xmlSchemaValidateDocument(ctxt, doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006343 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00006344}
6345
6346/**
6347 * xmlSchemaValidateStream:
6348 * @ctxt: a schema validation context
6349 * @input: the input to use for reading the data
6350 * @enc: an optional encoding information
6351 * @sax: a SAX handler for the resulting events
6352 * @user_data: the context to provide to the SAX handler.
6353 *
6354 * Validate a document tree in memory.
6355 *
6356 * Returns 0 if the document is schemas valid, a positive error code
6357 * number otherwise and -1 in case of internal or API error.
6358 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006359int
Daniel Veillard4255d502002-04-16 15:50:10 +00006360xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006361 xmlParserInputBufferPtr input, xmlCharEncoding enc,
6362 xmlSAXHandlerPtr sax, void *user_data)
6363{
Daniel Veillard4255d502002-04-16 15:50:10 +00006364 if ((ctxt == NULL) || (input == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006365 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006366 ctxt->input = input;
6367 ctxt->enc = enc;
6368 ctxt->sax = sax;
6369 ctxt->user_data = user_data;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006370 TODO return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006371}
6372
6373#endif /* LIBXML_SCHEMAS_ENABLED */