blob: 7823de01897428a5d408c65d81f555eb4ba72b97 [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 Veillarddda22c12004-01-24 08:31:30 +000088 int preserve; /* Whether the doc should be freed */
Daniel Veillard4255d502002-04-16 15:50:10 +000089
Daniel Veillardd0c9c322003-10-10 00:49:42 +000090 const char *buffer;
91 int size;
Daniel Veillard6045c902002-10-09 21:13:59 +000092
Daniel Veillard4255d502002-04-16 15:50:10 +000093 /*
94 * Used to build complex element content models
95 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000096 xmlAutomataPtr am;
Daniel Veillard4255d502002-04-16 15:50:10 +000097 xmlAutomataStatePtr start;
98 xmlAutomataStatePtr end;
99 xmlAutomataStatePtr state;
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000100
101 xmlDictPtr dict; /* dictionnary for interned string names */
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000102 int includes; /* the inclusion level, 0 for root or imports */
Daniel Veillard4255d502002-04-16 15:50:10 +0000103};
104
105
106#define XML_SCHEMAS_ATTR_UNKNOWN 1
107#define XML_SCHEMAS_ATTR_CHECKED 2
108
109typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
110typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
111struct _xmlSchemaAttrState {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000112 xmlAttrPtr attr;
113 int state;
Daniel Veillard4255d502002-04-16 15:50:10 +0000114};
115
116/**
117 * xmlSchemaValidCtxt:
118 *
119 * A Schemas validation context
120 */
121
122struct _xmlSchemaValidCtxt {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000123 void *userData; /* user specific data block */
124 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
125 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000126 xmlStructuredErrorFunc serror;
Daniel Veillard4255d502002-04-16 15:50:10 +0000127
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000128 xmlSchemaPtr schema; /* The schema in use */
129 xmlDocPtr doc;
Daniel Veillard4255d502002-04-16 15:50:10 +0000130 xmlParserInputBufferPtr input;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000131 xmlCharEncoding enc;
132 xmlSAXHandlerPtr sax;
133 void *user_data;
Daniel Veillard4255d502002-04-16 15:50:10 +0000134
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000135 xmlDocPtr myDoc;
136 int err;
137 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +0000138
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000139 xmlNodePtr node;
140 xmlNodePtr cur;
141 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000142
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000143 xmlRegExecCtxtPtr regexp;
144 xmlSchemaValPtr value;
Daniel Veillard4255d502002-04-16 15:50:10 +0000145
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000146 int attrNr;
147 int attrBase;
148 int attrMax;
149 xmlSchemaAttrStatePtr attr;
Daniel Veillard4255d502002-04-16 15:50:10 +0000150};
151
Daniel Veillard1d913862003-11-21 00:28:39 +0000152/*
153 * These are the entries in the schemas importSchemas hash table
154 */
155typedef struct _xmlSchemaImport xmlSchemaImport;
156typedef xmlSchemaImport *xmlSchemaImportPtr;
157struct _xmlSchemaImport {
158 const xmlChar *schemaLocation;
159 xmlSchemaPtr schema;
160};
Daniel Veillard4255d502002-04-16 15:50:10 +0000161
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000162/*
163 * These are the entries associated to includes in a schemas
164 */
165typedef struct _xmlSchemaInclude xmlSchemaInclude;
166typedef xmlSchemaInclude *xmlSchemaIncludePtr;
167struct _xmlSchemaInclude {
168 xmlSchemaIncludePtr next;
169
170 const xmlChar *schemaLocation;
171 xmlDocPtr doc;
172};
173
Daniel Veillard4255d502002-04-16 15:50:10 +0000174/************************************************************************
175 * *
176 * Some predeclarations *
177 * *
178 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000179static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
180 xmlSchemaTypePtr type,
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000181 const xmlChar * value);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000182
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000183static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt,
184 xmlSchemaPtr schema,
185 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000186/************************************************************************
187 * *
188 * Datatype error handlers *
189 * *
190 ************************************************************************/
191
192/**
193 * xmlSchemaPErrMemory:
194 * @node: a context node
195 * @extra: extra informations
196 *
197 * Handle an out of memory condition
198 */
199static void
200xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt,
201 const char *extra, xmlNodePtr node)
202{
203 if (ctxt != NULL)
204 ctxt->nberrors++;
205 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
206 extra);
207}
208
209/**
210 * xmlSchemaPErr:
211 * @ctxt: the parsing context
212 * @node: the context node
213 * @error: the error code
214 * @msg: the error message
215 * @str1: extra data
216 * @str2: extra data
217 *
218 * Handle a parser error
219 */
220static void
221xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error,
222 const char *msg, const xmlChar * str1, const xmlChar * str2)
223{
224 xmlGenericErrorFunc channel = NULL;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000225 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000226 void *data = NULL;
227
228 if (ctxt != NULL) {
229 ctxt->nberrors++;
230 channel = ctxt->error;
231 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000232 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000233 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000234 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000235 error, XML_ERR_ERROR, NULL, 0,
236 (const char *) str1, (const char *) str2, NULL, 0, 0,
237 msg, str1, str2);
238}
239
240/**
241 * xmlSchemaPErr2:
242 * @ctxt: the parsing context
243 * @node: the context node
244 * @node: the current child
245 * @error: the error code
246 * @msg: the error message
247 * @str1: extra data
248 * @str2: extra data
249 *
250 * Handle a parser error
251 */
252static void
253xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
254 xmlNodePtr child, int error,
255 const char *msg, const xmlChar * str1, const xmlChar * str2)
256{
257 if (child != NULL)
258 xmlSchemaPErr(ctxt, child, error, msg, str1, str2);
259 else
260 xmlSchemaPErr(ctxt, node, error, msg, str1, str2);
261}
262
263/**
264 * xmlSchemaVTypeErrMemory:
265 * @node: a context node
266 * @extra: extra informations
267 *
268 * Handle an out of memory condition
269 */
270static void
271xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt,
272 const char *extra, xmlNodePtr node)
273{
274 if (ctxt != NULL) {
275 ctxt->nberrors++;
276 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
277 }
278 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
279 extra);
280}
281
282/**
283 * xmlSchemaVErr3:
284 * @ctxt: the validation context
285 * @node: the context node
286 * @error: the error code
287 * @msg: the error message
288 * @str1: extra data
289 * @str2: extra data
290 * @str3: extra data
291 *
292 * Handle a validation error
293 */
294static void
295xmlSchemaVErr3(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
296 const char *msg, const xmlChar *str1, const xmlChar *str2,
297 const xmlChar *str3)
298{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000299 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000300 xmlGenericErrorFunc channel = NULL;
301 void *data = NULL;
302
303 if (ctxt != NULL) {
304 ctxt->nberrors++;
305 ctxt->err = error;
306 channel = ctxt->error;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000308 data = ctxt->userData;
309 }
310 /* reajust to global error numbers */
311 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000312 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000313 error, XML_ERR_ERROR, NULL, 0,
314 (const char *) str1, (const char *) str2,
315 (const char *) str3, 0, 0,
316 msg, str1, str2, str3);
317}
318/**
319 * xmlSchemaVErr:
320 * @ctxt: the validation context
321 * @node: the context node
322 * @error: the error code
323 * @msg: the error message
324 * @str1: extra data
325 * @str2: extra data
326 *
327 * Handle a validation error
328 */
329static void
330xmlSchemaVErr(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
331 const char *msg, const xmlChar * str1, const xmlChar * str2)
332{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000333 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000334 xmlGenericErrorFunc channel = NULL;
335 void *data = NULL;
336
337 if (ctxt != NULL) {
338 ctxt->nberrors++;
339 ctxt->err = error;
340 channel = ctxt->error;
341 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000342 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000343 }
344 /* reajust to global error numbers */
345 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000346 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000347 error, XML_ERR_ERROR, NULL, 0,
348 (const char *) str1, (const char *) str2, NULL, 0, 0,
349 msg, str1, str2);
350}
Daniel Veillard4255d502002-04-16 15:50:10 +0000351
352/************************************************************************
353 * *
354 * Allocation functions *
355 * *
356 ************************************************************************/
357
358/**
359 * xmlSchemaNewSchema:
William M. Brack08171912003-12-29 02:52:11 +0000360 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +0000361 *
362 * Allocate a new Schema structure.
363 *
364 * Returns the newly allocated structure or NULL in case or error
365 */
366static xmlSchemaPtr
367xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
368{
369 xmlSchemaPtr ret;
370
371 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
372 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000373 xmlSchemaPErrMemory(ctxt, "allocating schema", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +0000374 return (NULL);
375 }
376 memset(ret, 0, sizeof(xmlSchema));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000377 ret->dict = ctxt->dict;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000378 xmlDictReference(ret->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +0000379
380 return (ret);
381}
382
383/**
384 * xmlSchemaNewFacet:
Daniel Veillard4255d502002-04-16 15:50:10 +0000385 *
386 * Allocate a new Facet structure.
387 *
388 * Returns the newly allocated structure or NULL in case or error
389 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000390xmlSchemaFacetPtr
391xmlSchemaNewFacet(void)
Daniel Veillard4255d502002-04-16 15:50:10 +0000392{
393 xmlSchemaFacetPtr ret;
394
395 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
396 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000397 return (NULL);
398 }
399 memset(ret, 0, sizeof(xmlSchemaFacet));
400
401 return (ret);
402}
403
404/**
405 * xmlSchemaNewAnnot:
William M. Brack08171912003-12-29 02:52:11 +0000406 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +0000407 * @node: a node
408 *
409 * Allocate a new annotation structure.
410 *
411 * Returns the newly allocated structure or NULL in case or error
412 */
413static xmlSchemaAnnotPtr
414xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
415{
416 xmlSchemaAnnotPtr ret;
417
418 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
419 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000420 xmlSchemaPErrMemory(ctxt, "allocating annotation", node);
Daniel Veillard4255d502002-04-16 15:50:10 +0000421 return (NULL);
422 }
423 memset(ret, 0, sizeof(xmlSchemaAnnot));
424 ret->content = node;
425 return (ret);
426}
427
428/**
Daniel Veillardfdc91562002-07-01 21:52:03 +0000429 * xmlSchemaFreeAnnot:
430 * @annot: a schema type structure
431 *
432 * Deallocate a annotation structure
433 */
434static void
435xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
436{
437 if (annot == NULL)
438 return;
439 xmlFree(annot);
440}
441
442/**
Daniel Veillard1d913862003-11-21 00:28:39 +0000443 * xmlSchemaFreeImport:
444 * @import: a schema import structure
445 *
446 * Deallocate an import structure
447 */
448static void
449xmlSchemaFreeImport(xmlSchemaImportPtr import)
450{
451 if (import == NULL)
452 return;
453
454 xmlSchemaFree(import->schema);
Daniel Veillard1d913862003-11-21 00:28:39 +0000455 xmlFree(import);
456}
457
458/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000459 * xmlSchemaFreeInclude:
460 * @include: a schema include structure
461 *
462 * Deallocate an include structure
463 */
464static void
465xmlSchemaFreeInclude(xmlSchemaIncludePtr include)
466{
467 if (include == NULL)
468 return;
469
470 xmlFreeDoc(include->doc);
471 xmlFree(include);
472}
473
474/**
475 * xmlSchemaFreeIncludeList:
476 * @includes: a schema include list
477 *
478 * Deallocate an include structure
479 */
480static void
481xmlSchemaFreeIncludeList(xmlSchemaIncludePtr includes)
482{
483 xmlSchemaIncludePtr next;
484
485 while (includes != NULL) {
486 next = includes->next;
487 xmlSchemaFreeInclude(includes);
488 includes = next;
489 }
490}
491
492/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000493 * xmlSchemaFreeNotation:
494 * @schema: a schema notation structure
495 *
496 * Deallocate a Schema Notation structure.
497 */
498static void
499xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
500{
501 if (nota == NULL)
502 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000503 xmlFree(nota);
504}
505
506/**
507 * xmlSchemaFreeAttribute:
508 * @schema: a schema attribute structure
509 *
510 * Deallocate a Schema Attribute structure.
511 */
512static void
513xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
514{
515 if (attr == NULL)
516 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000517 xmlFree(attr);
518}
519
520/**
521 * xmlSchemaFreeAttributeGroup:
522 * @schema: a schema attribute group structure
523 *
524 * Deallocate a Schema Attribute Group structure.
525 */
526static void
527xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
528{
529 if (attr == NULL)
530 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000531 xmlFree(attr);
532}
533
534/**
535 * xmlSchemaFreeElement:
536 * @schema: a schema element structure
537 *
538 * Deallocate a Schema Element structure.
539 */
540static void
541xmlSchemaFreeElement(xmlSchemaElementPtr elem)
542{
543 if (elem == NULL)
544 return;
Daniel Veillard32370232002-10-16 14:08:14 +0000545 if (elem->annot != NULL)
546 xmlSchemaFreeAnnot(elem->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000547 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000548 xmlRegFreeRegexp(elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +0000549 xmlFree(elem);
550}
551
552/**
553 * xmlSchemaFreeFacet:
554 * @facet: a schema facet structure
555 *
556 * Deallocate a Schema Facet structure.
557 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000558void
Daniel Veillard4255d502002-04-16 15:50:10 +0000559xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
560{
561 if (facet == NULL)
562 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000563 if (facet->val != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000564 xmlSchemaFreeValue(facet->val);
Daniel Veillard4255d502002-04-16 15:50:10 +0000565 if (facet->regexp != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000566 xmlRegFreeRegexp(facet->regexp);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000567 if (facet->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000568 xmlSchemaFreeAnnot(facet->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000569 xmlFree(facet);
570}
571
572/**
573 * xmlSchemaFreeType:
574 * @type: a schema type structure
575 *
576 * Deallocate a Schema Type structure.
577 */
578void
579xmlSchemaFreeType(xmlSchemaTypePtr type)
580{
581 if (type == NULL)
582 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000583 if (type->annot != NULL)
Daniel Veillard32370232002-10-16 14:08:14 +0000584 xmlSchemaFreeAnnot(type->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000585 if (type->facets != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000586 xmlSchemaFacetPtr facet, next;
Daniel Veillard4255d502002-04-16 15:50:10 +0000587
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000588 facet = type->facets;
589 while (facet != NULL) {
590 next = facet->next;
591 xmlSchemaFreeFacet(facet);
592 facet = next;
593 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000594 }
595 xmlFree(type);
596}
597
598/**
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000599 * xmlSchemaFreeTypeList:
600 * @type: a schema type structure
601 *
602 * Deallocate a Schema Type structure.
603 */
604static void
605xmlSchemaFreeTypeList(xmlSchemaTypePtr type)
606{
607 xmlSchemaTypePtr next;
608
609 while (type != NULL) {
610 next = type->redef;
611 xmlSchemaFreeType(type);
612 type = next;
613 }
614}
615
616/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000617 * xmlSchemaFree:
618 * @schema: a schema structure
619 *
620 * Deallocate a Schema structure.
621 */
622void
623xmlSchemaFree(xmlSchemaPtr schema)
624{
625 if (schema == NULL)
626 return;
627
Daniel Veillard4255d502002-04-16 15:50:10 +0000628 if (schema->notaDecl != NULL)
629 xmlHashFree(schema->notaDecl,
630 (xmlHashDeallocator) xmlSchemaFreeNotation);
631 if (schema->attrDecl != NULL)
632 xmlHashFree(schema->attrDecl,
633 (xmlHashDeallocator) xmlSchemaFreeAttribute);
634 if (schema->attrgrpDecl != NULL)
635 xmlHashFree(schema->attrgrpDecl,
636 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup);
637 if (schema->elemDecl != NULL)
638 xmlHashFree(schema->elemDecl,
639 (xmlHashDeallocator) xmlSchemaFreeElement);
640 if (schema->typeDecl != NULL)
641 xmlHashFree(schema->typeDecl,
Daniel Veillardb0f397e2003-12-23 23:30:53 +0000642 (xmlHashDeallocator) xmlSchemaFreeTypeList);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000643 if (schema->groupDecl != NULL)
644 xmlHashFree(schema->groupDecl,
645 (xmlHashDeallocator) xmlSchemaFreeType);
Daniel Veillard1d913862003-11-21 00:28:39 +0000646 if (schema->schemasImports != NULL)
647 xmlHashFree(schema->schemasImports,
648 (xmlHashDeallocator) xmlSchemaFreeImport);
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000649 if (schema->includes != NULL) {
650 xmlSchemaFreeIncludeList((xmlSchemaIncludePtr) schema->includes);
651 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000652 if (schema->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000653 xmlSchemaFreeAnnot(schema->annot);
Daniel Veillarddda22c12004-01-24 08:31:30 +0000654 if (schema->doc != NULL && !schema->preserve)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000655 xmlFreeDoc(schema->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000656 xmlDictFree(schema->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +0000657
658 xmlFree(schema);
659}
660
661/************************************************************************
662 * *
Daniel Veillard4255d502002-04-16 15:50:10 +0000663 * Debug functions *
664 * *
665 ************************************************************************/
666
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000667#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000668
Daniel Veillard4255d502002-04-16 15:50:10 +0000669/**
670 * xmlSchemaElementDump:
671 * @elem: an element
672 * @output: the file output
673 *
674 * Dump the element
675 */
676static void
677xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000678 const xmlChar * name ATTRIBUTE_UNUSED,
679 const xmlChar * context ATTRIBUTE_UNUSED,
680 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +0000681{
682 if (elem == NULL)
683 return;
684
685 fprintf(output, "Element ");
686 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000687 fprintf(output, "toplevel ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000688 fprintf(output, ": %s ", elem->name);
689 if (namespace != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000690 fprintf(output, "namespace '%s' ", namespace);
691
Daniel Veillard4255d502002-04-16 15:50:10 +0000692 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000693 fprintf(output, "nillable ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000694 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000695 fprintf(output, "global ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000696 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000697 fprintf(output, "default ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000698 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000699 fprintf(output, "fixed ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000700 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000701 fprintf(output, "abstract ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000702 if (elem->flags & XML_SCHEMAS_ELEM_REF)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000703 fprintf(output, "ref '%s' ", elem->ref);
Daniel Veillard4255d502002-04-16 15:50:10 +0000704 if (elem->id != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000705 fprintf(output, "id '%s' ", elem->id);
Daniel Veillard4255d502002-04-16 15:50:10 +0000706 fprintf(output, "\n");
707 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000708 fprintf(output, " ");
709 if (elem->minOccurs != 1)
710 fprintf(output, "min: %d ", elem->minOccurs);
711 if (elem->maxOccurs >= UNBOUNDED)
712 fprintf(output, "max: unbounded\n");
713 else if (elem->maxOccurs != 1)
714 fprintf(output, "max: %d\n", elem->maxOccurs);
715 else
716 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000717 }
718 if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000719 fprintf(output, " type: %s", elem->namedType);
720 if (elem->namedTypeNs != NULL)
721 fprintf(output, " ns %s\n", elem->namedTypeNs);
722 else
723 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000724 }
725 if (elem->substGroup != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000726 fprintf(output, " substitutionGroup: %s", elem->substGroup);
727 if (elem->substGroupNs != NULL)
728 fprintf(output, " ns %s\n", elem->substGroupNs);
729 else
730 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000731 }
732 if (elem->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000733 fprintf(output, " default: %s", elem->value);
Daniel Veillard4255d502002-04-16 15:50:10 +0000734}
735
736/**
737 * xmlSchemaAnnotDump:
738 * @output: the file output
739 * @annot: a annotation
740 *
741 * Dump the annotation
742 */
743static void
744xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
745{
746 xmlChar *content;
747
748 if (annot == NULL)
749 return;
750
751 content = xmlNodeGetContent(annot->content);
752 if (content != NULL) {
753 fprintf(output, " Annot: %s\n", content);
754 xmlFree(content);
755 } else
756 fprintf(output, " Annot: empty\n");
757}
758
759/**
760 * xmlSchemaTypeDump:
761 * @output: the file output
762 * @type: a type structure
763 *
764 * Dump a SchemaType structure
765 */
766static void
767xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
768{
769 if (type == NULL) {
770 fprintf(output, "Type: NULL\n");
771 return;
772 }
773 fprintf(output, "Type: ");
774 if (type->name != NULL)
775 fprintf(output, "%s, ", type->name);
776 else
777 fprintf(output, "no name");
778 switch (type->type) {
779 case XML_SCHEMA_TYPE_BASIC:
780 fprintf(output, "basic ");
781 break;
782 case XML_SCHEMA_TYPE_SIMPLE:
783 fprintf(output, "simple ");
784 break;
785 case XML_SCHEMA_TYPE_COMPLEX:
786 fprintf(output, "complex ");
787 break;
788 case XML_SCHEMA_TYPE_SEQUENCE:
789 fprintf(output, "sequence ");
790 break;
791 case XML_SCHEMA_TYPE_CHOICE:
792 fprintf(output, "choice ");
793 break;
794 case XML_SCHEMA_TYPE_ALL:
795 fprintf(output, "all ");
796 break;
797 case XML_SCHEMA_TYPE_UR:
798 fprintf(output, "ur ");
799 break;
800 case XML_SCHEMA_TYPE_RESTRICTION:
801 fprintf(output, "restriction ");
802 break;
803 case XML_SCHEMA_TYPE_EXTENSION:
804 fprintf(output, "extension ");
805 break;
806 default:
807 fprintf(output, "unknowntype%d ", type->type);
808 break;
809 }
810 if (type->base != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000811 fprintf(output, "base %s, ", type->base);
Daniel Veillard4255d502002-04-16 15:50:10 +0000812 }
813 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000814 case XML_SCHEMA_CONTENT_UNKNOWN:
815 fprintf(output, "unknown ");
816 break;
817 case XML_SCHEMA_CONTENT_EMPTY:
818 fprintf(output, "empty ");
819 break;
820 case XML_SCHEMA_CONTENT_ELEMENTS:
821 fprintf(output, "element ");
822 break;
823 case XML_SCHEMA_CONTENT_MIXED:
824 fprintf(output, "mixed ");
825 break;
826 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
827 fprintf(output, "mixed_or_elems ");
828 break;
829 case XML_SCHEMA_CONTENT_BASIC:
830 fprintf(output, "basic ");
831 break;
832 case XML_SCHEMA_CONTENT_SIMPLE:
833 fprintf(output, "simple ");
834 break;
835 case XML_SCHEMA_CONTENT_ANY:
836 fprintf(output, "any ");
837 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000838 }
839 fprintf(output, "\n");
840 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000841 fprintf(output, " ");
842 if (type->minOccurs != 1)
843 fprintf(output, "min: %d ", type->minOccurs);
844 if (type->maxOccurs >= UNBOUNDED)
845 fprintf(output, "max: unbounded\n");
846 else if (type->maxOccurs != 1)
847 fprintf(output, "max: %d\n", type->maxOccurs);
848 else
849 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000850 }
851 if (type->annot != NULL)
852 xmlSchemaAnnotDump(output, type->annot);
853 if (type->subtypes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000854 xmlSchemaTypePtr sub = type->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +0000855
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000856 fprintf(output, " subtypes: ");
857 while (sub != NULL) {
858 fprintf(output, "%s ", sub->name);
859 sub = sub->next;
860 }
861 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000862 }
863
864}
865
866/**
867 * xmlSchemaDump:
868 * @output: the file output
869 * @schema: a schema structure
870 *
871 * Dump a Schema structure.
872 */
873void
874xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
875{
876 if (schema == NULL) {
877 fprintf(output, "Schemas: NULL\n");
878 return;
879 }
880 fprintf(output, "Schemas: ");
881 if (schema->name != NULL)
882 fprintf(output, "%s, ", schema->name);
883 else
884 fprintf(output, "no name, ");
885 if (schema->targetNamespace != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000886 fprintf(output, "%s", (const char *) schema->targetNamespace);
Daniel Veillard4255d502002-04-16 15:50:10 +0000887 else
888 fprintf(output, "no target namespace");
889 fprintf(output, "\n");
890 if (schema->annot != NULL)
891 xmlSchemaAnnotDump(output, schema->annot);
892
893 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
894 output);
895 xmlHashScanFull(schema->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000896 (xmlHashScannerFull) xmlSchemaElementDump, output);
Daniel Veillard4255d502002-04-16 15:50:10 +0000897}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000898#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard4255d502002-04-16 15:50:10 +0000899
900/************************************************************************
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000901 * *
902 * Utilities *
903 * *
904 ************************************************************************/
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000905
906/**
907 * xmlSchemaGetProp:
908 * @ctxt: the parser context
909 * @node: the node
910 * @name: the property name
911 *
912 * Read a attribute value and internalize the string
913 *
914 * Returns the string or NULL if not present.
915 */
916static const xmlChar *
917xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
918 const char *name)
919{
920 xmlChar *val;
921 const xmlChar *ret;
922
923 val = xmlGetProp(node, BAD_CAST name);
924 if (val == NULL)
925 return(NULL);
926 ret = xmlDictLookup(ctxt->dict, val, -1);
927 xmlFree(val);
928 return(ret);
929}
930
931/**
932 * xmlSchemaGetNamespace:
933 * @ctxt: the parser context
934 * @schema: the schemas containing the declaration
935 * @node: the node
936 * @qname: the QName to analyze
937 *
938 * Find the namespace name for the given declaration.
939 *
940 * Returns the local name for that declaration, as well as the namespace name
941 */
942static const xmlChar *
943xmlSchemaGetNamespace(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
944 xmlNodePtr node, const xmlChar *qname,
945 const xmlChar **namespace) {
946 int len;
947 const xmlChar *name, *prefix, *def = NULL;
948 xmlNsPtr ns;
949
950 *namespace = NULL;
951
952 if (xmlStrEqual(node->name, BAD_CAST "element") ||
953 xmlStrEqual(node->name, BAD_CAST "attribute") ||
954 xmlStrEqual(node->name, BAD_CAST "simpleType") ||
955 xmlStrEqual(node->name, BAD_CAST "complexType")) {
956 def = xmlSchemaGetProp(ctxt, node, "targetNamespace");
957 }
958
959 qname = xmlDictLookup(ctxt->dict, qname, -1); /* intern the string */
960 name = xmlSplitQName3(qname, &len);
961 if (name == NULL) {
962 if (def == NULL) {
963 if (xmlStrEqual(node->name, BAD_CAST "element")) {
964 if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
965 *namespace = schema->targetNamespace;
966 } else if (xmlStrEqual(node->name, BAD_CAST "attribute")) {
967 if (schema->flags & XML_SCHEMAS_QUALIF_ATTR)
968 *namespace = schema->targetNamespace;
969 } else if ((xmlStrEqual(node->name, BAD_CAST "simpleType")) ||
970 (xmlStrEqual(node->name, BAD_CAST "complexType"))) {
971 *namespace = schema->targetNamespace;
972 }
973 } else {
974 *namespace = def;
975 }
976 return(qname);
977 }
978 name = xmlDictLookup(ctxt->dict, name, -1);
979 prefix = xmlDictLookup(ctxt->dict, qname, len);
980 if (def != NULL) {
981 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_DEF_AND_PREFIX,
982 "%s: presence of both prefix %s and targetNamespace\n",
983 node->name, prefix);
984 }
985 ns = xmlSearchNs(node->doc, node, prefix);
986 if (ns == NULL) {
987 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
988 "%s: the QName prefix %s is undefined\n",
989 node->name, prefix);
990 return(name);
991 }
992 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
993 return(name);
994}
995
996/************************************************************************
Daniel Veillard4255d502002-04-16 15:50:10 +0000997 * *
998 * Parsing functions *
999 * *
1000 ************************************************************************/
1001
1002/**
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001003 * xmlSchemaGetElem:
1004 * @schema: the schemas context
1005 * @name: the element name
1006 * @ns: the element namespace
Daniel Veillardf2a12832003-11-24 13:04:35 +00001007 * @level: how deep is the request
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001008 *
1009 * Lookup a an element in the schemas or the accessible schemas
1010 *
1011 * Returns the element definition or NULL if not found.
1012 */
1013static xmlSchemaElementPtr
1014xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardf2a12832003-11-24 13:04:35 +00001015 const xmlChar * namespace, int level)
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001016{
1017 xmlSchemaElementPtr ret;
Daniel Veillardf2a12832003-11-24 13:04:35 +00001018 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001019
1020 if ((name == NULL) || (schema == NULL))
1021 return (NULL);
1022
1023 if (namespace == NULL) {
1024 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001025 if ((ret != NULL) &&
1026 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001027 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001028 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001029 } else if ((schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0) {
1030 if (xmlStrEqual(namespace, schema->targetNamespace))
1031 ret = xmlHashLookup2(schema->elemDecl, name, NULL);
1032 else
1033 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001034 if ((ret != NULL) &&
1035 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001036 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001037 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001038 } else {
1039 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001040 if ((ret != NULL) &&
1041 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001042 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001043 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001044 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00001045 if (level > 0)
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001046 import = xmlHashLookup(schema->schemasImports, namespace);
1047 if (import != NULL)
Daniel Veillardf2a12832003-11-24 13:04:35 +00001048 ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001049#ifdef DEBUG
1050 if (ret == NULL) {
1051 if (namespace == NULL)
1052 fprintf(stderr, "Unable to lookup type %s", name);
1053 else
1054 fprintf(stderr, "Unable to lookup type %s:%s", name,
1055 namespace);
1056 }
1057#endif
1058 return (ret);
1059}
1060
1061/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001062 * xmlSchemaGetType:
1063 * @schema: the schemas context
1064 * @name: the type name
1065 * @ns: the type namespace
1066 *
1067 * Lookup a type in the schemas or the predefined types
1068 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001069 * Returns the group definition or NULL if not found.
Daniel Veillard4255d502002-04-16 15:50:10 +00001070 */
1071static xmlSchemaTypePtr
1072xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001073 const xmlChar * namespace)
1074{
Daniel Veillard4255d502002-04-16 15:50:10 +00001075 xmlSchemaTypePtr ret;
Daniel Veillard1d913862003-11-21 00:28:39 +00001076 xmlSchemaImportPtr import;
Daniel Veillard4255d502002-04-16 15:50:10 +00001077
1078 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001079 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001080 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001081 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
1082 if (ret != NULL)
1083 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001084 }
1085 ret = xmlSchemaGetPredefinedType(name, namespace);
Daniel Veillard1d913862003-11-21 00:28:39 +00001086 if (ret != NULL)
1087 return (ret);
1088 import = xmlHashLookup(schema->schemasImports, namespace);
1089 if (import != NULL)
1090 ret = xmlSchemaGetType(import->schema, name, namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001091#ifdef DEBUG
1092 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001093 if (namespace == NULL)
1094 fprintf(stderr, "Unable to lookup type %s", name);
1095 else
1096 fprintf(stderr, "Unable to lookup type %s:%s", name,
1097 namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001098 }
1099#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001100 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001101}
1102
1103/************************************************************************
1104 * *
1105 * Parsing functions *
1106 * *
1107 ************************************************************************/
1108
1109#define IS_BLANK_NODE(n) \
1110 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
1111
1112/**
1113 * xmlSchemaIsBlank:
1114 * @str: a string
1115 *
1116 * Check if a string is ignorable
1117 *
1118 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
1119 */
1120static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001121xmlSchemaIsBlank(xmlChar * str)
1122{
Daniel Veillard4255d502002-04-16 15:50:10 +00001123 if (str == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001124 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001125 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001126 if (!(IS_BLANK_CH(*str)))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001127 return (0);
1128 str++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001129 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001130 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001131}
1132
1133/**
1134 * xmlSchemaAddNotation:
1135 * @ctxt: a schema validation context
1136 * @schema: the schema being built
1137 * @name: the item name
1138 *
1139 * Add an XML schema Attrribute declaration
1140 * *WARNING* this interface is highly subject to change
1141 *
1142 * Returns the new struture or NULL in case of error
1143 */
1144static xmlSchemaNotationPtr
1145xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001146 const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001147{
1148 xmlSchemaNotationPtr ret = NULL;
1149 int val;
1150
1151 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1152 return (NULL);
1153
1154 if (schema->notaDecl == NULL)
1155 schema->notaDecl = xmlHashCreate(10);
1156 if (schema->notaDecl == NULL)
1157 return (NULL);
1158
1159 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
1160 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001161 xmlSchemaPErrMemory(ctxt, "add annotation", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001162 return (NULL);
1163 }
1164 memset(ret, 0, sizeof(xmlSchemaNotation));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001165 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001166 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
1167 ret);
1168 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001169 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1170 XML_SCHEMAP_REDEFINED_NOTATION,
1171 "Notation %s already defined\n",
1172 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001173 xmlFree(ret);
1174 return (NULL);
1175 }
1176 return (ret);
1177}
1178
1179
1180/**
1181 * xmlSchemaAddAttribute:
1182 * @ctxt: a schema validation context
1183 * @schema: the schema being built
1184 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001185 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001186 *
1187 * Add an XML schema Attrribute declaration
1188 * *WARNING* this interface is highly subject to change
1189 *
1190 * Returns the new struture or NULL in case of error
1191 */
1192static xmlSchemaAttributePtr
1193xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001194 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001195{
1196 xmlSchemaAttributePtr ret = NULL;
1197 int val;
1198
1199 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1200 return (NULL);
1201
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001202#ifdef DEBUG
1203 fprintf(stderr, "Adding attribute %s\n", name);
1204 if (namespace != NULL)
1205 fprintf(stderr, " target namespace %s\n", namespace);
1206#endif
1207
Daniel Veillard4255d502002-04-16 15:50:10 +00001208 if (schema->attrDecl == NULL)
1209 schema->attrDecl = xmlHashCreate(10);
1210 if (schema->attrDecl == NULL)
1211 return (NULL);
1212
1213 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
1214 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001215 xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001216 return (NULL);
1217 }
1218 memset(ret, 0, sizeof(xmlSchemaAttribute));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001219 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1220 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001221 val = xmlHashAddEntry3(schema->attrDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001222 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001223 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001224 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1225 XML_SCHEMAP_REDEFINED_ATTR,
1226 "Attribute %s already defined\n",
1227 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001228 xmlFree(ret);
1229 return (NULL);
1230 }
1231 return (ret);
1232}
1233
1234/**
1235 * xmlSchemaAddAttributeGroup:
1236 * @ctxt: a schema validation context
1237 * @schema: the schema being built
1238 * @name: the item name
1239 *
1240 * Add an XML schema Attrribute Group declaration
1241 *
1242 * Returns the new struture or NULL in case of error
1243 */
1244static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001245xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1246 xmlSchemaPtr schema, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001247{
1248 xmlSchemaAttributeGroupPtr ret = NULL;
1249 int val;
1250
1251 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1252 return (NULL);
1253
1254 if (schema->attrgrpDecl == NULL)
1255 schema->attrgrpDecl = xmlHashCreate(10);
1256 if (schema->attrgrpDecl == NULL)
1257 return (NULL);
1258
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001259 ret =
1260 (xmlSchemaAttributeGroupPtr)
1261 xmlMalloc(sizeof(xmlSchemaAttributeGroup));
Daniel Veillard4255d502002-04-16 15:50:10 +00001262 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001263 xmlSchemaPErrMemory(ctxt, "allocating attribute group", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001264 return (NULL);
1265 }
1266 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001267 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001268 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001269 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001270 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001271 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1272 XML_SCHEMAP_REDEFINED_ATTRGROUP,
1273 "Attribute group %s already defined\n",
1274 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001275 xmlFree(ret);
1276 return (NULL);
1277 }
1278 return (ret);
1279}
1280
1281/**
1282 * xmlSchemaAddElement:
1283 * @ctxt: a schema validation context
1284 * @schema: the schema being built
1285 * @name: the type name
1286 * @namespace: the type namespace
1287 *
1288 * Add an XML schema Element declaration
1289 * *WARNING* this interface is highly subject to change
1290 *
1291 * Returns the new struture or NULL in case of error
1292 */
1293static xmlSchemaElementPtr
1294xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1295 const xmlChar * name, const xmlChar * namespace)
1296{
1297 xmlSchemaElementPtr ret = NULL;
1298 int val;
1299
1300 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1301 return (NULL);
1302
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001303#ifdef DEBUG
1304 fprintf(stderr, "Adding element %s\n", name);
1305 if (namespace != NULL)
1306 fprintf(stderr, " target namespace %s\n", namespace);
1307#endif
1308
Daniel Veillard4255d502002-04-16 15:50:10 +00001309 if (schema->elemDecl == NULL)
1310 schema->elemDecl = xmlHashCreate(10);
1311 if (schema->elemDecl == NULL)
1312 return (NULL);
1313
1314 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
1315 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001316 xmlSchemaPErrMemory(ctxt, "allocating element", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001317 return (NULL);
1318 }
1319 memset(ret, 0, sizeof(xmlSchemaElement));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001320 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1321 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001322 val = xmlHashAddEntry3(schema->elemDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001323 namespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001324 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001325 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00001326
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001327 snprintf(buf, 99, "privatieelem %d", ctxt->counter++ + 1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001328 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
1329 namespace, ret);
1330 if (val != 0) {
1331 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1332 XML_SCHEMAP_REDEFINED_ELEMENT,
1333 "Element %s already defined\n",
1334 name, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001335 xmlFree(ret);
1336 return (NULL);
1337 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001338 }
1339 return (ret);
1340}
1341
1342/**
1343 * xmlSchemaAddType:
1344 * @ctxt: a schema validation context
1345 * @schema: the schema being built
1346 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001347 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001348 *
1349 * Add an XML schema Simple Type definition
1350 * *WARNING* this interface is highly subject to change
1351 *
1352 * Returns the new struture or NULL in case of error
1353 */
1354static xmlSchemaTypePtr
1355xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001356 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001357{
1358 xmlSchemaTypePtr ret = NULL;
1359 int val;
1360
1361 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1362 return (NULL);
1363
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001364#ifdef DEBUG
1365 fprintf(stderr, "Adding type %s\n", name);
1366 if (namespace != NULL)
1367 fprintf(stderr, " target namespace %s\n", namespace);
1368#endif
1369
Daniel Veillard4255d502002-04-16 15:50:10 +00001370 if (schema->typeDecl == NULL)
1371 schema->typeDecl = xmlHashCreate(10);
1372 if (schema->typeDecl == NULL)
1373 return (NULL);
1374
1375 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1376 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001377 xmlSchemaPErrMemory(ctxt, "allocating type", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001378 return (NULL);
1379 }
1380 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001381 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00001382 ret->redef = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001383 val = xmlHashAddEntry2(schema->typeDecl, name, namespace, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001384 if (val != 0) {
Daniel Veillardb0f397e2003-12-23 23:30:53 +00001385 if (ctxt->includes == 0) {
1386 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1387 XML_SCHEMAP_REDEFINED_TYPE,
1388 "Type %s already defined\n",
1389 name, NULL);
1390 xmlFree(ret);
1391 return (NULL);
1392 } else {
1393 xmlSchemaTypePtr prev;
1394
1395 prev = xmlHashLookup2(schema->typeDecl, name, namespace);
1396 if (prev == NULL) {
1397 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1398 XML_ERR_INTERNAL_ERROR,
1399 "Internal error on type %s definition\n",
1400 name, NULL);
1401 xmlFree(ret);
1402 return (NULL);
1403 }
1404 ret->redef = prev->redef;
1405 prev->redef = ret;
1406 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001407 }
1408 ret->minOccurs = 1;
1409 ret->maxOccurs = 1;
1410
1411 return (ret);
1412}
1413
1414/**
1415 * xmlSchemaAddGroup:
1416 * @ctxt: a schema validation context
1417 * @schema: the schema being built
1418 * @name: the group name
1419 *
1420 * Add an XML schema Group definition
1421 *
1422 * Returns the new struture or NULL in case of error
1423 */
1424static xmlSchemaTypePtr
1425xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001426 const xmlChar * name)
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001427{
1428 xmlSchemaTypePtr ret = NULL;
1429 int val;
1430
1431 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1432 return (NULL);
1433
1434 if (schema->groupDecl == NULL)
1435 schema->groupDecl = xmlHashCreate(10);
1436 if (schema->groupDecl == NULL)
1437 return (NULL);
1438
1439 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1440 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001441 xmlSchemaPErrMemory(ctxt, "adding group", NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001442 return (NULL);
1443 }
1444 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001445 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001446 val =
1447 xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace,
1448 ret);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001449 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001450 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1451 XML_SCHEMAP_REDEFINED_GROUP,
1452 "Group %s already defined\n",
1453 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001454 xmlFree(ret);
1455 return (NULL);
1456 }
1457 ret->minOccurs = 1;
1458 ret->maxOccurs = 1;
1459
1460 return (ret);
1461}
1462
1463/************************************************************************
1464 * *
1465 * Utilities for parsing *
1466 * *
1467 ************************************************************************/
1468
1469/**
1470 * xmlGetQNameProp:
1471 * @ctxt: a schema validation context
1472 * @node: a subtree containing XML Schema informations
1473 * @name: the attribute name
1474 * @namespace: the result namespace if any
1475 *
1476 * Extract a QName Attribute value
1477 *
1478 * Returns the NCName or NULL if not found, and also update @namespace
1479 * with the namespace URI
1480 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001481static const xmlChar *
Daniel Veillard4255d502002-04-16 15:50:10 +00001482xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001483 const char *name, const xmlChar ** namespace)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001484{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001485 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001486 xmlNsPtr ns;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001487 const xmlChar *ret, *prefix;
1488 int len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001489
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001490 *namespace = NULL;
1491 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001492 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001493 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001494
Daniel Veillardba0153a2004-04-01 10:42:31 +00001495 if (!strchr((char *) val, ':')) {
Daniel Veillardebcdebd2004-03-05 00:15:50 +00001496 ns = xmlSearchNs(node->doc, node, 0);
1497 if (ns) {
1498 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
1499 return (val);
1500 }
1501 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001502 ret = xmlSplitQName3(val, &len);
1503 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001504 return (val);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001505 }
1506 ret = xmlDictLookup(ctxt->dict, ret, -1);
1507 prefix = xmlDictLookup(ctxt->dict, val, len);
Daniel Veillard4255d502002-04-16 15:50:10 +00001508
1509 ns = xmlSearchNs(node->doc, node, prefix);
1510 if (ns == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001511 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
1512 "Attribute %s: the QName prefix %s is undefined\n",
1513 (const xmlChar *) name, prefix);
Daniel Veillard4255d502002-04-16 15:50:10 +00001514 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001515 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001516 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001517 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001518}
1519
1520/**
1521 * xmlGetMaxOccurs:
1522 * @ctxt: a schema validation context
1523 * @node: a subtree containing XML Schema informations
1524 *
1525 * Get the maxOccurs property
1526 *
1527 * Returns the default if not found, or the value
1528 */
1529static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001530xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1531{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001532 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001533 int ret = 0;
1534
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001535 val = xmlSchemaGetProp(ctxt, node, "maxOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001536 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001537 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001538
1539 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001540 return (UNBOUNDED); /* encoding it with -1 might be another option */
Daniel Veillard4255d502002-04-16 15:50:10 +00001541 }
1542
1543 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001544 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001545 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001546 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001547 ret = ret * 10 + (*cur - '0');
1548 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001549 }
William M. Brack76e95df2003-10-18 16:20:14 +00001550 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001551 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001552 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001553 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS,
1554 "invalid value for maxOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001555 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001556 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001557 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001558}
1559
1560/**
1561 * xmlGetMinOccurs:
1562 * @ctxt: a schema validation context
1563 * @node: a subtree containing XML Schema informations
1564 *
1565 * Get the minOccurs property
1566 *
1567 * Returns the default if not found, or the value
1568 */
1569static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001570xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1571{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001572 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001573 int ret = 0;
1574
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001575 val = xmlSchemaGetProp(ctxt, node, "minOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001576 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001577 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001578
1579 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001580 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001581 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001582 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001583 ret = ret * 10 + (*cur - '0');
1584 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001585 }
William M. Brack76e95df2003-10-18 16:20:14 +00001586 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001587 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001588 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001589 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS,
1590 "invalid value for minOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001591 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001592 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001593 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001594}
1595
1596/**
1597 * xmlGetBooleanProp:
1598 * @ctxt: a schema validation context
1599 * @node: a subtree containing XML Schema informations
1600 * @name: the attribute name
1601 * @def: the default value
1602 *
1603 * Get is a bolean property is set
1604 *
1605 * Returns the default if not found, 0 if found to be false,
1606 * 1 if found to be true
1607 */
1608static int
1609xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001610 const char *name, int def)
1611{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001612 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001613
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001614 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001615 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001616 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001617
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001618 if (xmlStrEqual(val, BAD_CAST "true"))
1619 def = 1;
1620 else if (xmlStrEqual(val, BAD_CAST "false"))
1621 def = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001622 else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001623 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_BOOLEAN,
1624 "Attribute %s: the value %s is not boolean\n",
1625 (const xmlChar *) name, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001626 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001627 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001628}
1629
1630/************************************************************************
1631 * *
1632 * Shema extraction from an Infoset *
1633 * *
1634 ************************************************************************/
1635static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1636 ctxt, xmlSchemaPtr schema,
1637 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001638static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr
1639 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001640 xmlSchemaPtr schema,
1641 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001642static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr
1643 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001644 xmlSchemaPtr schema,
1645 xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001646 int simple);
Daniel Veillard4255d502002-04-16 15:50:10 +00001647static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1648 xmlSchemaPtr schema,
1649 xmlNodePtr node);
1650static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1651 xmlSchemaPtr schema,
1652 xmlNodePtr node);
1653static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1654 ctxt,
1655 xmlSchemaPtr schema,
1656 xmlNodePtr node);
1657static xmlSchemaAttributeGroupPtr
1658xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1659 xmlSchemaPtr schema, xmlNodePtr node);
1660static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1661 xmlSchemaPtr schema,
1662 xmlNodePtr node);
1663static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1664 xmlSchemaPtr schema,
1665 xmlNodePtr node);
1666static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001667xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1668 xmlSchemaPtr schema, xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00001669
1670/**
1671 * xmlSchemaParseAttrDecls:
1672 * @ctxt: a schema validation context
1673 * @schema: the schema being built
1674 * @node: a subtree containing XML Schema informations
1675 * @type: the hosting type
1676 *
1677 * parse a XML schema attrDecls declaration corresponding to
1678 * <!ENTITY % attrDecls
1679 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1680 */
1681static xmlNodePtr
1682xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1683 xmlNodePtr child, xmlSchemaTypePtr type)
1684{
1685 xmlSchemaAttributePtr lastattr, attr;
1686
1687 lastattr = NULL;
1688 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001689 (IS_SCHEMA(child, "attributeGroup"))) {
1690 attr = NULL;
1691 if (IS_SCHEMA(child, "attribute")) {
1692 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1693 } else if (IS_SCHEMA(child, "attributeGroup")) {
1694 attr = (xmlSchemaAttributePtr)
1695 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1696 }
1697 if (attr != NULL) {
1698 if (lastattr == NULL) {
1699 type->attributes = attr;
1700 lastattr = attr;
1701 } else {
1702 lastattr->next = attr;
1703 lastattr = attr;
1704 }
1705 }
1706 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001707 }
1708 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001709 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1710 if (attr != NULL) {
1711 if (lastattr == NULL) {
1712 type->attributes = attr;
1713 lastattr = attr;
1714 } else {
1715 lastattr->next = attr;
1716 lastattr = attr;
1717 }
1718 }
1719 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001720 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001721 return (child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001722}
1723
1724/**
1725 * xmlSchemaParseAnnotation:
1726 * @ctxt: a schema validation context
1727 * @schema: the schema being built
1728 * @node: a subtree containing XML Schema informations
1729 *
1730 * parse a XML schema Attrribute declaration
1731 * *WARNING* this interface is highly subject to change
1732 *
1733 * Returns -1 in case of error, 0 if the declaration is inproper and
1734 * 1 in case of success.
1735 */
1736static xmlSchemaAnnotPtr
1737xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1738 xmlNodePtr node)
1739{
1740 xmlSchemaAnnotPtr ret;
1741
1742 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1743 return (NULL);
1744 ret = xmlSchemaNewAnnot(ctxt, node);
1745
1746 return (ret);
1747}
1748
1749/**
1750 * xmlSchemaParseFacet:
1751 * @ctxt: a schema validation context
1752 * @schema: the schema being built
1753 * @node: a subtree containing XML Schema informations
1754 *
1755 * parse a XML schema Facet declaration
1756 * *WARNING* this interface is highly subject to change
1757 *
1758 * Returns the new type structure or NULL in case of error
1759 */
1760static xmlSchemaFacetPtr
1761xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001762 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001763{
1764 xmlSchemaFacetPtr facet;
1765 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001766 const xmlChar *value;
Daniel Veillard4255d502002-04-16 15:50:10 +00001767
1768 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1769 return (NULL);
1770
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001771 facet = xmlSchemaNewFacet();
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001772 if (facet == NULL) {
1773 xmlSchemaPErrMemory(ctxt, "allocating facet", node);
1774 return (NULL);
1775 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001776 facet->node = node;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001777 value = xmlSchemaGetProp(ctxt, node, "value");
Daniel Veillard4255d502002-04-16 15:50:10 +00001778 if (value == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001779 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE,
1780 "Facet %s has no value\n", node->name, NULL);
1781 xmlSchemaFreeFacet(facet);
Daniel Veillard4255d502002-04-16 15:50:10 +00001782 return (NULL);
1783 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001784 if (IS_SCHEMA(node, "minInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001785 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001786 } else if (IS_SCHEMA(node, "minExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001787 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001788 } else if (IS_SCHEMA(node, "maxInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001789 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001790 } else if (IS_SCHEMA(node, "maxExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001791 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001792 } else if (IS_SCHEMA(node, "totalDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001793 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001794 } else if (IS_SCHEMA(node, "fractionDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001795 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001796 } else if (IS_SCHEMA(node, "pattern")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001797 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001798 } else if (IS_SCHEMA(node, "enumeration")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001799 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001800 } else if (IS_SCHEMA(node, "whiteSpace")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001801 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001802 } else if (IS_SCHEMA(node, "length")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001803 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001804 } else if (IS_SCHEMA(node, "maxLength")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001805 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1806 } else if (IS_SCHEMA(node, "minLength")) {
1807 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1808 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001809 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE,
1810 "Unknown facet type %s\n", node->name, NULL);
1811 xmlSchemaFreeFacet(facet);
1812 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001813 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001814 facet->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00001815 facet->value = value;
1816 child = node->children;
1817
1818 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001819 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1820 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001821 }
1822 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001823 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD,
1824 "Facet %s has unexpected child content\n",
1825 node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001826 }
1827 return (facet);
1828}
1829
1830/**
1831 * xmlSchemaParseAny:
1832 * @ctxt: a schema validation context
1833 * @schema: the schema being built
1834 * @node: a subtree containing XML Schema informations
1835 *
1836 * parse a XML schema Any declaration
1837 * *WARNING* this interface is highly subject to change
1838 *
1839 * Returns the new type structure or NULL in case of error
1840 */
1841static xmlSchemaTypePtr
1842xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1843 xmlNodePtr node)
1844{
1845 xmlSchemaTypePtr type;
1846 xmlNodePtr child = NULL;
1847 xmlChar name[30];
1848
1849 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1850 return (NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001851 snprintf((char *) name, 30, "any %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001852 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001853 if (type == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001854 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001855 type->node = node;
1856 type->type = XML_SCHEMA_TYPE_ANY;
1857 child = node->children;
1858 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1859 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1860
1861 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001862 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1863 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001864 }
1865 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001866 xmlSchemaPErr2(ctxt, node, child,
1867 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
1868 "Sequence %s has unexpected content\n", type->name,
1869 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001870 }
1871
1872 return (type);
1873}
1874
1875/**
1876 * xmlSchemaParseNotation:
1877 * @ctxt: a schema validation context
1878 * @schema: the schema being built
1879 * @node: a subtree containing XML Schema informations
1880 *
1881 * parse a XML schema Notation declaration
1882 *
1883 * Returns the new structure or NULL in case of error
1884 */
1885static xmlSchemaNotationPtr
1886xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001887 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001888{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001889 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00001890 xmlSchemaNotationPtr ret;
1891 xmlNodePtr child = NULL;
1892
1893 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1894 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001895 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00001896 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001897 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME,
1898 "Notation has no name\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001899 return (NULL);
1900 }
1901 ret = xmlSchemaAddNotation(ctxt, schema, name);
1902 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001903 return (NULL);
1904 }
1905 child = node->children;
1906 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001907 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1908 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001909 }
1910 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001911 xmlSchemaPErr2(ctxt, node, child,
1912 XML_SCHEMAP_UNKNOWN_NOTATION_CHILD,
1913 "notation %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001914 }
1915
1916 return (ret);
1917}
1918
1919/**
1920 * xmlSchemaParseAnyAttribute:
1921 * @ctxt: a schema validation context
1922 * @schema: the schema being built
1923 * @node: a subtree containing XML Schema informations
1924 *
1925 * parse a XML schema AnyAttrribute declaration
1926 * *WARNING* this interface is highly subject to change
1927 *
1928 * Returns an attribute def structure or NULL
1929 */
1930static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001931xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1932 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001933{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001934 const xmlChar *processContents;
Daniel Veillard4255d502002-04-16 15:50:10 +00001935 xmlSchemaAttributePtr ret;
1936 xmlNodePtr child = NULL;
1937 char name[100];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001938 const xmlChar *local, *ns;
1939
Daniel Veillard4255d502002-04-16 15:50:10 +00001940
1941 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1942 return (NULL);
1943
1944 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001945 local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns);
1946 ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00001947 if (ret == NULL) {
1948 return (NULL);
1949 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001950 ret->id = xmlSchemaGetProp(ctxt, node, "id");
1951 processContents = xmlSchemaGetProp(ctxt, node, "processContents");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001952 if ((processContents == NULL)
1953 || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) {
1954 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1955 } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) {
1956 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1957 } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) {
1958 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
Daniel Veillard4255d502002-04-16 15:50:10 +00001959 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001960 xmlSchemaPErr2(ctxt, node, child,
1961 XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD,
1962 "anyAttribute has unexpected content for processContents: %s\n",
1963 processContents, NULL);
1964 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
Daniel Veillard4255d502002-04-16 15:50:10 +00001965 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001966
1967 child = node->children;
1968 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001969 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1970 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001971 }
1972 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001973 xmlSchemaPErr2(ctxt, node, child,
1974 XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD,
1975 "anyAttribute %s has unexpected content\n",
1976 (const xmlChar *) name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001977 }
1978
1979 return (ret);
1980}
1981
1982
1983/**
1984 * xmlSchemaParseAttribute:
1985 * @ctxt: a schema validation context
1986 * @schema: the schema being built
1987 * @node: a subtree containing XML Schema informations
1988 *
1989 * parse a XML schema Attrribute declaration
1990 * *WARNING* this interface is highly subject to change
1991 *
1992 * Returns -1 in case of error, 0 if the declaration is inproper and
1993 * 1 in case of success.
1994 */
1995static xmlSchemaAttributePtr
1996xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1997 xmlNodePtr node)
1998{
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00001999 const xmlChar *name, *refNs = NULL, *ref = NULL, *attrVal;
Daniel Veillard4255d502002-04-16 15:50:10 +00002000 xmlSchemaAttributePtr ret;
2001 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002002 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002003
2004 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2005 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002006 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002007 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002008
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002009 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2010 if (ref == NULL) {
2011 xmlSchemaPErr2(ctxt, node, child,
2012 XML_SCHEMAP_ATTR_NONAME_NOREF,
2013 "Attribute has no name nor ref\n", NULL, NULL);
2014 return (NULL);
2015 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002016 snprintf(buf, 99, "anonattr %d", ctxt->counter++ + 1);
2017 name = (const xmlChar *) buf;
2018 ret = xmlSchemaAddAttribute(ctxt, schema, name, NULL);
2019 } else {
2020 const xmlChar *local, *ns;
2021
2022 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2023 ret = xmlSchemaAddAttribute(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002024 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002025 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002026 return (NULL);
2027 }
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00002028
2029 /* Read the "use" attribute. */
2030 attrVal = xmlSchemaGetProp(ctxt, node, "use");
2031 if (attrVal != NULL) {
2032 if (xmlStrEqual(attrVal, BAD_CAST "optional"))
2033 ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
2034 else if (xmlStrEqual(attrVal, BAD_CAST "prohibited"))
2035 ret->occurs = XML_SCHEMAS_ATTR_USE_PROHIBITED;
2036 else if (xmlStrEqual(attrVal, BAD_CAST "required"))
2037 ret->occurs = XML_SCHEMAS_ATTR_USE_REQUIRED;
2038 else
2039 xmlSchemaPErr(ctxt, node,
2040 XML_SCHEMAP_INVALID_ATTR_USE,
2041 "attribute %s has an invalid value for \"use\"\n", name, NULL);
2042 } else
2043 ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
2044
Daniel Veillard4255d502002-04-16 15:50:10 +00002045 ret->ref = ref;
2046 ret->refNs = refNs;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002047 if ((ret->targetNamespace != NULL) &&
2048 ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) &&
2049 (xmlStrEqual(ret->targetNamespace, schema->targetNamespace)))
2050 ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT;
Daniel Veillard4255d502002-04-16 15:50:10 +00002051 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002052 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002053 child = node->children;
2054 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002055 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2056 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002057 }
2058 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002059 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
2060 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002061 }
2062 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002063 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD,
2064 "attribute %s has unexpected content\n", name,
2065 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002066 }
2067
2068 return (ret);
2069}
2070
2071/**
2072 * xmlSchemaParseAttributeGroup:
2073 * @ctxt: a schema validation context
2074 * @schema: the schema being built
2075 * @node: a subtree containing XML Schema informations
2076 *
2077 * parse a XML schema Attribute Group declaration
2078 * *WARNING* this interface is highly subject to change
2079 *
2080 * Returns the attribute group or NULL in case of error.
2081 */
2082static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002083xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
2084 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002085{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002086 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002087 xmlSchemaAttributeGroupPtr ret;
2088 xmlSchemaAttributePtr last = NULL, attr;
2089 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002090 const xmlChar *oldcontainer;
2091 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002092
2093 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2094 return (NULL);
2095 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002096 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002097 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002098
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002099 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2100 if (ref == NULL) {
2101 xmlSchemaPErr2(ctxt, node, child,
2102 XML_SCHEMAP_ATTRGRP_NONAME_NOREF,
2103 "AttributeGroup has no name nor ref\n", NULL,
2104 NULL);
2105 return (NULL);
2106 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002107 snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1);
2108 name = (const xmlChar *) buf;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002109 if (name == NULL) {
2110 xmlSchemaPErrMemory(ctxt, "creating attribute group", node);
2111 return (NULL);
2112 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002113 }
2114 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
2115 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002116 return (NULL);
2117 }
2118 ret->ref = ref;
2119 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00002120 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002121 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002122 child = node->children;
2123 ctxt->container = name;
2124 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002125 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2126 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002127 }
2128 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002129 (IS_SCHEMA(child, "attributeGroup"))) {
2130 attr = NULL;
2131 if (IS_SCHEMA(child, "attribute")) {
2132 attr = xmlSchemaParseAttribute(ctxt, schema, child);
2133 } else if (IS_SCHEMA(child, "attributeGroup")) {
2134 attr = (xmlSchemaAttributePtr)
2135 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2136 }
2137 if (attr != NULL) {
2138 if (last == NULL) {
2139 ret->attributes = attr;
2140 last = attr;
2141 } else {
2142 last->next = attr;
2143 last = attr;
2144 }
2145 }
2146 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002147 }
2148 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002149 TODO
2150 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002151 }
2152 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002153 xmlSchemaPErr2(ctxt, node, child,
2154 XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD,
2155 "attribute group %s has unexpected content\n", name,
2156 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002157 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002158 ctxt->container = oldcontainer;
2159 return (ret);
2160}
2161
2162/**
2163 * xmlSchemaParseElement:
2164 * @ctxt: a schema validation context
2165 * @schema: the schema being built
2166 * @node: a subtree containing XML Schema informations
2167 *
2168 * parse a XML schema Element declaration
2169 * *WARNING* this interface is highly subject to change
2170 *
2171 * Returns -1 in case of error, 0 if the declaration is inproper and
2172 * 1 in case of success.
2173 */
2174static xmlSchemaElementPtr
2175xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2176 xmlNodePtr node, int toplevel)
2177{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002178 const xmlChar *name, *fixed;
2179 const xmlChar *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002180 xmlSchemaElementPtr ret;
2181 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002182 const xmlChar *oldcontainer;
2183 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002184
2185 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2186 return (NULL);
2187 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002188 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002189 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002190
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002191 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2192 if (ref == NULL) {
2193 xmlSchemaPErr2(ctxt, node, child,
2194 XML_SCHEMAP_ELEM_NONAME_NOREF,
2195 "Element has no name nor ref\n", NULL, NULL);
2196 return (NULL);
2197 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002198 snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1);
2199 name = (const xmlChar *) buf;
2200 ret = xmlSchemaAddElement(ctxt, schema, name, NULL);
2201 } else {
2202 const xmlChar *local, *ns;
2203
2204 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2205 ret = xmlSchemaAddElement(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002206 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002207 if (ret != NULL)
2208 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002209 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002210 return (NULL);
2211 }
2212 ret->type = XML_SCHEMA_TYPE_ELEMENT;
2213 ret->ref = ref;
2214 ret->refNs = refNs;
2215 if (ref != NULL)
2216 ret->flags |= XML_SCHEMAS_ELEM_REF;
2217 if (toplevel)
2218 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
2219 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
2220 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2221 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
2222 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2223 ctxt->container = name;
2224
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002225 ret->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002226 ret->namedType =
2227 xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
2228 ret->substGroup =
2229 xmlGetQNameProp(ctxt, node, "substitutionGroup",
2230 &(ret->substGroupNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002231 fixed = xmlSchemaGetProp(ctxt, node, "fixed");
Daniel Veillard4255d502002-04-16 15:50:10 +00002232 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
2233 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002234
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002235 ret->value = xmlSchemaGetProp(ctxt, node, "default");
Daniel Veillard4255d502002-04-16 15:50:10 +00002236 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002237 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED,
2238 "Element %s has both default and fixed\n",
2239 ret->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002240 } else if (fixed != NULL) {
2241 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002242 ret->value = fixed;
Daniel Veillard4255d502002-04-16 15:50:10 +00002243 }
2244
2245 child = node->children;
2246 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002247 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2248 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002249 }
2250 if (IS_SCHEMA(child, "complexType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002251 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002252 child = child->next;
2253 } else if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002254 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002255 child = child->next;
2256 }
2257 while ((IS_SCHEMA(child, "unique")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002258 (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
2259 TODO child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002260 }
2261 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002262 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD,
2263 "element %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002264 }
2265
2266 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00002267 return (ret);
2268}
2269
2270/**
2271 * xmlSchemaParseUnion:
2272 * @ctxt: a schema validation context
2273 * @schema: the schema being built
2274 * @node: a subtree containing XML Schema informations
2275 *
2276 * parse a XML schema Union definition
2277 * *WARNING* this interface is highly subject to change
2278 *
2279 * Returns -1 in case of error, 0 if the declaration is inproper and
2280 * 1 in case of success.
2281 */
2282static xmlSchemaTypePtr
2283xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002284 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002285{
2286 xmlSchemaTypePtr type, subtype, last = NULL;
2287 xmlNodePtr child = NULL;
2288 xmlChar name[30];
2289
2290 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2291 return (NULL);
2292
2293
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002294 snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002295 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002296 if (type == NULL)
2297 return (NULL);
2298 type->node = node;
Daniel Veillard377e1a92004-04-16 16:30:05 +00002299 type->type = XML_SCHEMA_TYPE_UNION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002300 type->id = xmlSchemaGetProp(ctxt, node, "id");
2301 type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes");
Daniel Veillard4255d502002-04-16 15:50:10 +00002302
2303 child = node->children;
2304 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002305 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2306 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002307 }
2308 while (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002309 subtype = (xmlSchemaTypePtr)
2310 xmlSchemaParseSimpleType(ctxt, schema, child);
2311 if (subtype != NULL) {
2312 if (last == NULL) {
2313 type->subtypes = subtype;
2314 last = subtype;
2315 } else {
2316 last->next = subtype;
2317 last = subtype;
2318 }
2319 last->next = NULL;
2320 }
2321 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002322 }
2323 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002324 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD,
2325 "Union %s has unexpected content\n", type->name,
2326 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002327 }
2328 return (type);
2329}
2330
2331/**
2332 * xmlSchemaParseList:
2333 * @ctxt: a schema validation context
2334 * @schema: the schema being built
2335 * @node: a subtree containing XML Schema informations
2336 *
2337 * parse a XML schema List definition
2338 * *WARNING* this interface is highly subject to change
2339 *
2340 * Returns -1 in case of error, 0 if the declaration is inproper and
2341 * 1 in case of success.
2342 */
2343static xmlSchemaTypePtr
2344xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002345 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002346{
2347 xmlSchemaTypePtr type, subtype;
2348 xmlNodePtr child = NULL;
2349 xmlChar name[30];
2350
2351 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2352 return (NULL);
2353
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002354 snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002355 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002356 if (type == NULL)
2357 return (NULL);
2358 type->node = node;
2359 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002360 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002361 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
2362
2363 child = node->children;
2364 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002365 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2366 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002367 }
2368 subtype = NULL;
2369 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002370 subtype = (xmlSchemaTypePtr)
2371 xmlSchemaParseSimpleType(ctxt, schema, child);
2372 child = child->next;
2373 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002374 }
2375 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002376 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD,
2377 "List %s has unexpected content\n", type->name,
2378 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002379 }
2380 return (type);
2381}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002382
Daniel Veillard4255d502002-04-16 15:50:10 +00002383/**
2384 * xmlSchemaParseSimpleType:
2385 * @ctxt: a schema validation context
2386 * @schema: the schema being built
2387 * @node: a subtree containing XML Schema informations
2388 *
2389 * parse a XML schema Simple Type definition
2390 * *WARNING* this interface is highly subject to change
2391 *
2392 * Returns -1 in case of error, 0 if the declaration is inproper and
2393 * 1 in case of success.
2394 */
2395static xmlSchemaTypePtr
2396xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2397 xmlNodePtr node)
2398{
2399 xmlSchemaTypePtr type, subtype;
2400 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002401 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00002402
2403 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2404 return (NULL);
2405
2406
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002407 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002408 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002409 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002410
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002411 snprintf(buf, 99, "simpletype %d", ctxt->counter++ + 1);
2412 type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL);
2413 } else {
2414 const xmlChar *local, *ns;
2415
2416 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2417 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002418 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002419 if (type == NULL)
2420 return (NULL);
2421 type->node = node;
2422 type->type = XML_SCHEMA_TYPE_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002423 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002424
2425 child = node->children;
2426 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002427 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2428 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002429 }
2430 subtype = NULL;
2431 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002432 subtype = (xmlSchemaTypePtr)
2433 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2434 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002435 } else if (IS_SCHEMA(child, "list")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002436 subtype = (xmlSchemaTypePtr)
2437 xmlSchemaParseList(ctxt, schema, child);
2438 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002439 } else if (IS_SCHEMA(child, "union")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002440 subtype = (xmlSchemaTypePtr)
2441 xmlSchemaParseUnion(ctxt, schema, child);
2442 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002443 }
2444 type->subtypes = subtype;
2445 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002446 xmlSchemaPErr2(ctxt, node, child,
2447 XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD,
2448 "SimpleType %s has unexpected content\n",
2449 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002450 }
2451
2452 return (type);
2453}
2454
2455
2456/**
2457 * xmlSchemaParseGroup:
2458 * @ctxt: a schema validation context
2459 * @schema: the schema being built
2460 * @node: a subtree containing XML Schema informations
2461 *
2462 * parse a XML schema Group definition
2463 * *WARNING* this interface is highly subject to change
2464 *
2465 * Returns -1 in case of error, 0 if the declaration is inproper and
2466 * 1 in case of success.
2467 */
2468static xmlSchemaTypePtr
2469xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002470 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002471{
2472 xmlSchemaTypePtr type, subtype;
2473 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002474 const xmlChar *name;
2475 const xmlChar *ref = NULL, *refNs = NULL;
2476 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002477
2478 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2479 return (NULL);
2480
2481
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002482 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002483 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002484
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002485 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2486 if (ref == NULL) {
2487 xmlSchemaPErr2(ctxt, node, child,
2488 XML_SCHEMAP_GROUP_NONAME_NOREF,
2489 "Group has no name nor ref\n", NULL, NULL);
2490 return (NULL);
2491 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002492 if (refNs == NULL)
2493 refNs = schema->targetNamespace;
2494 snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1);
2495 name = (const xmlChar *) buf;
Daniel Veillard4255d502002-04-16 15:50:10 +00002496 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002497 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002498 if (type == NULL)
2499 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00002500
Daniel Veillard4255d502002-04-16 15:50:10 +00002501 type->node = node;
2502 type->type = XML_SCHEMA_TYPE_GROUP;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002503 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002504 type->ref = ref;
2505 type->refNs = refNs;
2506 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2507 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2508
2509 child = node->children;
2510 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002511 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2512 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002513 }
2514 subtype = NULL;
2515 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002516 subtype = (xmlSchemaTypePtr)
2517 xmlSchemaParseAll(ctxt, schema, child);
2518 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002519 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002520 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2521 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002522 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002523 subtype = (xmlSchemaTypePtr)
2524 xmlSchemaParseSequence(ctxt, schema, child);
2525 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002526 }
2527 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002528 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002529 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002530 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD,
2531 "Group %s has unexpected content\n", type->name,
2532 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002533 }
2534
2535 return (type);
2536}
2537
2538/**
2539 * xmlSchemaParseAll:
2540 * @ctxt: a schema validation context
2541 * @schema: the schema being built
2542 * @node: a subtree containing XML Schema informations
2543 *
2544 * parse a XML schema All definition
2545 * *WARNING* this interface is highly subject to change
2546 *
2547 * Returns -1 in case of error, 0 if the declaration is inproper and
2548 * 1 in case of success.
2549 */
2550static xmlSchemaTypePtr
2551xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002552 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002553{
2554 xmlSchemaTypePtr type, subtype, last = NULL;
2555 xmlNodePtr child = NULL;
2556 xmlChar name[30];
2557
2558 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2559 return (NULL);
2560
2561
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002562 snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002563 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002564 if (type == NULL)
2565 return (NULL);
2566 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002567 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002568 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002569 type->minOccurs = xmlGetMinOccurs(ctxt, node);
William M. Brackb15351e2003-12-27 04:34:42 +00002570 if (type->minOccurs > 1)
2571 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS,
2572 "invalid value for minOccurs (must be 0 or 1)\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002573 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
William M. Brackb15351e2003-12-27 04:34:42 +00002574 if (type->maxOccurs > 1)
2575 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS,
2576 "invalid value for maxOccurs (must be 0 or 1)\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002577
2578 child = node->children;
2579 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002580 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2581 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002582 }
2583 while (IS_SCHEMA(child, "element")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002584 subtype = (xmlSchemaTypePtr)
2585 xmlSchemaParseElement(ctxt, schema, child, 0);
2586 if (subtype != NULL) {
William M. Brackb15351e2003-12-27 04:34:42 +00002587 if (subtype->minOccurs > 1)
2588 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MINOCCURS,
2589 "invalid value for minOccurs (must be 0 or 1)\n",
2590 NULL, NULL);
2591 if (subtype->maxOccurs > 1)
2592 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MAXOCCURS,
2593 "invalid value for maxOccurs (must be 0 or 1)\n",
2594 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002595 if (last == NULL) {
2596 type->subtypes = subtype;
2597 last = subtype;
2598 } else {
2599 last->next = subtype;
2600 last = subtype;
2601 }
2602 last->next = NULL;
2603 }
2604 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002605 }
2606 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002607 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD,
2608 "All %s has unexpected content\n", type->name,
2609 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002610 }
2611
2612 return (type);
2613}
2614
2615/**
Daniel Veillard1d913862003-11-21 00:28:39 +00002616 * xmlSchemaImportSchema
2617 *
2618 * @ctxt: a schema validation context
2619 * @schemaLocation: an URI defining where to find the imported schema
2620 *
2621 * import a XML schema
2622 * *WARNING* this interface is highly subject to change
2623 *
2624 * Returns -1 in case of error and 1 in case of success.
2625 */
2626static xmlSchemaImportPtr
2627xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt,
2628 const xmlChar *schemaLocation)
2629{
2630 xmlSchemaImportPtr import;
2631 xmlSchemaParserCtxtPtr newctxt;
2632
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002633 newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
Daniel Veillard1d913862003-11-21 00:28:39 +00002634 if (newctxt == NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002635 xmlSchemaPErrMemory(ctxt, "allocating schama parser context",
Daniel Veillard1d913862003-11-21 00:28:39 +00002636 NULL);
2637 return (NULL);
2638 }
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002639 memset(newctxt, 0, sizeof(xmlSchemaParserCtxt));
2640 /* Keep the same dictionnary for parsing, really */
2641 xmlDictReference(ctxt->dict);
2642 newctxt->dict = ctxt->dict;
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002643 newctxt->includes = 0;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002644 newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1);
2645
Daniel Veillard1d913862003-11-21 00:28:39 +00002646 xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning,
2647 ctxt->userData);
2648
2649 import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport));
2650 if (import == NULL) {
2651 xmlSchemaPErrMemory(NULL, "allocating imported schema",
2652 NULL);
2653 xmlSchemaFreeParserCtxt(newctxt);
2654 return (NULL);
2655 }
2656
2657 memset(import, 0, sizeof(xmlSchemaImport));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002658 import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
Daniel Veillard1d913862003-11-21 00:28:39 +00002659 import->schema = xmlSchemaParse(newctxt);
2660
2661 if (import->schema == NULL) {
2662 /* FIXME use another error enum here ? */
2663 xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL,
2664 "failed to import schema at location %s\n",
2665 schemaLocation, NULL);
2666
2667 xmlSchemaFreeParserCtxt(newctxt);
2668 if (import->schemaLocation != NULL)
2669 xmlFree((xmlChar *)import->schemaLocation);
2670 xmlFree(import);
2671 return NULL;
2672 }
2673
2674 xmlSchemaFreeParserCtxt(newctxt);
2675 return import;
2676}
2677
2678
2679/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002680 * xmlSchemaParseImport:
2681 * @ctxt: a schema validation context
2682 * @schema: the schema being built
2683 * @node: a subtree containing XML Schema informations
2684 *
2685 * parse a XML schema Import definition
2686 * *WARNING* this interface is highly subject to change
2687 *
2688 * Returns -1 in case of error, 0 if the declaration is inproper and
2689 * 1 in case of success.
2690 */
2691static int
2692xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002693 xmlNodePtr node)
Daniel Veillard5a872412002-05-22 06:40:27 +00002694{
2695 xmlNodePtr child = NULL;
Daniel Veillard1d913862003-11-21 00:28:39 +00002696 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002697 const xmlChar *namespace;
2698 const xmlChar *schemaLocation;
Daniel Veillard1d913862003-11-21 00:28:39 +00002699 const xmlChar *previous;
Daniel Veillard5a872412002-05-22 06:40:27 +00002700 xmlURIPtr check;
2701
Daniel Veillard1d913862003-11-21 00:28:39 +00002702
Daniel Veillard5a872412002-05-22 06:40:27 +00002703 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2704 return (-1);
2705
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002706 namespace = xmlSchemaGetProp(ctxt, node, "namespace");
Daniel Veillard5a872412002-05-22 06:40:27 +00002707 if (namespace != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002708 check = xmlParseURI((const char *) namespace);
2709 if (check == NULL) {
2710 xmlSchemaPErr2(ctxt, node, child,
2711 XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI,
2712 "Import namespace attribute is not an URI: %s\n",
2713 namespace, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002714 return (-1);
2715 } else {
2716 xmlFreeURI(check);
2717 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002718 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002719 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
Daniel Veillard5a872412002-05-22 06:40:27 +00002720 if (schemaLocation != NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002721 xmlChar *base = NULL;
2722 xmlChar *URI = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002723 check = xmlParseURI((const char *) schemaLocation);
2724 if (check == NULL) {
2725 xmlSchemaPErr2(ctxt, node, child,
2726 XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI,
2727 "Import schemaLocation attribute is not an URI: %s\n",
2728 schemaLocation, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002729 return (-1);
2730 } else {
2731 xmlFreeURI(check);
2732 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002733 base = xmlNodeGetBase(node->doc, node);
2734 if (base == NULL) {
2735 URI = xmlBuildURI(schemaLocation, node->doc->URL);
2736 } else {
2737 URI = xmlBuildURI(schemaLocation, base);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002738 xmlFree(base);
Daniel Veillard1d913862003-11-21 00:28:39 +00002739 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002740 if (URI != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002741 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
2742 xmlFree(URI);
Daniel Veillard1d913862003-11-21 00:28:39 +00002743 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002744 }
2745 if (schema->schemasImports == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002746 schema->schemasImports = xmlHashCreate(10);
2747 if (schema->schemasImports == NULL) {
2748 xmlSchemaPErr2(ctxt, node, child,
2749 XML_SCHEMAP_FAILED_BUILD_IMPORT,
2750 "Internal: failed to build import table\n",
2751 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002752 return (-1);
2753 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002754 }
2755 if (namespace == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002756 import = xmlHashLookup(schema->schemasImports,
2757 XML_SCHEMAS_DEFAULT_NAMESPACE);
2758 if (import != NULL)
2759 previous = import->schemaLocation;
2760 else
2761 previous = NULL;
2762
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002763 if (schemaLocation != NULL) {
2764 if (previous != NULL) {
2765 if (!xmlStrEqual(schemaLocation, previous)) {
2766 xmlSchemaPErr2(ctxt, node, child,
2767 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2768 "Redefining import for default namespace with a different URI: %s\n",
2769 schemaLocation, NULL);
2770 }
2771 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002772 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2773 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002774 return (-1);
2775 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002776 xmlHashAddEntry(schema->schemasImports,
2777 XML_SCHEMAS_DEFAULT_NAMESPACE,
Daniel Veillard1d913862003-11-21 00:28:39 +00002778 import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002779 }
2780 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002781 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002782 import = xmlHashLookup(schema->schemasImports, namespace);
2783 if (import != NULL)
2784 previous = import->schemaLocation;
2785 else
2786 previous = NULL;
2787
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002788 if (schemaLocation != NULL) {
2789 if (previous != NULL) {
2790 if (!xmlStrEqual(schemaLocation, previous)) {
2791 xmlSchemaPErr2(ctxt, node, child,
2792 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2793 "Redefining import for namespace %s with a different URI: %s\n",
2794 namespace, schemaLocation);
2795 }
2796 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002797 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2798 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002799 return (-1);
2800 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002801 xmlHashAddEntry(schema->schemasImports,
Daniel Veillard1d913862003-11-21 00:28:39 +00002802 namespace, import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002803 }
2804 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002805 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002806
2807 child = node->children;
2808 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002809 /*
2810 * the annotations here are simply discarded ...
2811 */
2812 child = child->next;
Daniel Veillard5a872412002-05-22 06:40:27 +00002813 }
2814 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002815 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD,
2816 "Import has unexpected content\n", NULL, NULL);
2817 return (-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002818 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002819 return (1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002820}
2821
2822/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002823 * xmlSchemaCleanupDoc:
2824 * @ctxt: a schema validation context
2825 * @node: the root of the document.
2826 *
2827 * removes unwanted nodes in a schemas document tree
2828 */
2829static void
2830xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root)
2831{
2832 xmlNodePtr delete, cur;
2833
2834 if ((ctxt == NULL) || (root == NULL)) return;
2835
2836 /*
2837 * Remove all the blank text nodes
2838 */
2839 delete = NULL;
2840 cur = root;
2841 while (cur != NULL) {
2842 if (delete != NULL) {
2843 xmlUnlinkNode(delete);
2844 xmlFreeNode(delete);
2845 delete = NULL;
2846 }
2847 if (cur->type == XML_TEXT_NODE) {
2848 if (IS_BLANK_NODE(cur)) {
2849 if (xmlNodeGetSpacePreserve(cur) != 1) {
2850 delete = cur;
2851 }
2852 }
2853 } else if ((cur->type != XML_ELEMENT_NODE) &&
2854 (cur->type != XML_CDATA_SECTION_NODE)) {
2855 delete = cur;
2856 goto skip_children;
2857 }
2858
2859 /*
2860 * Skip to next node
2861 */
2862 if (cur->children != NULL) {
2863 if ((cur->children->type != XML_ENTITY_DECL) &&
2864 (cur->children->type != XML_ENTITY_REF_NODE) &&
2865 (cur->children->type != XML_ENTITY_NODE)) {
2866 cur = cur->children;
2867 continue;
2868 }
2869 }
2870 skip_children:
2871 if (cur->next != NULL) {
2872 cur = cur->next;
2873 continue;
2874 }
2875
2876 do {
2877 cur = cur->parent;
2878 if (cur == NULL)
2879 break;
2880 if (cur == root) {
2881 cur = NULL;
2882 break;
2883 }
2884 if (cur->next != NULL) {
2885 cur = cur->next;
2886 break;
2887 }
2888 } while (cur != NULL);
2889 }
2890 if (delete != NULL) {
2891 xmlUnlinkNode(delete);
2892 xmlFreeNode(delete);
2893 delete = NULL;
2894 }
2895}
2896
2897/**
2898 * xmlSchemaParseSchemaTopLevel:
2899 * @ctxt: a schema validation context
2900 * @schema: the schemas
2901 * @nodes: the list of top level nodes
2902 *
2903 * Returns the internal XML Schema structure built from the resource or
2904 * NULL in case of error
2905 */
2906static void
2907xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt,
2908 xmlSchemaPtr schema, xmlNodePtr nodes)
2909{
2910 xmlNodePtr child;
2911 xmlSchemaAnnotPtr annot;
2912
2913 if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL))
2914 return;
2915
2916 child = nodes;
2917 while ((IS_SCHEMA(child, "include")) ||
2918 (IS_SCHEMA(child, "import")) ||
2919 (IS_SCHEMA(child, "redefine")) ||
2920 (IS_SCHEMA(child, "annotation"))) {
2921 if (IS_SCHEMA(child, "annotation")) {
2922 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2923 if (schema->annot == NULL)
2924 schema->annot = annot;
2925 else
2926 xmlSchemaFreeAnnot(annot);
2927 } else if (IS_SCHEMA(child, "import")) {
2928 xmlSchemaParseImport(ctxt, schema, child);
2929 } else if (IS_SCHEMA(child, "include")) {
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002930 ctxt->includes++;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002931 xmlSchemaParseInclude(ctxt, schema, child);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002932 ctxt->includes--;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002933 } else if (IS_SCHEMA(child, "redefine")) {
2934 TODO
2935 }
2936 child = child->next;
2937 }
2938 while (child != NULL) {
2939 if (IS_SCHEMA(child, "complexType")) {
2940 xmlSchemaParseComplexType(ctxt, schema, child);
2941 child = child->next;
2942 } else if (IS_SCHEMA(child, "simpleType")) {
2943 xmlSchemaParseSimpleType(ctxt, schema, child);
2944 child = child->next;
2945 } else if (IS_SCHEMA(child, "element")) {
2946 xmlSchemaParseElement(ctxt, schema, child, 1);
2947 child = child->next;
2948 } else if (IS_SCHEMA(child, "attribute")) {
2949 xmlSchemaParseAttribute(ctxt, schema, child);
2950 child = child->next;
2951 } else if (IS_SCHEMA(child, "attributeGroup")) {
2952 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2953 child = child->next;
2954 } else if (IS_SCHEMA(child, "group")) {
2955 xmlSchemaParseGroup(ctxt, schema, child);
2956 child = child->next;
2957 } else if (IS_SCHEMA(child, "notation")) {
2958 xmlSchemaParseNotation(ctxt, schema, child);
2959 child = child->next;
2960 } else {
2961 xmlSchemaPErr2(ctxt, NULL, child,
2962 XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD,
2963 "Schemas: unexpected element %s here \n",
2964 child->name, NULL);
2965 child = child->next;
2966 }
2967 while (IS_SCHEMA(child, "annotation")) {
2968 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2969 if (schema->annot == NULL)
2970 schema->annot = annot;
2971 else
2972 xmlSchemaFreeAnnot(annot);
2973 child = child->next;
2974 }
2975 }
2976}
2977
2978/**
2979 * xmlSchemaParseInclude:
2980 * @ctxt: a schema validation context
2981 * @schema: the schema being built
2982 * @node: a subtree containing XML Schema informations
2983 *
2984 * parse a XML schema Include definition
2985 *
2986 * Returns -1 in case of error, 0 if the declaration is inproper and
2987 * 1 in case of success.
2988 */
2989static int
2990xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2991 xmlNodePtr node)
2992{
2993 xmlNodePtr child = NULL;
2994 const xmlChar *schemaLocation;
2995 xmlURIPtr check;
2996 xmlDocPtr doc;
2997 xmlNodePtr root;
2998 xmlSchemaIncludePtr include;
2999
3000
3001 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3002 return (-1);
3003
3004 /*
3005 * Preliminary step, extract the URI-Reference for the include and
3006 * make an URI from the base.
3007 */
3008 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
3009 if (schemaLocation != NULL) {
3010 xmlChar *base = NULL;
3011 xmlChar *URI = NULL;
3012 check = xmlParseURI((const char *) schemaLocation);
3013 if (check == NULL) {
3014 xmlSchemaPErr2(ctxt, node, child,
3015 XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI,
3016 "Include schemaLocation attribute is not an URI: %s\n",
3017 schemaLocation, NULL);
3018 return (-1);
3019 } else {
3020 xmlFreeURI(check);
3021 }
3022 base = xmlNodeGetBase(node->doc, node);
3023 if (base == NULL) {
3024 URI = xmlBuildURI(schemaLocation, node->doc->URL);
3025 } else {
3026 URI = xmlBuildURI(schemaLocation, base);
3027 xmlFree(base);
3028 }
3029 if (URI != NULL) {
3030 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
3031 xmlFree(URI);
3032 }
3033 } else {
3034 xmlSchemaPErr2(ctxt, node, child,
3035 XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI,
3036 "Include schemaLocation attribute missing\n",
3037 NULL, NULL);
3038 return (-1);
3039 }
3040
3041 child = node->children;
3042 while (IS_SCHEMA(child, "annotation")) {
3043 /*
3044 * the annotations here are simply discarded ...
3045 */
3046 child = child->next;
3047 }
3048 if (child != NULL) {
3049 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD,
3050 "Include has unexpected content\n", NULL, NULL);
3051 return (-1);
3052 }
3053
3054 /*
3055 * First step is to parse the input document into an DOM/Infoset
3056 */
3057 doc = xmlReadFile((const char *) schemaLocation, NULL,
3058 SCHEMAS_PARSE_OPTIONS);
3059 if (doc == NULL) {
3060 xmlSchemaPErr(ctxt, NULL,
3061 XML_SCHEMAP_FAILED_LOAD,
3062 "xmlSchemaParse: could not load %s\n",
3063 ctxt->URL, NULL);
3064 return(-1);
3065 }
3066
3067 /*
3068 * Then extract the root of the schema
3069 */
3070 root = xmlDocGetRootElement(doc);
3071 if (root == NULL) {
3072 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3073 XML_SCHEMAP_NOROOT,
3074 "schemas %s has no root", schemaLocation, NULL);
3075 xmlFreeDoc(doc);
3076 return (-1);
3077 }
3078
3079 /*
3080 * Remove all the blank text nodes
3081 */
3082 xmlSchemaCleanupDoc(ctxt, root);
3083
3084 /*
3085 * Check the schemas top level element
3086 */
3087 if (!IS_SCHEMA(root, "schema")) {
3088 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3089 XML_SCHEMAP_NOT_SCHEMA,
3090 "File %s is not a schemas", schemaLocation, NULL);
3091 xmlFreeDoc(doc);
3092 return (-1);
3093 }
3094
3095 /*
3096 * register the include
3097 */
3098 include = (xmlSchemaIncludePtr) xmlMalloc(sizeof(xmlSchemaInclude));
3099 if (include == NULL) {
3100 xmlSchemaPErrMemory(ctxt, "allocating included schema", NULL);
3101 xmlFreeDoc(doc);
3102 return (-1);
3103 }
3104
3105 memset(include, 0, sizeof(xmlSchemaInclude));
3106 include->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
3107 include->doc = doc;
3108 include->next = schema->includes;
3109 schema->includes = include;
3110
3111
3112 /*
3113 * parse the declarations in the included file like if they
3114 * were in the original file.
3115 */
3116 xmlSchemaParseSchemaTopLevel(ctxt, schema, root->children);
3117
3118 return (1);
3119}
3120
3121/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003122 * xmlSchemaParseChoice:
3123 * @ctxt: a schema validation context
3124 * @schema: the schema being built
3125 * @node: a subtree containing XML Schema informations
3126 *
3127 * parse a XML schema Choice definition
3128 * *WARNING* this interface is highly subject to change
3129 *
3130 * Returns -1 in case of error, 0 if the declaration is inproper and
3131 * 1 in case of success.
3132 */
3133static xmlSchemaTypePtr
3134xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003135 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003136{
3137 xmlSchemaTypePtr type, subtype, last = NULL;
3138 xmlNodePtr child = NULL;
3139 xmlChar name[30];
3140
3141 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3142 return (NULL);
3143
3144
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003145 snprintf((char *) name, 30, "choice %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003146 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003147 if (type == NULL)
3148 return (NULL);
3149 type->node = node;
3150 type->type = XML_SCHEMA_TYPE_CHOICE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003151 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003152 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3153 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3154
3155 child = node->children;
3156 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003157 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3158 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003159 }
3160 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003161 (IS_SCHEMA(child, "group")) ||
3162 (IS_SCHEMA(child, "any")) ||
3163 (IS_SCHEMA(child, "choice")) ||
3164 (IS_SCHEMA(child, "sequence"))) {
3165 subtype = NULL;
3166 if (IS_SCHEMA(child, "element")) {
3167 subtype = (xmlSchemaTypePtr)
3168 xmlSchemaParseElement(ctxt, schema, child, 0);
3169 } else if (IS_SCHEMA(child, "group")) {
3170 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3171 } else if (IS_SCHEMA(child, "any")) {
3172 subtype = xmlSchemaParseAny(ctxt, schema, child);
3173 } else if (IS_SCHEMA(child, "sequence")) {
3174 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3175 } else if (IS_SCHEMA(child, "choice")) {
3176 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3177 }
3178 if (subtype != NULL) {
3179 if (last == NULL) {
3180 type->subtypes = subtype;
3181 last = subtype;
3182 } else {
3183 last->next = subtype;
3184 last = subtype;
3185 }
3186 last->next = NULL;
3187 }
3188 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003189 }
3190 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003191 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_CHOICE_CHILD,
3192 "Choice %s has unexpected content\n", type->name,
3193 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003194 }
3195
3196 return (type);
3197}
3198
3199/**
3200 * xmlSchemaParseSequence:
3201 * @ctxt: a schema validation context
3202 * @schema: the schema being built
3203 * @node: a subtree containing XML Schema informations
3204 *
3205 * parse a XML schema Sequence definition
3206 * *WARNING* this interface is highly subject to change
3207 *
3208 * Returns -1 in case of error, 0 if the declaration is inproper and
3209 * 1 in case of success.
3210 */
3211static xmlSchemaTypePtr
3212xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003213 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003214{
3215 xmlSchemaTypePtr type, subtype, last = NULL;
3216 xmlNodePtr child = NULL;
3217 xmlChar name[30];
3218
3219 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3220 return (NULL);
3221
3222
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003223 snprintf((char *) name, 30, "sequence %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003224 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003225 if (type == NULL)
3226 return (NULL);
3227 type->node = node;
3228 type->type = XML_SCHEMA_TYPE_SEQUENCE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003229 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003230 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3231 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3232
3233 child = node->children;
3234 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003235 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3236 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003237 }
3238 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003239 (IS_SCHEMA(child, "group")) ||
3240 (IS_SCHEMA(child, "any")) ||
3241 (IS_SCHEMA(child, "choice")) ||
3242 (IS_SCHEMA(child, "sequence"))) {
3243 subtype = NULL;
3244 if (IS_SCHEMA(child, "element")) {
3245 subtype = (xmlSchemaTypePtr)
3246 xmlSchemaParseElement(ctxt, schema, child, 0);
3247 } else if (IS_SCHEMA(child, "group")) {
3248 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3249 } else if (IS_SCHEMA(child, "any")) {
3250 subtype = xmlSchemaParseAny(ctxt, schema, child);
3251 } else if (IS_SCHEMA(child, "choice")) {
3252 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3253 } else if (IS_SCHEMA(child, "sequence")) {
3254 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3255 }
3256 if (subtype != NULL) {
3257 if (last == NULL) {
3258 type->subtypes = subtype;
3259 last = subtype;
3260 } else {
3261 last->next = subtype;
3262 last = subtype;
3263 }
3264 last->next = NULL;
3265 }
3266 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003267 }
3268 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003269 xmlSchemaPErr2(ctxt, node, child,
3270 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
3271 "Sequence %s has unexpected content\n", type->name,
3272 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003273 }
3274
3275 return (type);
3276}
3277
3278/**
3279 * xmlSchemaParseRestriction:
3280 * @ctxt: a schema validation context
3281 * @schema: the schema being built
3282 * @node: a subtree containing XML Schema informations
3283 * @simple: is that part of a simple type.
3284 *
3285 * parse a XML schema Restriction definition
3286 * *WARNING* this interface is highly subject to change
3287 *
3288 * Returns the type definition or NULL in case of error
3289 */
3290static xmlSchemaTypePtr
3291xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3292 xmlNodePtr node, int simple)
3293{
3294 xmlSchemaTypePtr type, subtype;
3295 xmlSchemaFacetPtr facet, lastfacet = NULL;
3296 xmlNodePtr child = NULL;
3297 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003298 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003299
3300 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3301 return (NULL);
3302
3303 oldcontainer = ctxt->container;
3304
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003305 snprintf((char *) name, 30, "restriction %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003306 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003307 if (type == NULL)
3308 return (NULL);
3309 type->node = node;
3310 type->type = XML_SCHEMA_TYPE_RESTRICTION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003311 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003312 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3313 if ((!simple) && (type->base == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003314 xmlSchemaPErr2(ctxt, node, child,
3315 XML_SCHEMAP_RESTRICTION_NONAME_NOREF,
3316 "Restriction %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003317 }
3318 ctxt->container = name;
3319
3320 child = node->children;
3321 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003322 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3323 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003324 }
3325 subtype = NULL;
3326
3327 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003328 subtype = (xmlSchemaTypePtr)
3329 xmlSchemaParseAll(ctxt, schema, child);
3330 child = child->next;
3331 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003332 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003333 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3334 child = child->next;
3335 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003336 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003337 subtype = (xmlSchemaTypePtr)
3338 xmlSchemaParseSequence(ctxt, schema, child);
3339 child = child->next;
3340 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003341 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003342 subtype = (xmlSchemaTypePtr)
3343 xmlSchemaParseGroup(ctxt, schema, child);
3344 child = child->next;
3345 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003346 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003347 if (IS_SCHEMA(child, "simpleType")) {
3348 subtype = (xmlSchemaTypePtr)
3349 xmlSchemaParseSimpleType(ctxt, schema, child);
3350 child = child->next;
3351 type->baseType = subtype;
3352 }
3353 /*
3354 * Facets
3355 */
Daniel Veillard4255d502002-04-16 15:50:10 +00003356 while ((IS_SCHEMA(child, "minInclusive")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003357 (IS_SCHEMA(child, "minExclusive")) ||
3358 (IS_SCHEMA(child, "maxInclusive")) ||
3359 (IS_SCHEMA(child, "maxExclusive")) ||
3360 (IS_SCHEMA(child, "totalDigits")) ||
3361 (IS_SCHEMA(child, "fractionDigits")) ||
3362 (IS_SCHEMA(child, "pattern")) ||
3363 (IS_SCHEMA(child, "enumeration")) ||
3364 (IS_SCHEMA(child, "whiteSpace")) ||
3365 (IS_SCHEMA(child, "length")) ||
3366 (IS_SCHEMA(child, "maxLength")) ||
3367 (IS_SCHEMA(child, "minLength"))) {
3368 facet = xmlSchemaParseFacet(ctxt, schema, child);
3369 if (facet != NULL) {
3370 if (lastfacet == NULL) {
3371 type->facets = facet;
3372 lastfacet = facet;
3373 } else {
3374 lastfacet->next = facet;
3375 lastfacet = facet;
3376 }
3377 lastfacet->next = NULL;
3378 }
3379 child = child->next;
3380 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003381 }
3382 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3383 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003384 xmlSchemaPErr2(ctxt, node, child,
3385 XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD,
3386 "Restriction %s has unexpected content\n",
3387 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003388 }
3389 ctxt->container = oldcontainer;
3390 return (type);
3391}
3392
3393/**
3394 * xmlSchemaParseExtension:
3395 * @ctxt: a schema validation context
3396 * @schema: the schema being built
3397 * @node: a subtree containing XML Schema informations
3398 *
3399 * parse a XML schema Extension definition
3400 * *WARNING* this interface is highly subject to change
3401 *
3402 * Returns the type definition or NULL in case of error
3403 */
3404static xmlSchemaTypePtr
3405xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003406 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003407{
3408 xmlSchemaTypePtr type, subtype;
3409 xmlNodePtr child = NULL;
3410 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003411 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003412
3413 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3414 return (NULL);
3415
3416 oldcontainer = ctxt->container;
3417
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003418 snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003419 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003420 if (type == NULL)
3421 return (NULL);
3422 type->node = node;
3423 type->type = XML_SCHEMA_TYPE_EXTENSION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003424 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003425 ctxt->container = name;
3426
3427 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3428 if (type->base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003429 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_EXTENSION_NO_BASE,
3430 "Extension %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003431 }
3432 child = node->children;
3433 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003434 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3435 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003436 }
3437 subtype = NULL;
3438
3439 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003440 subtype = xmlSchemaParseAll(ctxt, schema, child);
3441 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003442 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003443 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3444 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003445 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003446 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3447 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003448 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003449 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3450 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003451 }
3452 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003453 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003454 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3455 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003456 xmlSchemaPErr2(ctxt, node, child,
3457 XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD,
3458 "Extension %s has unexpected content\n", type->name,
3459 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003460 }
3461 ctxt->container = oldcontainer;
3462 return (type);
3463}
3464
3465/**
3466 * xmlSchemaParseSimpleContent:
3467 * @ctxt: a schema validation context
3468 * @schema: the schema being built
3469 * @node: a subtree containing XML Schema informations
3470 *
3471 * parse a XML schema SimpleContent definition
3472 * *WARNING* this interface is highly subject to change
3473 *
3474 * Returns the type definition or NULL in case of error
3475 */
3476static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003477xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt,
3478 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003479{
3480 xmlSchemaTypePtr type, subtype;
3481 xmlNodePtr child = NULL;
3482 xmlChar name[30];
3483
3484 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3485 return (NULL);
3486
3487
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003488 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003489 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003490 if (type == NULL)
3491 return (NULL);
3492 type->node = node;
3493 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003494 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003495
3496 child = node->children;
3497 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003498 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3499 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003500 }
3501 subtype = NULL;
3502 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003503 subtype = (xmlSchemaTypePtr)
3504 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3505 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003506 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003507 subtype = (xmlSchemaTypePtr)
3508 xmlSchemaParseExtension(ctxt, schema, child);
3509 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003510 }
3511 type->subtypes = subtype;
3512 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003513 xmlSchemaPErr2(ctxt, node, child,
3514 XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD,
3515 "SimpleContent %s has unexpected content\n",
3516 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003517 }
3518 return (type);
3519}
3520
3521/**
3522 * xmlSchemaParseComplexContent:
3523 * @ctxt: a schema validation context
3524 * @schema: the schema being built
3525 * @node: a subtree containing XML Schema informations
3526 *
3527 * parse a XML schema ComplexContent definition
3528 * *WARNING* this interface is highly subject to change
3529 *
3530 * Returns the type definition or NULL in case of error
3531 */
3532static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003533xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt,
3534 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003535{
3536 xmlSchemaTypePtr type, subtype;
3537 xmlNodePtr child = NULL;
3538 xmlChar name[30];
3539
3540 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3541 return (NULL);
3542
3543
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003544 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003545 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003546 if (type == NULL)
3547 return (NULL);
3548 type->node = node;
3549 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003550 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003551
3552 child = node->children;
3553 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003554 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3555 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003556 }
3557 subtype = NULL;
3558 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003559 subtype = (xmlSchemaTypePtr)
3560 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3561 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003562 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003563 subtype = (xmlSchemaTypePtr)
3564 xmlSchemaParseExtension(ctxt, schema, child);
3565 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003566 }
3567 type->subtypes = subtype;
3568 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003569 xmlSchemaPErr2(ctxt, node, child,
3570 XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD,
3571 "ComplexContent %s has unexpected content\n",
3572 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003573 }
3574 return (type);
3575}
3576
3577/**
3578 * xmlSchemaParseComplexType:
3579 * @ctxt: a schema validation context
3580 * @schema: the schema being built
3581 * @node: a subtree containing XML Schema informations
3582 *
3583 * parse a XML schema Complex Type definition
3584 * *WARNING* this interface is highly subject to change
3585 *
3586 * Returns the type definition or NULL in case of error
3587 */
3588static xmlSchemaTypePtr
3589xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3590 xmlNodePtr node)
3591{
3592 xmlSchemaTypePtr type, subtype;
3593 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003594 const xmlChar *name;
3595 const xmlChar *oldcontainer;
Daniel Veillard1aefc862004-03-04 11:40:48 +00003596 const xmlChar *mixed;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003597 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00003598
3599 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3600 return (NULL);
3601
3602 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003603 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00003604 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003605
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003606 snprintf(buf, 99, "anontype %d", ctxt->counter++ + 1);
3607 name = (const xmlChar *)buf;
3608 type = xmlSchemaAddType(ctxt, schema, name, NULL);
3609 } else {
3610 const xmlChar *local, *ns;
3611
3612 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
3613 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00003614 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003615 if (type == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003616 return (NULL);
3617 }
Daniel Veillard1aefc862004-03-04 11:40:48 +00003618
3619 mixed = xmlSchemaGetProp(ctxt, node, "mixed");
3620 if (mixed != NULL)
3621 type->flags |= XML_SCHEMAS_TYPE_MIXED;
3622
Daniel Veillard4255d502002-04-16 15:50:10 +00003623 type->node = node;
3624 type->type = XML_SCHEMA_TYPE_COMPLEX;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003625 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003626 ctxt->container = name;
3627
3628 child = node->children;
3629 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003630 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3631 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003632 }
3633 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003634 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
3635 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003636 } else if (IS_SCHEMA(child, "complexContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003637 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
3638 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003639 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003640 subtype = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003641
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003642 if (IS_SCHEMA(child, "all")) {
3643 subtype = xmlSchemaParseAll(ctxt, schema, child);
3644 child = child->next;
3645 } else if (IS_SCHEMA(child, "choice")) {
3646 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3647 child = child->next;
3648 } else if (IS_SCHEMA(child, "sequence")) {
3649 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3650 child = child->next;
3651 } else if (IS_SCHEMA(child, "group")) {
3652 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3653 child = child->next;
3654 }
3655 if (subtype != NULL)
3656 type->subtypes = subtype;
3657 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
Daniel Veillard4255d502002-04-16 15:50:10 +00003658 }
3659 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003660 xmlSchemaPErr2(ctxt, node, child,
3661 XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD,
3662 "ComplexType %s has unexpected content\n",
3663 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003664 }
3665 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003666 return (type);
3667}
3668
Daniel Veillard4255d502002-04-16 15:50:10 +00003669/**
3670 * xmlSchemaParseSchema:
3671 * @ctxt: a schema validation context
3672 * @node: a subtree containing XML Schema informations
3673 *
3674 * parse a XML schema definition from a node set
3675 * *WARNING* this interface is highly subject to change
3676 *
3677 * Returns the internal XML Schema structure built from the resource or
3678 * NULL in case of error
3679 */
3680static xmlSchemaPtr
3681xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3682{
3683 xmlSchemaPtr schema = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003684 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003685 const xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003686 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003687
3688 if ((ctxt == NULL) || (node == NULL))
3689 return (NULL);
3690
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003691 nberrors = ctxt->nberrors;
3692 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003693 if (IS_SCHEMA(node, "schema")) {
3694 schema = xmlSchemaNewSchema(ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003695 if (schema == NULL)
3696 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003697 val = xmlSchemaGetProp(ctxt, node, "targetNamespace");
3698 if (val != NULL) {
3699 schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1);
3700 } else {
3701 schema->targetNamespace = NULL;
3702 }
3703 schema->id = xmlSchemaGetProp(ctxt, node, "id");
3704 schema->version = xmlSchemaGetProp(ctxt, node, "version");
3705 val = xmlSchemaGetProp(ctxt, node, "elementFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003706 if (val != NULL) {
3707 if (xmlStrEqual(val, BAD_CAST "qualified"))
3708 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3709 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3710 xmlSchemaPErr2(ctxt, node, child,
3711 XML_SCHEMAP_ELEMFORMDEFAULT_VALUE,
3712 "Invalid value %s for elementFormDefault\n",
3713 val, NULL);
3714 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003715 } else {
3716 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3717 }
3718 val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003719 if (val != NULL) {
3720 if (xmlStrEqual(val, BAD_CAST "qualified"))
3721 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3722 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3723 xmlSchemaPErr2(ctxt, node, child,
3724 XML_SCHEMAP_ATTRFORMDEFAULT_VALUE,
3725 "Invalid value %s for attributeFormDefault\n",
3726 val, NULL);
3727 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003728 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003729
Daniel Veillardbd2904b2003-11-25 15:38:59 +00003730 xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children);
3731 } else {
3732 xmlDocPtr doc;
3733
3734 doc = node->doc;
3735
3736 if ((doc != NULL) && (doc->URL != NULL)) {
3737 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3738 XML_SCHEMAP_NOT_SCHEMA,
3739 "File %s is not a schemas", doc->URL, NULL);
3740 } else {
3741 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3742 XML_SCHEMAP_NOT_SCHEMA,
3743 "File is not a schemas", NULL, NULL);
3744 }
3745 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003746 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003747 if (ctxt->nberrors != 0) {
3748 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003749 xmlSchemaFree(schema);
3750 schema = NULL;
3751 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003752 }
3753 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003754#ifdef DEBUG
3755 if (schema == NULL)
3756 xmlGenericError(xmlGenericErrorContext,
3757 "xmlSchemaParse() failed\n");
3758#endif
3759
3760 return (schema);
3761}
3762
3763/************************************************************************
3764 * *
3765 * Validating using Schemas *
3766 * *
3767 ************************************************************************/
3768
3769/************************************************************************
3770 * *
3771 * Reading/Writing Schemas *
3772 * *
3773 ************************************************************************/
3774
3775/**
3776 * xmlSchemaNewParserCtxt:
3777 * @URL: the location of the schema
3778 *
3779 * Create an XML Schemas parse context for that file/resource expected
3780 * to contain an XML Schemas file.
3781 *
3782 * Returns the parser context or NULL in case of error
3783 */
3784xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003785xmlSchemaNewParserCtxt(const char *URL)
3786{
Daniel Veillard4255d502002-04-16 15:50:10 +00003787 xmlSchemaParserCtxtPtr ret;
3788
3789 if (URL == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003790 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003791
3792 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3793 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003794 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3795 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003796 return (NULL);
3797 }
3798 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003799 ret->dict = xmlDictCreate();
3800 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00003801 ret->includes = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003802 return (ret);
3803}
3804
3805/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003806 * xmlSchemaNewMemParserCtxt:
3807 * @buffer: a pointer to a char array containing the schemas
3808 * @size: the size of the array
3809 *
3810 * Create an XML Schemas parse context for that memory buffer expected
3811 * to contain an XML Schemas file.
3812 *
3813 * Returns the parser context or NULL in case of error
3814 */
3815xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003816xmlSchemaNewMemParserCtxt(const char *buffer, int size)
3817{
Daniel Veillard6045c902002-10-09 21:13:59 +00003818 xmlSchemaParserCtxtPtr ret;
3819
3820 if ((buffer == NULL) || (size <= 0))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003821 return (NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003822
3823 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3824 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003825 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3826 NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003827 return (NULL);
3828 }
3829 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3830 ret->buffer = buffer;
3831 ret->size = size;
William M. Brackcf9eadf2003-12-25 13:24:05 +00003832 ret->dict = xmlDictCreate();
Daniel Veillard6045c902002-10-09 21:13:59 +00003833 return (ret);
3834}
3835
3836/**
Daniel Veillard9d751502003-10-29 13:21:47 +00003837 * xmlSchemaNewDocParserCtxt:
3838 * @doc: a preparsed document tree
3839 *
3840 * Create an XML Schemas parse context for that document.
3841 * NB. The document may be modified during the parsing process.
3842 *
3843 * Returns the parser context or NULL in case of error
3844 */
3845xmlSchemaParserCtxtPtr
3846xmlSchemaNewDocParserCtxt(xmlDocPtr doc)
3847{
3848 xmlSchemaParserCtxtPtr ret;
3849
3850 if (doc == NULL)
3851 return (NULL);
3852
3853 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3854 if (ret == NULL) {
3855 xmlSchemaPErrMemory(NULL, "allocating schema parser context",
3856 NULL);
3857 return (NULL);
3858 }
3859 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3860 ret->doc = doc;
William M. Brackcf9eadf2003-12-25 13:24:05 +00003861 ret->dict = xmlDictCreate();
Daniel Veillarddda22c12004-01-24 08:31:30 +00003862 /* The application has responsibility for the document */
3863 ret->preserve = 1;
Daniel Veillard9d751502003-10-29 13:21:47 +00003864
3865 return (ret);
3866}
3867
3868/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003869 * xmlSchemaFreeParserCtxt:
3870 * @ctxt: the schema parser context
3871 *
3872 * Free the resources associated to the schema parser context
3873 */
3874void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003875xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt)
3876{
Daniel Veillard4255d502002-04-16 15:50:10 +00003877 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003878 return;
Daniel Veillarddda22c12004-01-24 08:31:30 +00003879 if (ctxt->doc != NULL && !ctxt->preserve)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003880 xmlFreeDoc(ctxt->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003881 xmlDictFree(ctxt->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +00003882 xmlFree(ctxt);
3883}
3884
3885/************************************************************************
3886 * *
3887 * Building the content models *
3888 * *
3889 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003890
Daniel Veillard4255d502002-04-16 15:50:10 +00003891/**
3892 * xmlSchemaBuildAContentModel:
3893 * @type: the schema type definition
3894 * @ctxt: the schema parser context
3895 * @name: the element name whose content is being built
3896 *
3897 * Generate the automata sequence needed for that type
3898 */
3899static void
3900xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003901 xmlSchemaParserCtxtPtr ctxt,
3902 const xmlChar * name)
3903{
Daniel Veillard4255d502002-04-16 15:50:10 +00003904 if (type == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003905 xmlGenericError(xmlGenericErrorContext,
3906 "Found unexpected type = NULL in %s content model\n",
3907 name);
3908 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003909 }
3910 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003911 case XML_SCHEMA_TYPE_ANY:
3912 /* TODO : handle the namespace too */
3913 /* TODO : make that a specific transition type */
3914 TODO ctxt->state =
3915 xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL,
3916 BAD_CAST "*", NULL);
3917 break;
3918 case XML_SCHEMA_TYPE_ELEMENT:{
3919 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard32370232002-10-16 14:08:14 +00003920
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003921 /* TODO : handle the namespace too */
3922 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003923
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003924 if (elem->maxOccurs >= UNBOUNDED) {
3925 if (elem->minOccurs > 1) {
3926 xmlAutomataStatePtr tmp;
3927 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003928
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003929 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3930 oldstate,
3931 NULL);
3932 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003933
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003934 counter = xmlAutomataNewCounter(ctxt->am,
3935 elem->minOccurs -
3936 1, UNBOUNDED);
Daniel Veillard32370232002-10-16 14:08:14 +00003937
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003938 if (elem->refDecl != NULL) {
3939 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3940 elem->refDecl,
3941 ctxt,
3942 elem->refDecl->
3943 name);
3944 } else {
3945 ctxt->state =
3946 xmlAutomataNewTransition(ctxt->am,
3947 ctxt->state, NULL,
3948 elem->name, type);
3949 }
3950 tmp = ctxt->state;
3951 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3952 counter);
3953 ctxt->state =
3954 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
3955 counter);
Daniel Veillard32370232002-10-16 14:08:14 +00003956
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003957 } else {
3958 if (elem->refDecl != NULL) {
3959 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3960 elem->refDecl,
3961 ctxt,
3962 elem->refDecl->
3963 name);
3964 } else {
3965 ctxt->state =
3966 xmlAutomataNewTransition(ctxt->am,
3967 ctxt->state, NULL,
3968 elem->name, type);
3969 }
3970 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3971 oldstate);
3972 if (elem->minOccurs == 0) {
3973 /* basically an elem* */
3974 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3975 ctxt->state);
3976 }
3977 }
3978 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3979 xmlAutomataStatePtr tmp;
3980 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003981
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003982 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3983 oldstate, NULL);
3984 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003985
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003986 counter = xmlAutomataNewCounter(ctxt->am,
3987 elem->minOccurs - 1,
3988 elem->maxOccurs - 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003989
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003990 if (elem->refDecl != NULL) {
3991 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3992 elem->refDecl, ctxt,
3993 elem->refDecl->name);
3994 } else {
3995 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3996 ctxt->state,
3997 NULL,
3998 elem->name,
3999 type);
4000 }
4001 tmp = ctxt->state;
4002 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
4003 counter);
4004 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
4005 NULL,
4006 counter);
4007 if (elem->minOccurs == 0) {
4008 /* basically an elem? */
4009 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4010 ctxt->state);
4011 }
Daniel Veillardb39bc392002-10-26 19:29:51 +00004012
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004013 } else {
4014 if (elem->refDecl != NULL) {
4015 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
4016 elem->refDecl, ctxt,
4017 elem->refDecl->name);
4018 } else {
4019 ctxt->state = xmlAutomataNewTransition(ctxt->am,
4020 ctxt->state,
4021 NULL,
4022 elem->name,
4023 type);
4024 }
4025 if (elem->minOccurs == 0) {
4026 /* basically an elem? */
4027 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4028 ctxt->state);
4029 }
4030 }
4031 break;
4032 }
4033 case XML_SCHEMA_TYPE_SEQUENCE:{
4034 xmlSchemaTypePtr subtypes;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004035
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004036 /*
4037 * If max and min occurances are default (1) then
4038 * simply iterate over the subtypes
4039 */
4040 if ((type->minOccurs == 1) && (type->maxOccurs == 1)) {
4041 subtypes = type->subtypes;
4042 while (subtypes != NULL) {
4043 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4044 subtypes = subtypes->next;
4045 }
4046 } else {
4047 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004048
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004049 if (type->maxOccurs >= UNBOUNDED) {
4050 if (type->minOccurs > 1) {
4051 xmlAutomataStatePtr tmp;
4052 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004053
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004054 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4055 oldstate,
4056 NULL);
4057 oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004058
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004059 counter = xmlAutomataNewCounter(ctxt->am,
4060 type->
4061 minOccurs - 1,
4062 UNBOUNDED);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004063
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004064 subtypes = type->subtypes;
4065 while (subtypes != NULL) {
4066 xmlSchemaBuildAContentModel(subtypes, ctxt,
4067 name);
4068 subtypes = subtypes->next;
4069 }
4070 tmp = ctxt->state;
4071 xmlAutomataNewCountedTrans(ctxt->am, tmp,
4072 oldstate, counter);
4073 ctxt->state =
4074 xmlAutomataNewCounterTrans(ctxt->am, tmp,
4075 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004076
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004077 } else {
4078 subtypes = type->subtypes;
4079 while (subtypes != NULL) {
4080 xmlSchemaBuildAContentModel(subtypes, ctxt,
4081 name);
4082 subtypes = subtypes->next;
4083 }
4084 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
4085 oldstate);
4086 if (type->minOccurs == 0) {
4087 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4088 ctxt->state);
4089 }
4090 }
4091 } else if ((type->maxOccurs > 1)
4092 || (type->minOccurs > 1)) {
4093 xmlAutomataStatePtr tmp;
4094 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004095
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004096 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4097 oldstate,
4098 NULL);
4099 oldstate = ctxt->state;
Daniel Veillard4255d502002-04-16 15:50:10 +00004100
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004101 counter = xmlAutomataNewCounter(ctxt->am,
4102 type->minOccurs -
4103 1,
4104 type->maxOccurs -
4105 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004106
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004107 subtypes = type->subtypes;
4108 while (subtypes != NULL) {
4109 xmlSchemaBuildAContentModel(subtypes, ctxt,
4110 name);
4111 subtypes = subtypes->next;
4112 }
4113 tmp = ctxt->state;
4114 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
4115 counter);
4116 ctxt->state =
4117 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
4118 counter);
4119 if (type->minOccurs == 0) {
4120 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4121 ctxt->state);
4122 }
Daniel Veillardb509f152002-04-17 16:28:10 +00004123
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004124 } else {
4125 subtypes = type->subtypes;
4126 while (subtypes != NULL) {
4127 xmlSchemaBuildAContentModel(subtypes, ctxt,
4128 name);
4129 subtypes = subtypes->next;
4130 }
4131 if (type->minOccurs == 0) {
4132 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4133 ctxt->state);
4134 }
4135 }
4136 }
4137 break;
4138 }
4139 case XML_SCHEMA_TYPE_CHOICE:{
4140 xmlSchemaTypePtr subtypes;
4141 xmlAutomataStatePtr start, end;
Daniel Veillardb509f152002-04-17 16:28:10 +00004142
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004143 start = ctxt->state;
4144 end = xmlAutomataNewState(ctxt->am);
Daniel Veillard7646b182002-04-20 06:41:40 +00004145
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004146 /*
4147 * iterate over the subtypes and remerge the end with an
4148 * epsilon transition
4149 */
4150 if (type->maxOccurs == 1) {
4151 subtypes = type->subtypes;
4152 while (subtypes != NULL) {
4153 ctxt->state = start;
4154 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4155 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
4156 subtypes = subtypes->next;
4157 }
4158 } else {
4159 int counter;
4160 xmlAutomataStatePtr hop;
4161 int maxOccurs = type->maxOccurs == UNBOUNDED ?
4162 UNBOUNDED : type->maxOccurs - 1;
4163 int minOccurs =
4164 type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillard7646b182002-04-20 06:41:40 +00004165
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004166 /*
4167 * use a counter to keep track of the number of transtions
4168 * which went through the choice.
4169 */
4170 counter =
4171 xmlAutomataNewCounter(ctxt->am, minOccurs,
4172 maxOccurs);
4173 hop = xmlAutomataNewState(ctxt->am);
Daniel Veillard6231e842002-04-18 11:54:04 +00004174
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004175 subtypes = type->subtypes;
4176 while (subtypes != NULL) {
4177 ctxt->state = start;
4178 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4179 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
4180 subtypes = subtypes->next;
4181 }
4182 xmlAutomataNewCountedTrans(ctxt->am, hop, start,
4183 counter);
4184 xmlAutomataNewCounterTrans(ctxt->am, hop, end,
4185 counter);
4186 }
4187 if (type->minOccurs == 0) {
4188 xmlAutomataNewEpsilon(ctxt->am, start, end);
4189 }
4190 ctxt->state = end;
4191 break;
4192 }
4193 case XML_SCHEMA_TYPE_ALL:{
4194 xmlAutomataStatePtr start;
4195 xmlSchemaTypePtr subtypes;
4196 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
4197 int lax;
4198
4199 subtypes = type->subtypes;
4200 if (subtypes == NULL)
4201 break;
4202 start = ctxt->state;
4203 while (subtypes != NULL) {
4204 ctxt->state = start;
4205 elem = (xmlSchemaElementPtr) subtypes;
4206
4207 /* TODO : handle the namespace too */
4208 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
4209 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state,
4210 ctxt->state, elem->name, 1,
4211 1, subtypes);
4212 } else {
4213 xmlAutomataNewCountTrans(ctxt->am, ctxt->state,
4214 ctxt->state, elem->name,
4215 elem->minOccurs,
4216 elem->maxOccurs,
4217 subtypes);
4218 }
4219 subtypes = subtypes->next;
4220 }
4221 lax = type->minOccurs == 0;
4222 ctxt->state =
4223 xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
4224 lax);
4225 break;
4226 }
4227 case XML_SCHEMA_TYPE_RESTRICTION:
4228 if (type->subtypes != NULL)
4229 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4230 break;
4231 case XML_SCHEMA_TYPE_EXTENSION:
4232 if (type->baseType != NULL) {
4233 xmlSchemaTypePtr subtypes;
4234
4235 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
4236 subtypes = type->subtypes;
4237 while (subtypes != NULL) {
4238 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4239 subtypes = subtypes->next;
4240 }
4241 } else if (type->subtypes != NULL)
4242 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4243 break;
4244 case XML_SCHEMA_TYPE_GROUP:
4245 if (type->subtypes == NULL) {
4246 }
4247 case XML_SCHEMA_TYPE_COMPLEX:
4248 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4249 if (type->subtypes != NULL)
4250 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4251 break;
4252 default:
4253 xmlGenericError(xmlGenericErrorContext,
4254 "Found unexpected type %d in %s content model\n",
4255 type->type, name);
4256 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004257 }
4258}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004259
Daniel Veillard4255d502002-04-16 15:50:10 +00004260/**
4261 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004262 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00004263 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004264 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00004265 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004266 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00004267 */
4268static void
4269xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004270 xmlSchemaParserCtxtPtr ctxt,
4271 const xmlChar * name)
4272{
Daniel Veillard4255d502002-04-16 15:50:10 +00004273 xmlAutomataStatePtr start;
4274
Daniel Veillard4255d502002-04-16 15:50:10 +00004275 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004276 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004277 if (elem->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004278 elem->contentType = XML_SCHEMA_CONTENT_ANY;
4279 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004280 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004281 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004282 return;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004283 if ((elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC) ||
4284 (elem->subtypes->contentType == XML_SCHEMA_CONTENT_SIMPLE))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004285 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004286
4287#ifdef DEBUG_CONTENT
4288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004289 "Building content model for %s\n", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004290#endif
4291
Daniel Veillard4255d502002-04-16 15:50:10 +00004292 ctxt->am = xmlNewAutomata();
4293 if (ctxt->am == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004294 xmlGenericError(xmlGenericErrorContext,
4295 "Cannot create automata for elem %s\n", name);
4296 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004297 }
4298 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
4299 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
4300 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00004301 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004302 if (elem->contModel == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004303 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_INTERNAL,
4304 "failed to compile %s content model\n", name, NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004305 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004306 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_NOTDETERMINIST,
4307 "Content model of %s is not determinist:\n", name,
4308 NULL);
Daniel Veillarde19fc232002-04-22 16:01:24 +00004309 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00004310#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004311 xmlGenericError(xmlGenericErrorContext,
4312 "Content model of %s:\n", name);
4313 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00004314#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00004315 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004316 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00004317 xmlFreeAutomata(ctxt->am);
4318 ctxt->am = NULL;
4319}
4320
4321/**
4322 * xmlSchemaRefFixupCallback:
4323 * @elem: the schema element context
4324 * @ctxt: the schema parser context
4325 *
4326 * Free the resources associated to the schema parser context
4327 */
4328static void
4329xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004330 xmlSchemaParserCtxtPtr ctxt,
4331 const xmlChar * name,
4332 const xmlChar * context ATTRIBUTE_UNUSED,
4333 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00004334{
4335 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004336 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004337 if (elem->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004338 xmlSchemaElementPtr elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004339
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004340 if (elem->subtypes != NULL) {
4341 xmlSchemaPErr(ctxt, elem->node,
4342 XML_SCHEMAP_INVALID_REF_AND_SUBTYPE,
4343 "Schemas: element %s have both ref and subtype\n",
4344 name, NULL);
4345 return;
4346 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004347 elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00004348
4349 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004350 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF,
4351 "Schemas: element %s ref to %s not found\n",
4352 name, elem->ref);
4353 return;
4354 }
4355 elem->refDecl = elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004356 } else if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004357 xmlSchemaTypePtr typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004358
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004359 if (elem->subtypes != NULL) {
4360 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE,
4361 "Schemas: element %s have both type and subtype\n",
4362 name, NULL);
4363 return;
4364 }
4365 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
4366 elem->namedTypeNs);
Daniel Veillard4255d502002-04-16 15:50:10 +00004367
4368 if (typeDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004369 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE,
4370 "Schemas: element %s type %s not found\n", name,
4371 elem->namedType);
4372 return;
4373 }
4374 elem->subtypes = typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004375 }
4376}
4377
Daniel Veillard377e1a92004-04-16 16:30:05 +00004378static void
4379xmlSchemaParseUnionRefCheck(xmlSchemaTypePtr typeDecl,
4380 xmlSchemaParserCtxtPtr ctxt)
4381{
4382 const xmlChar *cur, *end, *prefix, *ncName, *namespace;
4383 xmlChar *tmp;
4384 xmlSchemaTypePtr subtype;
4385 xmlNsPtr ns;
4386 int len;
4387
4388 if ((typeDecl->type != XML_SCHEMA_TYPE_UNION) || (typeDecl->ref == NULL))
4389 return;
4390
4391 cur = typeDecl->ref;
4392 do {
4393 while (IS_BLANK_CH(*cur))
4394 cur++;
4395 end = cur;
4396 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
4397 end++;
4398 if (end == cur)
4399 break;
4400 tmp = xmlStrndup(cur, end - cur);
4401 ncName = xmlSplitQName3(tmp, &len);
4402 if (ncName != NULL) {
4403 prefix = xmlDictLookup(ctxt->dict, tmp, len);
4404 } else {
4405 prefix = NULL;
4406 ncName = tmp;
4407 }
4408 ns = xmlSearchNs(typeDecl->node->doc, typeDecl->node, prefix);
4409 if (ns == NULL) {
4410 xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_PREFIX_UNDEFINED,
4411 "Union %s: the namespace of member type %s is undefined\n",
4412 typeDecl->name, (const char *) tmp);
4413 } else {
4414 namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
4415 }
4416 /* Lookup the referenced type */
4417 subtype = xmlSchemaGetType(ctxt->schema, ncName, namespace);
4418 if (subtype == NULL) {
4419 xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE,
4420 "Union %s references an unknown member type >%s<\n",
4421 typeDecl->name, (const char *) tmp);
4422 }
4423 xmlFree(tmp);
4424 cur = end;
4425 } while (*cur != 0);
4426
4427}
4428
Daniel Veillard4255d502002-04-16 15:50:10 +00004429/**
4430 * xmlSchemaTypeFixup:
4431 * @typeDecl: the schema type definition
4432 * @ctxt: the schema parser context
4433 *
4434 * Fixes the content model of the type.
4435 */
4436static void
4437xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004438 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004439{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004440 if (typeDecl == NULL)
4441 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004442 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004443 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004444 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004445 switch (typeDecl->type) {
4446 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{
4447 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
4448 if (typeDecl->subtypes != NULL)
4449 typeDecl->contentType =
4450 typeDecl->subtypes->contentType;
4451 break;
4452 }
4453 case XML_SCHEMA_TYPE_RESTRICTION:{
4454 if (typeDecl->subtypes != NULL)
4455 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004456
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004457 if (typeDecl->base != NULL) {
4458 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004459
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004460 baseType =
4461 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4462 typeDecl->baseNs);
4463 if (baseType == NULL) {
4464 xmlSchemaPErr(ctxt, typeDecl->node,
4465 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004466 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004467 name, typeDecl->base);
4468 }
4469 typeDecl->baseType = baseType;
4470 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004471 if (typeDecl->subtypes == NULL)
4472 if (typeDecl->baseType != NULL)
4473 typeDecl->contentType =
4474 typeDecl->baseType->contentType;
4475 else
4476 /* 1.1.1 */
4477 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004478 else if ((typeDecl->subtypes->subtypes == NULL) &&
4479 ((typeDecl->subtypes->type ==
4480 XML_SCHEMA_TYPE_ALL)
4481 || (typeDecl->subtypes->type ==
4482 XML_SCHEMA_TYPE_SEQUENCE)))
4483 /* 1.1.2 */
4484 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4485 else if ((typeDecl->subtypes->type ==
4486 XML_SCHEMA_TYPE_CHOICE)
4487 && (typeDecl->subtypes->subtypes == NULL))
4488 /* 1.1.3 */
4489 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4490 else {
4491 /* 1.2 and 2.X are applied at the other layer */
4492 typeDecl->contentType =
4493 XML_SCHEMA_CONTENT_ELEMENTS;
4494 }
4495 break;
4496 }
4497 case XML_SCHEMA_TYPE_EXTENSION:{
4498 xmlSchemaContentType explicitContentType;
4499 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00004500
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004501 if (typeDecl->base != NULL) {
4502 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004503
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004504 baseType =
4505 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4506 typeDecl->baseNs);
4507 if (baseType == NULL) {
4508 xmlSchemaPErr(ctxt, typeDecl->node,
4509 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004510 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004511 name, typeDecl->base);
4512 }
4513 typeDecl->baseType = baseType;
4514 }
4515 if (typeDecl->subtypes != NULL)
4516 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004517
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004518 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
4519 if (typeDecl->subtypes == NULL)
4520 /* 1.1.1 */
4521 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4522 else if ((typeDecl->subtypes->subtypes == NULL) &&
4523 ((typeDecl->subtypes->type ==
4524 XML_SCHEMA_TYPE_ALL)
4525 || (typeDecl->subtypes->type ==
4526 XML_SCHEMA_TYPE_SEQUENCE)))
4527 /* 1.1.2 */
4528 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4529 else if ((typeDecl->subtypes->type ==
4530 XML_SCHEMA_TYPE_CHOICE)
4531 && (typeDecl->subtypes->subtypes == NULL))
4532 /* 1.1.3 */
4533 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard4255d502002-04-16 15:50:10 +00004534
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004535 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
4536 typeDecl->baseNs);
4537 if (base == NULL) {
4538 xmlSchemaPErr(ctxt, typeDecl->node,
4539 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
4540 "Schemas: base type %s of type %s not found\n",
4541 typeDecl->base, name);
4542 return;
4543 }
4544 xmlSchemaTypeFixup(base, ctxt, NULL);
4545 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
4546 /* 2.1 */
4547 typeDecl->contentType = base->contentType;
4548 } else if (base->contentType ==
4549 XML_SCHEMA_CONTENT_EMPTY) {
4550 /* 2.2 imbitable ! */
4551 typeDecl->contentType =
4552 XML_SCHEMA_CONTENT_ELEMENTS;
4553 } else {
4554 /* 2.3 imbitable pareil ! */
4555 typeDecl->contentType =
4556 XML_SCHEMA_CONTENT_ELEMENTS;
4557 }
4558 break;
4559 }
4560 case XML_SCHEMA_TYPE_COMPLEX:{
4561 if (typeDecl->subtypes == NULL) {
4562 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard1aefc862004-03-04 11:40:48 +00004563
4564 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4565 typeDecl->contentType =
4566 XML_SCHEMA_CONTENT_MIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004567 } else {
4568 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4569 typeDecl->contentType =
4570 XML_SCHEMA_CONTENT_MIXED;
4571 else {
4572 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4573 NULL);
4574 if (typeDecl->subtypes != NULL)
4575 typeDecl->contentType =
4576 typeDecl->subtypes->contentType;
4577 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004578 if (typeDecl->attributes == NULL)
4579 typeDecl->attributes =
4580 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004581 }
4582 break;
4583 }
4584 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{
4585 if (typeDecl->subtypes == NULL) {
4586 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard1aefc862004-03-04 11:40:48 +00004587 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4588 typeDecl->contentType =
4589 XML_SCHEMA_CONTENT_MIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004590 } else {
4591 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4592 typeDecl->contentType =
4593 XML_SCHEMA_CONTENT_MIXED;
4594 else {
4595 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4596 NULL);
4597 if (typeDecl->subtypes != NULL)
4598 typeDecl->contentType =
4599 typeDecl->subtypes->contentType;
4600 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004601 if (typeDecl->attributes == NULL)
4602 typeDecl->attributes =
4603 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004604 }
4605 break;
4606 }
4607 case XML_SCHEMA_TYPE_SEQUENCE:
4608 case XML_SCHEMA_TYPE_GROUP:
4609 case XML_SCHEMA_TYPE_ALL:
4610 case XML_SCHEMA_TYPE_CHOICE:
4611 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
4612 break;
4613 case XML_SCHEMA_TYPE_BASIC:
4614 case XML_SCHEMA_TYPE_ANY:
4615 case XML_SCHEMA_TYPE_FACET:
4616 case XML_SCHEMA_TYPE_SIMPLE:
4617 case XML_SCHEMA_TYPE_UR:
4618 case XML_SCHEMA_TYPE_ELEMENT:
4619 case XML_SCHEMA_TYPE_ATTRIBUTE:
4620 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4621 case XML_SCHEMA_TYPE_NOTATION:
4622 case XML_SCHEMA_TYPE_LIST:
4623 case XML_SCHEMA_TYPE_UNION:
Daniel Veillard377e1a92004-04-16 16:30:05 +00004624 xmlSchemaParseUnionRefCheck(typeDecl, ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004625 case XML_SCHEMA_FACET_MININCLUSIVE:
4626 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4627 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4628 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4629 case XML_SCHEMA_FACET_TOTALDIGITS:
4630 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4631 case XML_SCHEMA_FACET_PATTERN:
4632 case XML_SCHEMA_FACET_ENUMERATION:
4633 case XML_SCHEMA_FACET_WHITESPACE:
4634 case XML_SCHEMA_FACET_LENGTH:
4635 case XML_SCHEMA_FACET_MAXLENGTH:
4636 case XML_SCHEMA_FACET_MINLENGTH:
4637 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004638 if (typeDecl->subtypes != NULL)
4639 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004640 break;
4641 }
4642 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004643#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004644 if (typeDecl->node != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004645 xmlGenericError(xmlGenericErrorContext,
4646 "Type of %s : %s:%d :", name,
4647 typeDecl->node->doc->URL,
4648 xmlGetLineNo(typeDecl->node));
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004649 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004650 xmlGenericError(xmlGenericErrorContext, "Type of %s :", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004651 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004652 switch (typeDecl->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004653 case XML_SCHEMA_CONTENT_SIMPLE:
4654 xmlGenericError(xmlGenericErrorContext, "simple\n");
4655 break;
4656 case XML_SCHEMA_CONTENT_ELEMENTS:
4657 xmlGenericError(xmlGenericErrorContext, "elements\n");
4658 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004659 case XML_SCHEMA_CONTENT_UNKNOWN:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004660 xmlGenericError(xmlGenericErrorContext, "unknown !!!\n");
4661 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004662 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004663 xmlGenericError(xmlGenericErrorContext, "empty\n");
4664 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004665 case XML_SCHEMA_CONTENT_MIXED:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004666 xmlGenericError(xmlGenericErrorContext, "mixed\n");
4667 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004668 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004669 xmlGenericError(xmlGenericErrorContext, "mixed or elems\n");
4670 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004671 case XML_SCHEMA_CONTENT_BASIC:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004672 xmlGenericError(xmlGenericErrorContext, "basic\n");
4673 break;
4674 default:
4675 xmlGenericError(xmlGenericErrorContext,
4676 "not registered !!!\n");
4677 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004678 }
4679#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00004680}
4681
4682/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004683 * xmlSchemaCheckFacet:
4684 * @facet: the facet
4685 * @typeDecl: the schema type definition
4686 * @ctxt: the schema parser context or NULL
4687 * @name: name of the type
4688 *
4689 * Checks the default values types, especially for facets
4690 *
4691 * Returns 0 if okay or -1 in cae of error
4692 */
4693int
4694xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004695 xmlSchemaTypePtr typeDecl,
4696 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004697{
4698 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
4699 int ret = 0;
4700
4701 if (nonNegativeIntegerType == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004702 nonNegativeIntegerType =
4703 xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger",
4704 xmlSchemaNs);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004705 }
4706 switch (facet->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004707 case XML_SCHEMA_FACET_MININCLUSIVE:
4708 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4709 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4710 case XML_SCHEMA_FACET_MAXEXCLUSIVE:{
4711 /*
4712 * Okay we need to validate the value
4713 * at that point.
4714 */
4715 xmlSchemaValidCtxtPtr vctxt;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004716
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004717 vctxt = xmlSchemaNewValidCtxt(NULL);
4718 if (vctxt == NULL)
4719 break;
4720 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4721 facet->value);
4722 facet->val = vctxt->value;
4723 vctxt->value = NULL;
4724 if (facet->val == NULL) {
4725 /* error code */
4726 if (ctxt != NULL) {
4727 xmlSchemaPErr(ctxt, facet->node,
4728 XML_SCHEMAP_INVALID_FACET,
4729 "Schemas: type %s facet value %s invalid\n",
4730 name, facet->value);
4731 }
4732 ret = -1;
4733 }
4734 xmlSchemaFreeValidCtxt(vctxt);
4735 break;
4736 }
4737 case XML_SCHEMA_FACET_ENUMERATION:{
4738 /*
4739 * Okay we need to validate the value
4740 * at that point.
4741 */
4742 xmlSchemaValidCtxtPtr vctxt;
4743 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004744
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004745 vctxt = xmlSchemaNewValidCtxt(NULL);
4746 if (vctxt == NULL)
4747 break;
4748 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4749 facet->value);
4750 if (tmp != 0) {
4751 if (ctxt != NULL) {
4752 xmlSchemaPErr(ctxt, facet->node,
4753 XML_SCHEMAP_INVALID_ENUM,
4754 "Schemas: type %s enumeration value %s invalid\n",
4755 name, facet->value);
4756 }
4757 ret = -1;
4758 }
4759 xmlSchemaFreeValidCtxt(vctxt);
4760 break;
4761 }
4762 case XML_SCHEMA_FACET_PATTERN:
4763 facet->regexp = xmlRegexpCompile(facet->value);
4764 if (facet->regexp == NULL) {
4765 xmlSchemaPErr(ctxt, typeDecl->node,
4766 XML_SCHEMAP_REGEXP_INVALID,
4767 "Schemas: type %s facet regexp %s invalid\n",
4768 name, facet->value);
4769 ret = -1;
4770 }
4771 break;
4772 case XML_SCHEMA_FACET_TOTALDIGITS:
4773 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4774 case XML_SCHEMA_FACET_LENGTH:
4775 case XML_SCHEMA_FACET_MAXLENGTH:
4776 case XML_SCHEMA_FACET_MINLENGTH:{
4777 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004778
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004779 tmp =
4780 xmlSchemaValidatePredefinedType(nonNegativeIntegerType,
4781 facet->value,
4782 &facet->val);
4783 if (tmp != 0) {
4784 /* error code */
4785 if (ctxt != NULL) {
4786 xmlSchemaPErr(ctxt, facet->node,
4787 XML_SCHEMAP_INVALID_FACET_VALUE,
4788 "Schemas: type %s facet value %s invalid\n",
4789 name, facet->value);
4790 }
4791 ret = -1;
4792 }
4793 break;
4794 }
4795 case XML_SCHEMA_FACET_WHITESPACE:{
4796 if (xmlStrEqual(facet->value, BAD_CAST "preserve")) {
4797 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4798 } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) {
4799 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4800 } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) {
4801 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4802 } else {
4803 if (ctxt != NULL) {
4804 xmlSchemaPErr(ctxt, facet->node,
4805 XML_SCHEMAP_INVALID_WHITE_SPACE,
4806 "Schemas: type %s whiteSpace value %s invalid\n",
4807 name, facet->value);
4808 }
4809 ret = -1;
4810 }
4811 }
4812 default:
4813 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004814 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004815 return (ret);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004816}
4817
4818/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004819 * xmlSchemaCheckDefaults:
4820 * @typeDecl: the schema type definition
4821 * @ctxt: the schema parser context
4822 *
4823 * Checks the default values types, especially for facets
4824 */
4825static void
4826xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004827 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004828{
Daniel Veillard4255d502002-04-16 15:50:10 +00004829 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004830 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004831 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004832 if (typeDecl->facets != NULL) {
4833 xmlSchemaFacetPtr facet = typeDecl->facets;
4834
4835 while (facet != NULL) {
4836 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
4837 facet = facet->next;
4838 }
4839 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004840 }
4841}
4842
4843/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004844 * xmlSchemaAttrGrpFixup:
4845 * @attrgrpDecl: the schema attribute definition
4846 * @ctxt: the schema parser context
4847 * @name: the attribute name
4848 *
4849 * Fixes finish doing the computations on the attributes definitions
4850 */
4851static void
4852xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004853 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard13e04c62002-04-23 17:51:29 +00004854{
4855 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004856 name = attrgrpDecl->name;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004857 if (attrgrpDecl->attributes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004858 return;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004859 if (attrgrpDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004860 xmlSchemaAttributeGroupPtr ref;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004861
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004862 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4863 attrgrpDecl->refNs);
4864 if (ref == NULL) {
4865 xmlSchemaPErr(ctxt, attrgrpDecl->node,
4866 XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP,
4867 "Schemas: attribute group %s reference %s not found\n",
4868 name, attrgrpDecl->ref);
4869 return;
4870 }
4871 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4872 attrgrpDecl->attributes = ref->attributes;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004873 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004874 xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF,
4875 "Schemas: attribute %s has no attributes nor reference\n",
4876 name, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004877 }
4878}
4879
4880/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004881 * xmlSchemaAttrFixup:
4882 * @attrDecl: the schema attribute definition
4883 * @ctxt: the schema parser context
4884 * @name: the attribute name
4885 *
4886 * Fixes finish doing the computations on the attributes definitions
4887 */
4888static void
4889xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004890 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004891{
4892 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004893 name = attrDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004894 if (attrDecl->subtypes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004895 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004896 if (attrDecl->typeName != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004897 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004898
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004899 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4900 attrDecl->typeNs);
4901 if (type == NULL) {
4902 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE,
4903 "Schemas: attribute %s type %s not found\n",
4904 name, attrDecl->typeName);
4905 }
4906 attrDecl->subtypes = type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004907 } else if (attrDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004908 xmlSchemaAttributePtr ref;
Daniel Veillard4255d502002-04-16 15:50:10 +00004909
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004910 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4911 attrDecl->refNs);
4912 if (ref == NULL) {
4913 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF,
4914 "Schemas: attribute %s reference %s not found\n",
4915 name, attrDecl->ref);
4916 return;
4917 }
4918 xmlSchemaAttrFixup(ref, ctxt, NULL);
4919 attrDecl->subtypes = ref->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +00004920 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004921 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF,
4922 "Schemas: attribute %s has no type nor reference\n",
4923 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004924 }
4925}
4926
4927/**
4928 * xmlSchemaParse:
4929 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004930 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004931 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004932 * XML Shema struture which can be used to validate instances.
4933 * *WARNING* this interface is highly subject to change
4934 *
4935 * Returns the internal XML Schema structure built from the resource or
4936 * NULL in case of error
4937 */
4938xmlSchemaPtr
4939xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4940{
4941 xmlSchemaPtr ret = NULL;
4942 xmlDocPtr doc;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004943 xmlNodePtr root;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004944 int nberrors;
Daniel Veillarddda22c12004-01-24 08:31:30 +00004945 int preserve = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004946
4947 xmlSchemaInitTypes();
4948
Daniel Veillard6045c902002-10-09 21:13:59 +00004949 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004950 return (NULL);
4951
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004952 nberrors = ctxt->nberrors;
4953 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004954 ctxt->counter = 0;
4955 ctxt->container = NULL;
4956
4957 /*
4958 * First step is to parse the input document into an DOM/Infoset
4959 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004960 if (ctxt->URL != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004961 doc = xmlReadFile((const char *) ctxt->URL, NULL,
4962 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004963 if (doc == NULL) {
4964 xmlSchemaPErr(ctxt, NULL,
4965 XML_SCHEMAP_FAILED_LOAD,
4966 "xmlSchemaParse: could not load %s\n",
4967 ctxt->URL, NULL);
4968 return (NULL);
4969 }
Daniel Veillard6045c902002-10-09 21:13:59 +00004970 } else if (ctxt->buffer != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004971 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
4972 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004973 if (doc == NULL) {
4974 xmlSchemaPErr(ctxt, NULL,
4975 XML_SCHEMAP_FAILED_PARSE,
4976 "xmlSchemaParse: could not parse\n",
4977 NULL, NULL);
4978 return (NULL);
4979 }
4980 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard65765282004-01-08 16:59:30 +00004981 ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
Daniel Veillard9d751502003-10-29 13:21:47 +00004982 } else if (ctxt->doc != NULL) {
4983 doc = ctxt->doc;
Daniel Veillarddda22c12004-01-24 08:31:30 +00004984 preserve = 1;
Daniel Veillard6045c902002-10-09 21:13:59 +00004985 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004986 xmlSchemaPErr(ctxt, NULL,
4987 XML_SCHEMAP_NOTHING_TO_PARSE,
4988 "xmlSchemaParse: could not parse\n",
4989 NULL, NULL);
4990 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004991 }
4992
4993 /*
4994 * Then extract the root and Schema parse it
4995 */
4996 root = xmlDocGetRootElement(doc);
4997 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004998 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
4999 XML_SCHEMAP_NOROOT,
5000 "schemas has no root", NULL, NULL);
Daniel Veillarddda22c12004-01-24 08:31:30 +00005001 if (!preserve) {
5002 xmlFreeDoc(doc);
5003 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005004 return (NULL);
5005 }
5006
5007 /*
5008 * Remove all the blank text nodes
5009 */
Daniel Veillardbd2904b2003-11-25 15:38:59 +00005010 xmlSchemaCleanupDoc(ctxt, root);
Daniel Veillard4255d502002-04-16 15:50:10 +00005011
5012 /*
5013 * Then do the parsing for good
5014 */
5015 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillard1d913862003-11-21 00:28:39 +00005016 if (ret == NULL) {
Daniel Veillarddda22c12004-01-24 08:31:30 +00005017 if (!preserve) {
5018 xmlFreeDoc(doc);
5019 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005020 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00005021 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005022 ret->doc = doc;
Daniel Veillarddda22c12004-01-24 08:31:30 +00005023 ret->preserve = preserve;
Daniel Veillard4255d502002-04-16 15:50:10 +00005024
5025 /*
5026 * Then fix all the references.
5027 */
5028 ctxt->schema = ret;
5029 xmlHashScanFull(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005030 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005031
5032 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005033 * Then fixup all attributes declarations
5034 */
5035 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
5036
5037 /*
5038 * Then fixup all attributes group declarations
5039 */
5040 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup,
5041 ctxt);
5042
5043 /*
Daniel Veillard4255d502002-04-16 15:50:10 +00005044 * Then fixup all types properties
5045 */
5046 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
5047
5048 /*
5049 * Then build the content model for all elements
5050 */
5051 xmlHashScan(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005052 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005053
5054 /*
5055 * Then check the defaults part of the type like facets values
5056 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005057 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults,
5058 ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005059
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005060 if (ctxt->nberrors != 0) {
5061 xmlSchemaFree(ret);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005062 ret = NULL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005063 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005064 return (ret);
5065}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005066
Daniel Veillard4255d502002-04-16 15:50:10 +00005067/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005068 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00005069 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00005070 * @err: the error callback
5071 * @warn: the warning callback
5072 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00005073 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00005074 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00005075 */
5076void
5077xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005078 xmlSchemaValidityErrorFunc err,
5079 xmlSchemaValidityWarningFunc warn, void *ctx)
5080{
Daniel Veillard4255d502002-04-16 15:50:10 +00005081 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005082 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00005083 ctxt->error = err;
5084 ctxt->warning = warn;
5085 ctxt->userData = ctx;
5086}
5087
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005088/**
5089 * xmlSchemaFacetTypeToString:
5090 * @type: the facet type
5091 *
5092 * Convert the xmlSchemaTypeType to a char string.
5093 *
5094 * Returns the char string representation of the facet type if the
5095 * type is a facet and an "Internal Error" string otherwise.
5096 */
5097static const char *
5098xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
5099{
5100 switch (type) {
5101 case XML_SCHEMA_FACET_PATTERN:
5102 return ("pattern");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005103 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005104 return ("maxExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005105 case XML_SCHEMA_FACET_MAXINCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005106 return ("maxInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005107 case XML_SCHEMA_FACET_MINEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005108 return ("minExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005109 case XML_SCHEMA_FACET_MININCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005110 return ("minInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005111 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005112 return ("whiteSpace");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005113 case XML_SCHEMA_FACET_ENUMERATION:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005114 return ("enumeration");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005115 case XML_SCHEMA_FACET_LENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005116 return ("length");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005117 case XML_SCHEMA_FACET_MAXLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005118 return ("maxLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005119 case XML_SCHEMA_FACET_MINLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005120 return ("minLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005121 case XML_SCHEMA_FACET_TOTALDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005122 return ("totalDigits");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005123 case XML_SCHEMA_FACET_FRACTIONDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005124 return ("fractionDigits");
5125 default:
5126 break;
5127 }
5128 return ("Internal Error");
5129}
5130
5131/**
5132 * xmlSchemaValidateFacets:
5133 * @ctxt: a schema validation context
5134 * @base: the base type
5135 * @facets: the list of facets to check
5136 * @value: the lexical repr of the value to validate
5137 * @val: the precomputed value
5138 *
5139 * Check a value against all facet conditions
5140 *
5141 * Returns 0 if the element is schemas valid, a positive error code
5142 * number otherwise and -1 in case of internal or API error.
5143 */
5144static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005145xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
5146 xmlSchemaTypePtr base,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005147 xmlSchemaFacetPtr facets, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005148{
Daniel Veillard377e1a92004-04-16 16:30:05 +00005149 return(xmlSchemaValidateFacetsInternal(ctxt, base, facets, value, 1));
5150}
5151
5152/**
5153 * xmlSchemaValidateFacetsInternal:
5154 * @ctxt: a schema validation context
5155 * @base: the base type
5156 * @facets: the list of facets to check
5157 * @value: the lexical repr of the value to validate
5158 * @val: the precomputed value
5159 * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
5160 *
5161 * Check a value against all facet conditions
5162 *
5163 * Returns 0 if the element is schemas valid, a positive error code
5164 * number otherwise and -1 in case of internal or API error.
5165 */
5166static int
5167xmlSchemaValidateFacetsInternal(xmlSchemaValidCtxtPtr ctxt,
5168 xmlSchemaTypePtr base,
5169 xmlSchemaFacetPtr facets, const xmlChar * value, int fireErrors)
5170{
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005171 int ret = 0;
5172 int tmp = 0;
5173 xmlSchemaTypeType type;
5174 xmlSchemaFacetPtr facet = facets;
5175
5176 while (facet != NULL) {
5177 type = facet->type;
5178 if (type == XML_SCHEMA_FACET_ENUMERATION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005179 tmp = 1;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005180
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005181 while (facet != NULL) {
5182 tmp =
5183 xmlSchemaValidateFacet(base, facet, value,
5184 ctxt->value);
5185 if (tmp == 0) {
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005186 return 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005187 }
5188 facet = facet->next;
5189 }
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005190 } else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005191 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005192
5193 if (tmp != 0) {
5194 ret = tmp;
Daniel Veillard377e1a92004-04-16 16:30:05 +00005195 if (fireErrors)
5196 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 +00005197 }
5198 if (facet != NULL)
5199 facet = facet->next;
5200 }
5201 return (ret);
5202}
5203
Daniel Veillard4255d502002-04-16 15:50:10 +00005204/************************************************************************
5205 * *
5206 * Simple type validation *
5207 * *
5208 ************************************************************************/
5209
5210/**
Daniel Veillard377e1a92004-04-16 16:30:05 +00005211 * xmlSchemaValidateSimpleValueUnion:
5212 * @ctxt: a schema validation context
5213 * @type: the type declaration
5214 * @value: the value to validate
5215 *
5216 * Validates a value against a union.
5217 *
5218 * Returns 0 if the value is valid, a positive error code
5219 * number otherwise and -1 in case of internal or API error.
5220 */
5221static int
5222xmlSchemaValidateSimpleValueUnion(xmlSchemaValidCtxtPtr ctxt,
5223 xmlSchemaTypePtr type, const xmlChar * value)
5224{
5225 int ret = 0;
5226 const xmlChar *cur, *end, *prefix, *ncName;
5227 xmlChar *tmp;
5228 xmlSchemaTypePtr subtype;
5229 xmlNsPtr ns;
5230 int len;
5231
5232
5233 /* Process referenced memberTypes. */
5234 cur = type->ref;
5235 do {
5236 while (IS_BLANK_CH(*cur))
5237 cur++;
5238 end = cur;
5239 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
5240 end++;
5241 if (end == cur)
5242 break;
5243 tmp = xmlStrndup(cur, end - cur);
5244 ncName = xmlSplitQName3(tmp, &len);
5245 if (ncName != NULL) {
5246 prefix = xmlStrndup(tmp, len);
5247 /* prefix = xmlDictLookup(ctxt->doc->dict, tmp, len); */
5248 } else {
5249 prefix = NULL;
5250 ncName = tmp;
5251 }
5252 /* We won't do additional checks here, since they have been performed during parsing. */
5253 ns = xmlSearchNs(type->node->doc, type->node, prefix);
5254 /* namespace = xmlDictLookup(ctxt->doc->dict, ns->href, -1); */
5255 subtype = xmlSchemaGetType(ctxt->schema, ncName, ns->href);
5256 if (tmp != NULL)
5257 xmlFree(tmp);
5258 if (prefix != NULL)
5259 xmlFree(prefix);
5260 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
5261 if ((ret == 0) || (ret == -1)) {
5262 return (ret);
5263 }
5264 cur = end;
5265 } while (*cur != 0);
5266
5267 if (type->subtypes != NULL) {
5268 subtype = type->subtypes;
5269 do {
5270 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
5271 if ((ret == 0) || (ret == -1)) {
5272 return (ret);
5273 }
5274 subtype = subtype->next;
5275 } while (subtype != NULL);
5276 }
5277 return (ret);
5278}
5279
5280/**
Daniel Veillard4255d502002-04-16 15:50:10 +00005281 * xmlSchemaValidateSimpleValue:
5282 * @ctxt: a schema validation context
5283 * @type: the type declaration
5284 * @value: the value to validate
5285 *
5286 * Validate a value against a simple type
5287 *
5288 * Returns 0 if the value is valid, a positive error code
5289 * number otherwise and -1 in case of internal or API error.
5290 */
5291static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005292xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005293 xmlSchemaTypePtr type, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005294{
Daniel Veillard377e1a92004-04-16 16:30:05 +00005295 return (xmlSchemaValidateSimpleValueInternal(ctxt, type, value, 1));
5296}
5297
5298/**
5299 * xmlSchemaValidateSimpleValue:
5300 * @ctxt: a schema validation context
5301 * @type: the type declaration
5302 * @value: the value to validate
5303 * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
5304 *
5305 * Validate a value against a simple type
5306 *
5307 * Returns 0 if the value is valid, a positive error code
5308 * number otherwise and -1 in case of internal or API error.
5309 */
5310static int
5311xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt,
5312 xmlSchemaTypePtr type, const xmlChar * value, int fireErrors)
5313{
Daniel Veillard4255d502002-04-16 15:50:10 +00005314 int ret = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005315
Daniel Veillard4255d502002-04-16 15:50:10 +00005316 /*
5317 * First normalize the value accordingly to Schema Datatype
5318 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
5319 */
5320 /*
5321 * Then check the normalized value against the lexical space of the
5322 * type.
5323 */
5324 if (type->type == XML_SCHEMA_TYPE_BASIC) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005325 if (ctxt->value != NULL) {
5326 xmlSchemaFreeValue(ctxt->value);
5327 ctxt->value = NULL;
5328 }
5329 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
5330 ctxt->cur);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005331 if ((fireErrors) && (ret != 0)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005332 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 +00005333 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005334 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005335 xmlSchemaTypePtr base;
5336 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005337
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005338 base = type->baseType;
5339 if (base != NULL) {
Daniel Veillard377e1a92004-04-16 16:30:05 +00005340 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005341 } else if (type->subtypes != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005342 TODO
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005343 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005344
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005345 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005346 * Do not validate facets or attributes when working on
5347 * building the Schemas
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005348 */
5349 if (ctxt->schema != NULL) {
5350 if (ret == 0) {
5351 facet = type->facets;
Daniel Veillard377e1a92004-04-16 16:30:05 +00005352 ret = xmlSchemaValidateFacetsInternal(ctxt, base, facet, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005353 }
5354 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005355 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005356 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00005357
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005358 base = type->subtypes;
5359 if (base != NULL) {
Daniel Veillard377e1a92004-04-16 16:30:05 +00005360 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005361 } else {
5362 TODO}
Daniel Veillard4255d502002-04-16 15:50:10 +00005363 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005364 xmlSchemaTypePtr base;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005365 const xmlChar *cur, *end;
5366 xmlChar *tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005367 int ret2;
Daniel Veillard4255d502002-04-16 15:50:10 +00005368
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005369 base = type->subtypes;
5370 if (base == NULL) {
5371 xmlSchemaVErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL,
5372 "Internal: List type %s has no base type\n",
5373 type->name, NULL);
5374 return (-1);
5375 }
5376 cur = value;
5377 do {
William M. Brack76e95df2003-10-18 16:20:14 +00005378 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005379 cur++;
5380 end = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00005381 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005382 end++;
5383 if (end == cur)
5384 break;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005385 tmp = xmlStrndup(cur, end - cur);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005386 ret2 = xmlSchemaValidateSimpleValueInternal(ctxt, base, tmp, fireErrors);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005387 xmlFree(tmp);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005388 if (ret2 != 0)
5389 ret = 1;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005390 cur = end;
5391 } while (*cur != 0);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005392 } else if (type->type == XML_SCHEMA_TYPE_UNION) {
5393 ret = xmlSchemaValidateSimpleValueUnion(ctxt, type, value);
5394 if ((fireErrors) && (ret != 0)) {
5395 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, "Failed to validate type %s\n", type->name, NULL);
5396 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005397 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005398 TODO
5399 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005400 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005401}
5402
5403/************************************************************************
5404 * *
5405 * DOM Validation code *
5406 * *
5407 ************************************************************************/
5408
5409static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005410 xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005411static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005412 xmlNodePtr elem,
5413 xmlSchemaAttributePtr attributes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005414static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005415 xmlNodePtr elem,
5416 xmlSchemaElementPtr elemDecl,
5417 xmlSchemaTypePtr type);
Daniel Veillard4255d502002-04-16 15:50:10 +00005418
5419/**
5420 * xmlSchemaRegisterAttributes:
5421 * @ctxt: a schema validation context
5422 * @attrs: a list of attributes
5423 *
5424 * Register the list of attributes as the set to be validated on that element
5425 *
5426 * Returns -1 in case of error, 0 otherwise
5427 */
5428static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005429xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs)
5430{
Daniel Veillard4255d502002-04-16 15:50:10 +00005431 while (attrs != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005432 if ((attrs->ns != NULL) &&
5433 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
5434 attrs = attrs->next;
5435 continue;
5436 }
5437 if (ctxt->attrNr >= ctxt->attrMax) {
5438 xmlSchemaAttrStatePtr tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00005439
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005440 ctxt->attrMax *= 2;
5441 tmp = (xmlSchemaAttrStatePtr)
5442 xmlRealloc(ctxt->attr, ctxt->attrMax *
5443 sizeof(xmlSchemaAttrState));
5444 if (tmp == NULL) {
5445 xmlSchemaVErrMemory(ctxt, "registering attributes", NULL);
5446 ctxt->attrMax /= 2;
5447 return (-1);
5448 }
5449 ctxt->attr = tmp;
5450 }
5451 ctxt->attr[ctxt->attrNr].attr = attrs;
5452 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
5453 ctxt->attrNr++;
5454 attrs = attrs->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005455 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005456 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005457}
5458
5459/**
5460 * xmlSchemaCheckAttributes:
5461 * @ctxt: a schema validation context
5462 * @node: the node carrying it.
5463 *
5464 * Check that the registered set of attributes on the current node
5465 * has been properly validated.
5466 *
5467 * Returns 0 if validity constraints are met, 1 otherwise.
5468 */
5469static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005470xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5471{
Daniel Veillard4255d502002-04-16 15:50:10 +00005472 int ret = 0;
5473 int i;
5474
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005475 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
5476 if (ctxt->attr[i].attr == NULL)
5477 break;
5478 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
5479 ret = 1;
5480 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, "Attribute %s on %s is unknown\n", ctxt->attr[i].attr->name, node->name);
5481 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005482 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005483 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005484}
5485
5486/**
5487 * xmlSchemaValidateSimpleContent:
5488 * @ctxt: a schema validation context
5489 * @elem: an element
5490 * @type: the type declaration
5491 *
5492 * Validate the content of an element expected to be a simple type
5493 *
5494 * Returns 0 if the element is schemas valid, a positive error code
5495 * number otherwise and -1 in case of internal or API error.
5496 */
5497static int
5498xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005499 xmlNodePtr node ATTRIBUTE_UNUSED)
5500{
Daniel Veillard4255d502002-04-16 15:50:10 +00005501 xmlNodePtr child;
5502 xmlSchemaTypePtr type, base;
5503 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005504 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00005505
5506 child = ctxt->node;
5507 type = ctxt->type;
5508
5509 /*
5510 * Validation Rule: Element Locally Valid (Type): 3.1.3
5511 */
5512 value = xmlNodeGetContent(child);
5513 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
5514 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005515 case XML_SCHEMA_TYPE_RESTRICTION:{
5516 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005517
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005518 base = type->baseType;
5519 if (base != NULL) {
5520 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5521 } else {
5522 TODO}
5523 if (ret == 0) {
5524 facet = type->facets;
5525 ret =
5526 xmlSchemaValidateFacets(ctxt, base, facet, value);
5527 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005528 if ((ret == 0) && (type->attributes != NULL)) {
5529 ret = xmlSchemaValidateAttributes(ctxt, node,
5530 type->attributes);
5531 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005532 break;
5533 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005534 case XML_SCHEMA_TYPE_EXTENSION:{
5535 TODO
5536 break;
5537 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005538 default:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005539 TODO
5540 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005541 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005542 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005543
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005544 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005545}
5546
5547/**
5548 * xmlSchemaValidateCheckNodeList
5549 * @nodelist: the list of nodes
5550 *
5551 * Check the node list is only made of text nodes and entities pointing
5552 * to text nodes
5553 *
5554 * Returns 1 if true, 0 if false and -1 in case of error
5555 */
5556static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005557xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist)
5558{
Daniel Veillard4255d502002-04-16 15:50:10 +00005559 while (nodelist != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005560 if (nodelist->type == XML_ENTITY_REF_NODE) {
5561 TODO /* implement recursion in the entity content */
5562 }
5563 if ((nodelist->type != XML_TEXT_NODE) &&
5564 (nodelist->type != XML_COMMENT_NODE) &&
5565 (nodelist->type != XML_PI_NODE) &&
5566 (nodelist->type != XML_PI_NODE)) {
5567 return (0);
5568 }
5569 nodelist = nodelist->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005570 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005571 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005572}
5573
5574/**
5575 * xmlSchemaSkipIgnored:
5576 * @ctxt: a schema validation context
5577 * @type: the current type context
5578 * @node: the top node.
5579 *
5580 * Skip ignorable nodes in that context
5581 *
5582 * Returns the new sibling
5583 * number otherwise and -1 in case of internal or API error.
5584 */
5585static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00005586xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005587 xmlSchemaTypePtr type, xmlNodePtr node)
5588{
Daniel Veillard4255d502002-04-16 15:50:10 +00005589 int mixed = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005590
Daniel Veillard4255d502002-04-16 15:50:10 +00005591 /*
5592 * TODO complete and handle entities
5593 */
5594 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005595 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
Daniel Veillard4255d502002-04-16 15:50:10 +00005596 while ((node != NULL) &&
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005597 ((node->type == XML_COMMENT_NODE) ||
5598 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
5599 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
5600 (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) {
5601 node = node->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005602 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005603 return (node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005604}
5605
5606/**
5607 * xmlSchemaValidateCallback:
5608 * @ctxt: a schema validation context
5609 * @name: the name of the element detected (might be NULL)
5610 * @type: the type
5611 *
5612 * A transition has been made in the automata associated to an element
5613 * content model
5614 */
5615static void
5616xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005617 const xmlChar * name ATTRIBUTE_UNUSED,
5618 xmlSchemaTypePtr type, xmlNodePtr node)
5619{
Daniel Veillard4255d502002-04-16 15:50:10 +00005620 xmlSchemaTypePtr oldtype = ctxt->type;
5621 xmlNodePtr oldnode = ctxt->node;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005622
Daniel Veillard4255d502002-04-16 15:50:10 +00005623#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00005624 xmlGenericError(xmlGenericErrorContext,
5625 "xmlSchemaValidateCallback: %s, %s, %s\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005626 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005627#endif
5628 ctxt->type = type;
5629 ctxt->node = node;
5630 xmlSchemaValidateContent(ctxt, node);
5631 ctxt->type = oldtype;
5632 ctxt->node = oldnode;
5633}
5634
5635
5636#if 0
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005637
Daniel Veillard4255d502002-04-16 15:50:10 +00005638/**
5639 * xmlSchemaValidateSimpleRestrictionType:
5640 * @ctxt: a schema validation context
5641 * @node: the top node.
5642 *
5643 * Validate the content of a restriction type.
5644 *
5645 * Returns 0 if the element is schemas valid, a positive error code
5646 * number otherwise and -1 in case of internal or API error.
5647 */
5648static int
5649xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
5650 xmlNodePtr node)
5651{
5652 xmlNodePtr child;
5653 xmlSchemaTypePtr type;
5654 int ret;
5655
5656 child = ctxt->node;
5657 type = ctxt->type;
5658
5659 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005660 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005661 return (-1);
5662 }
5663 /*
5664 * Only text and text based entities references shall be found there
5665 */
5666 ret = xmlSchemaValidateCheckNodeList(child);
5667 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005668 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005669 return (-1);
5670 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005671 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 +00005672 return (-1);
5673 }
5674 ctxt->type = type->subtypes;
5675 xmlSchemaValidateContent(ctxt, node);
5676 ctxt->type = type;
5677 return (ret);
5678}
5679#endif
5680
5681/**
5682 * xmlSchemaValidateSimpleType:
5683 * @ctxt: a schema validation context
5684 * @node: the top node.
5685 *
5686 * Validate the content of an simple type.
5687 *
5688 * Returns 0 if the element is schemas valid, a positive error code
5689 * number otherwise and -1 in case of internal or API error.
5690 */
5691static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005692xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5693{
Daniel Veillard4255d502002-04-16 15:50:10 +00005694 xmlNodePtr child;
5695 xmlSchemaTypePtr type;
5696 xmlAttrPtr attr;
5697 int ret;
5698
5699 child = ctxt->node;
5700 type = ctxt->type;
5701
5702 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005703 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s\n", node->name, NULL);
5704 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005705 }
5706 /*
5707 * Only text and text based entities references shall be found there
5708 */
5709 ret = xmlSchemaValidateCheckNodeList(child);
5710 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005711 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
5712 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005713 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005714 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, "Element %s content is not a simple type\n", node->name, NULL);
5715 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005716 }
5717 /*
5718 * Validation Rule: Element Locally Valid (Type): 3.1.1
5719 */
5720 attr = node->properties;
5721 while (attr != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005722 if ((attr->ns == NULL) ||
5723 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
5724 ((!xmlStrEqual(attr->name, BAD_CAST "type")) &&
5725 (!xmlStrEqual(attr->name, BAD_CAST "nil")) &&
5726 (!xmlStrEqual(attr->name, BAD_CAST "schemasLocation")) &&
5727 (!xmlStrEqual
5728 (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) {
5729 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDATTR, "Element %s: attribute %s should not be present\n", node->name, attr->name);
5730 return (ctxt->err);
5731 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005732 }
5733
5734 ctxt->type = type->subtypes;
5735 ret = xmlSchemaValidateSimpleContent(ctxt, node);
5736 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005737 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005738}
5739
5740/**
5741 * xmlSchemaValidateElementType:
5742 * @ctxt: a schema validation context
5743 * @node: the top node.
5744 *
5745 * Validate the content of an element type.
5746 * Validation Rule: Element Locally Valid (Complex Type)
5747 *
5748 * Returns 0 if the element is schemas valid, a positive error code
5749 * number otherwise and -1 in case of internal or API error.
5750 */
5751static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005752xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5753{
Daniel Veillard4255d502002-04-16 15:50:10 +00005754 xmlNodePtr child;
5755 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005756 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
Daniel Veillard4255d502002-04-16 15:50:10 +00005757 xmlSchemaElementPtr decl;
5758 int ret, attrBase;
5759
5760 oldregexp = ctxt->regexp;
5761
5762 child = ctxt->node;
5763 type = ctxt->type;
5764
5765 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005766 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateElementType\n", node->name, NULL);
5767 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005768 }
5769 if (child == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005770 if (type->minOccurs > 0) {
5771 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, "Element %s: missing child %s\n", node->name, type->name);
5772 }
5773 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005774 }
5775
5776 /*
5777 * Verify the element matches
5778 */
5779 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005780 xmlSchemaVErr3(ctxt, node, XML_SCHEMAS_ERR_WRONGELEM, "Element %s: missing child %s found %s\n", node->name, type->name, child->name);
5781 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005782 }
5783 /*
5784 * Verify the attributes
5785 */
5786 attrBase = ctxt->attrBase;
5787 ctxt->attrBase = ctxt->attrNr;
5788 xmlSchemaRegisterAttributes(ctxt, child->properties);
5789 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
5790 /*
5791 * Verify the element content recursively
5792 */
5793 decl = (xmlSchemaElementPtr) type;
5794 oldregexp = ctxt->regexp;
5795 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005796 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5797 (xmlRegExecCallbacks)
5798 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005799#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005800 xmlGenericError(xmlGenericErrorContext, "====> %s\n", node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005801#endif
5802 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005803 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr) type,
5804 type->subtypes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005805
5806 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005807 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005808#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005809 xmlGenericError(xmlGenericErrorContext,
5810 "====> %s : %d\n", node->name, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005811#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005812 if (ret == 0) {
5813 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", node->name, NULL);
5814 } else if (ret < 0) {
5815 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failure\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005816#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005817 } else {
5818 xmlGenericError(xmlGenericErrorContext,
5819 "Element %s content check succeeded\n",
5820 node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005821
5822#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005823 }
5824 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00005825 }
5826 /*
5827 * Verify that all attributes were Schemas-validated
5828 */
5829 xmlSchemaCheckAttributes(ctxt, node);
5830 ctxt->attrNr = ctxt->attrBase;
5831 ctxt->attrBase = attrBase;
5832
5833 ctxt->regexp = oldregexp;
5834
5835 ctxt->node = child;
5836 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005837 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005838}
5839
5840/**
5841 * xmlSchemaValidateBasicType:
5842 * @ctxt: a schema validation context
5843 * @node: the top node.
5844 *
5845 * Validate the content of an element expected to be a basic type type
5846 *
5847 * Returns 0 if the element is schemas valid, a positive error code
5848 * number otherwise and -1 in case of internal or API error.
5849 */
5850static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005851xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5852{
Daniel Veillard4255d502002-04-16 15:50:10 +00005853 int ret;
5854 xmlNodePtr child, cur;
5855 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005856 xmlChar *value; /* lexical representation */
Daniel Veillard4255d502002-04-16 15:50:10 +00005857
5858 child = ctxt->node;
5859 type = ctxt->type;
5860
5861 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005862 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateBasicType\n", node->name, NULL);
5863 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005864 }
5865 /*
5866 * First check the content model of the node.
5867 */
5868 cur = child;
5869 while (cur != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005870 switch (cur->type) {
5871 case XML_TEXT_NODE:
5872 case XML_CDATA_SECTION_NODE:
5873 case XML_PI_NODE:
5874 case XML_COMMENT_NODE:
5875 case XML_XINCLUDE_START:
5876 case XML_XINCLUDE_END:
5877 break;
5878 case XML_ENTITY_REF_NODE:
5879 case XML_ENTITY_NODE:
5880 TODO break;
5881 case XML_ELEMENT_NODE:
5882 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: child %s should not be present\n", node->name, cur->name);
5883 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005884 case XML_ATTRIBUTE_NODE:
5885 case XML_DOCUMENT_NODE:
5886 case XML_DOCUMENT_TYPE_NODE:
5887 case XML_DOCUMENT_FRAG_NODE:
5888 case XML_NOTATION_NODE:
5889 case XML_HTML_DOCUMENT_NODE:
5890 case XML_DTD_NODE:
5891 case XML_ELEMENT_DECL:
5892 case XML_ATTRIBUTE_DECL:
5893 case XML_ENTITY_DECL:
5894 case XML_NAMESPACE_DECL:
5895#ifdef LIBXML_DOCB_ENABLED
5896 case XML_DOCB_DOCUMENT_NODE:
5897#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005898 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: node type of node unexpected here\n", node->name, NULL);
5899 return (ctxt->err);
5900 }
5901 cur = cur->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005902 }
5903 if (child == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005904 value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005905 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005906 value = xmlNodeGetContent(child->parent);
Daniel Veillard4255d502002-04-16 15:50:10 +00005907
5908 if (ctxt->value != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005909 xmlSchemaFreeValue(ctxt->value);
5910 ctxt->value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005911 }
5912 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5913 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005914 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005915 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005916 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 +00005917 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005918 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005919}
5920
5921/**
5922 * xmlSchemaValidateComplexType:
5923 * @ctxt: a schema validation context
5924 * @node: the top node.
5925 *
5926 * Validate the content of an element expected to be a complex type type
5927 * xmlschema-1.html#cvc-complex-type
5928 * Validation Rule: Element Locally Valid (Complex Type)
5929 *
5930 * Returns 0 if the element is schemas valid, a positive error code
5931 * number otherwise and -1 in case of internal or API error.
5932 */
5933static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005934xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5935{
Daniel Veillard4255d502002-04-16 15:50:10 +00005936 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005937 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005938 int ret;
5939
5940 child = ctxt->node;
5941 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005942 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005943
Daniel Veillard4255d502002-04-16 15:50:10 +00005944 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005945 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005946 if (type->baseType != NULL) {
5947 } else if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005948 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is supposed to be empty\n", node->name, NULL);
5949 }
5950 if (type->attributes != NULL) {
5951 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5952 }
5953 subtype = type->subtypes;
5954 while (subtype != NULL) {
5955 ctxt->type = subtype;
5956 xmlSchemaValidateComplexType(ctxt, node);
5957 subtype = subtype->next;
5958 }
5959 break;
5960 case XML_SCHEMA_CONTENT_ELEMENTS:
5961 case XML_SCHEMA_CONTENT_MIXED:
5962 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5963 /*
5964 * Skip ignorable nodes in that context
5965 */
5966 child = xmlSchemaSkipIgnored(ctxt, type, child);
5967 while (child != NULL) {
5968 if (child->type == XML_ELEMENT_NODE) {
5969 ret = xmlRegExecPushString(ctxt->regexp,
5970 child->name, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005971#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005972 if (ret < 0)
5973 xmlGenericError(xmlGenericErrorContext,
5974 " --> %s Error\n", child->name);
5975 else
5976 xmlGenericError(xmlGenericErrorContext,
5977 " --> %s\n", child->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005978#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005979 }
5980 child = child->next;
5981 /*
5982 * Skip ignorable nodes in that context
5983 */
5984 child = xmlSchemaSkipIgnored(ctxt, type, child);
5985 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005986 if (type->attributes != NULL) {
5987 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5988 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005989 break;
5990 case XML_SCHEMA_CONTENT_BASIC:{
5991 if (type->subtypes != NULL) {
5992 ctxt->type = type->subtypes;
5993 xmlSchemaValidateComplexType(ctxt, node);
5994 }
5995 if (type->baseType != NULL) {
5996 ctxt->type = type->baseType;
5997 xmlSchemaValidateBasicType(ctxt, node);
5998 }
5999 if (type->attributes != NULL) {
6000 xmlSchemaValidateAttributes(ctxt, node,
6001 type->attributes);
6002 }
6003 ctxt->type = type;
6004 break;
6005 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006006 case XML_SCHEMA_CONTENT_SIMPLE:{
6007 if (type->subtypes != NULL) {
6008 ctxt->type = type->subtypes;
6009 xmlSchemaValidateComplexType(ctxt, node);
6010 }
6011 if (type->baseType != NULL) {
6012 ctxt->type = type->baseType;
6013 xmlSchemaValidateComplexType(ctxt, node);
6014 }
6015 if (type->attributes != NULL) {
6016 xmlSchemaValidateAttributes(ctxt, node,
6017 type->attributes);
6018 }
6019 ctxt->type = type;
6020 break;
6021 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006022 default:
6023 TODO xmlGenericError(xmlGenericErrorContext,
6024 "unimplemented content type %d\n",
6025 type->contentType);
Daniel Veillard4255d502002-04-16 15:50:10 +00006026 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006027 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006028}
6029
6030/**
6031 * xmlSchemaValidateContent:
6032 * @ctxt: a schema validation context
6033 * @elem: an element
6034 * @type: the type declaration
6035 *
6036 * Validate the content of an element against the type.
6037 *
6038 * Returns 0 if the element is schemas valid, a positive error code
6039 * number otherwise and -1 in case of internal or API error.
6040 */
6041static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006042xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
6043{
Daniel Veillard4255d502002-04-16 15:50:10 +00006044 xmlNodePtr child;
6045 xmlSchemaTypePtr type;
6046
6047 child = ctxt->node;
6048 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00006049 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00006050
Daniel Veillarde19fc232002-04-22 16:01:24 +00006051 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00006052 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00006053
Daniel Veillard4255d502002-04-16 15:50:10 +00006054 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006055 case XML_SCHEMA_TYPE_ANY:
6056 /* Any type will do it, fine */
6057 TODO /* handle recursivity */
6058 break;
6059 case XML_SCHEMA_TYPE_COMPLEX:
6060 xmlSchemaValidateComplexType(ctxt, node);
6061 break;
6062 case XML_SCHEMA_TYPE_ELEMENT:{
6063 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
6064
6065 /*
6066 * Handle element reference here
6067 */
6068 if (decl->ref != NULL) {
6069 if (decl->refDecl == NULL) {
6070 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: element reference %s not resolved\n", decl->ref, NULL);
6071 return (-1);
6072 }
6073 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
6074 decl = decl->refDecl;
6075 }
6076 xmlSchemaValidateElementType(ctxt, node);
6077 ctxt->type = type;
6078 break;
6079 }
6080 case XML_SCHEMA_TYPE_BASIC:
6081 xmlSchemaValidateBasicType(ctxt, node);
6082 break;
6083 case XML_SCHEMA_TYPE_FACET:
6084 TODO break;
6085 case XML_SCHEMA_TYPE_SIMPLE:
6086 xmlSchemaValidateSimpleType(ctxt, node);
6087 break;
6088 case XML_SCHEMA_TYPE_SEQUENCE:
6089 TODO break;
6090 case XML_SCHEMA_TYPE_CHOICE:
6091 TODO break;
6092 case XML_SCHEMA_TYPE_ALL:
6093 TODO break;
6094 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
6095 TODO break;
6096 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
6097 TODO break;
6098 case XML_SCHEMA_TYPE_UR:
6099 TODO break;
6100 case XML_SCHEMA_TYPE_RESTRICTION:
6101 /*xmlSchemaValidateRestrictionType(ctxt, node); */
6102 TODO break;
6103 case XML_SCHEMA_TYPE_EXTENSION:
6104 TODO break;
6105 case XML_SCHEMA_TYPE_ATTRIBUTE:
6106 TODO break;
6107 case XML_SCHEMA_TYPE_GROUP:
6108 TODO break;
6109 case XML_SCHEMA_TYPE_NOTATION:
6110 TODO break;
6111 case XML_SCHEMA_TYPE_LIST:
6112 TODO break;
6113 case XML_SCHEMA_TYPE_UNION:
6114 TODO break;
6115 case XML_SCHEMA_FACET_MININCLUSIVE:
6116 TODO break;
6117 case XML_SCHEMA_FACET_MINEXCLUSIVE:
6118 TODO break;
6119 case XML_SCHEMA_FACET_MAXINCLUSIVE:
6120 TODO break;
6121 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
6122 TODO break;
6123 case XML_SCHEMA_FACET_TOTALDIGITS:
6124 TODO break;
6125 case XML_SCHEMA_FACET_FRACTIONDIGITS:
6126 TODO break;
6127 case XML_SCHEMA_FACET_PATTERN:
6128 TODO break;
6129 case XML_SCHEMA_FACET_ENUMERATION:
6130 TODO break;
6131 case XML_SCHEMA_FACET_WHITESPACE:
6132 TODO break;
6133 case XML_SCHEMA_FACET_LENGTH:
6134 TODO break;
6135 case XML_SCHEMA_FACET_MAXLENGTH:
6136 TODO break;
6137 case XML_SCHEMA_FACET_MINLENGTH:
6138 TODO break;
6139 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
6140 TODO break;
Daniel Veillard4255d502002-04-16 15:50:10 +00006141 }
6142 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
6143
6144 if (ctxt->node == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006145 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006146 ctxt->node = ctxt->node->next;
6147 ctxt->type = type->next;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006148 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006149}
6150
6151/**
6152 * xmlSchemaValidateType:
6153 * @ctxt: a schema validation context
6154 * @elem: an element
6155 * @type: the list of type declarations
6156 *
6157 * Validate the content of an element against the types.
6158 *
6159 * Returns 0 if the element is schemas valid, a positive error code
6160 * number otherwise and -1 in case of internal or API error.
6161 */
6162static int
6163xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006164 xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type)
6165{
Daniel Veillard4255d502002-04-16 15:50:10 +00006166 xmlChar *nil;
6167
Daniel Veillard2db8c122003-07-08 12:16:59 +00006168 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006169 return (0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00006170
Daniel Veillard4255d502002-04-16 15:50:10 +00006171 /*
6172 * 3.3.4 : 2
6173 */
6174 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006175 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, "Element %s is abstract\n", elem->name, NULL);
6176 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006177 }
6178 /*
6179 * 3.3.4: 3
6180 */
6181 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
6182 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006183 /* 3.3.4: 3.2 */
6184 if (xmlStrEqual(nil, BAD_CAST "true")) {
6185 if (elem->children != NULL) {
6186 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is not empty\n", elem->name, NULL);
6187 return (ctxt->err);
6188 }
6189 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
6190 (elemDecl->value != NULL)) {
6191 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_HAVEDEFAULT, "Empty element %s cannot get a fixed value\n", elem->name, NULL);
6192 return (ctxt->err);
6193 }
6194 }
Daniel Veillard4255d502002-04-16 15:50:10 +00006195 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006196 /* 3.3.4: 3.1 */
6197 if (nil != NULL) {
6198 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTNILLABLE, "Element %s with xs:nil but not nillable\n", elem->name, NULL);
6199 xmlFree(nil);
6200 return (ctxt->err);
6201 }
Daniel Veillard4255d502002-04-16 15:50:10 +00006202 }
6203
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006204 /* TODO 3.3.4: 4 if the element carries xs:type */
Daniel Veillard4255d502002-04-16 15:50:10 +00006205
6206 ctxt->type = elemDecl->subtypes;
6207 ctxt->node = elem->children;
6208 xmlSchemaValidateContent(ctxt, elem);
6209 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006210
6211 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006212}
6213
6214
6215/**
6216 * xmlSchemaValidateAttributes:
6217 * @ctxt: a schema validation context
6218 * @elem: an element
6219 * @attributes: the list of attribute declarations
6220 *
6221 * Validate the attributes of an element.
6222 *
6223 * Returns 0 if the element is schemas valid, a positive error code
6224 * number otherwise and -1 in case of internal or API error.
6225 */
6226static int
6227xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006228 xmlSchemaAttributePtr attributes)
6229{
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006230 int i, ret, count = 1;
Daniel Veillard4255d502002-04-16 15:50:10 +00006231 xmlAttrPtr attr;
6232 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00006233 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006234 int found;
Daniel Veillard4255d502002-04-16 15:50:10 +00006235
6236 if (attributes == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006237 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006238 while (attributes != NULL) {
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006239 found = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006240 /*
6241 * Handle attribute groups
6242 */
6243 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
6244 group = (xmlSchemaAttributeGroupPtr) attributes;
6245 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
6246 attributes = group->next;
6247 continue;
6248 }
6249 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
6250 attr = ctxt->attr[i].attr;
6251 if (attr == NULL)
6252 continue;
6253 if (attributes->ref != NULL) {
6254 if (!xmlStrEqual(attr->name, attributes->ref))
6255 continue;
6256 if (attr->ns != NULL) {
6257 if ((attributes->refNs == NULL) ||
6258 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
6259 continue;
6260 } else if (attributes->refNs != NULL) {
6261 continue;
6262 }
6263 } else {
6264 if (!xmlStrEqual(attr->name, attributes->name))
6265 continue;
6266 /*
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006267 * handle the namespaces checks here
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006268 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006269 if (attr->ns == NULL) {
6270 /*
6271 * accept an unqualified attribute only if the declaration
6272 * is unqualified or if the schemas allowed it.
6273 */
6274 if ((attributes->targetNamespace != NULL) &&
6275 ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0))
6276 continue;
6277 } else {
6278 if (attributes->targetNamespace == NULL)
6279 continue;
6280 if (!xmlStrEqual(attributes->targetNamespace,
6281 attr->ns->href))
6282 continue;
6283 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006284 }
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006285 found = 1;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006286 ctxt->cur = (xmlNodePtr) attributes;
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006287
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006288 if (attributes->subtypes == NULL) {
6289 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL);
6290 continue;
6291 }
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006292
6293 if (attributes->occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) {
6294 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_INVALIDATTR, "attribute %s on %s is prohibited\n", attributes->name, elem->name);
6295 /* Setting the state to XML_SCHEMAS_ATTR_CHECKED seems not very logical but it
6296 surpresses the "attribute is unknown" error report. Please change this if you know better */
6297 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
6298 break;
6299 }
6300
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006301 value = xmlNodeListGetString(elem->doc, attr->children, 1);
6302 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
6303 value);
6304 if (ret != 0) {
6305 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_ATTRINVALID, "attribute %s on %s does not match type\n", attr->name, elem->name);
6306 } else {
6307 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
6308 }
6309 if (value != NULL) {
6310 xmlFree(value);
6311 }
6312 }
Daniel Veillardc85d0fe2004-04-16 16:46:51 +00006313 if ((!found) && (attributes->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) {
6314 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_MISSING, "required attribute %s on %s is missing\n", attributes->name, elem->name);
6315 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006316 attributes = attributes->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00006317 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006318 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006319}
6320
6321/**
6322 * xmlSchemaValidateElement:
6323 * @ctxt: a schema validation context
6324 * @elem: an element
6325 *
6326 * Validate an element in a tree
6327 *
6328 * Returns 0 if the element is schemas valid, a positive error code
6329 * number otherwise and -1 in case of internal or API error.
6330 */
6331static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006332xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem)
6333{
Daniel Veillard4255d502002-04-16 15:50:10 +00006334 xmlSchemaElementPtr elemDecl;
6335 int ret, attrBase;
6336
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006337 if (elem->ns != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006338 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6339 elem->name, elem->ns->href, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006340 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006341 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6342 elem->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006343 }
6344 /*
6345 * special case whe elementFormDefault is unqualified for top-level elem.
6346 */
6347 if ((elemDecl == NULL) && (elem->ns != NULL) &&
6348 (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) &&
6349 (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) &&
6350 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6351 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6352 elem->name, NULL, NULL);
6353 }
6354
Daniel Veillard4255d502002-04-16 15:50:10 +00006355 /*
6356 * 3.3.4 : 1
6357 */
6358 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006359 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", elem->name, NULL);
6360 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006361 }
6362 if (elemDecl->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006363 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTYPE, "Element %s has no type\n", elem->name, NULL);
6364 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006365 }
6366 /*
6367 * Verify the attributes
6368 */
6369 attrBase = ctxt->attrBase;
6370 ctxt->attrBase = ctxt->attrNr;
6371 xmlSchemaRegisterAttributes(ctxt, elem->properties);
6372 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
6373 /*
6374 * Verify the element content recursively
6375 */
6376 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006377 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
6378 (xmlRegExecCallbacks)
6379 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00006380#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006381 xmlGenericError(xmlGenericErrorContext, "====> %s\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006382#endif
6383 }
6384 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006385 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006386 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006387#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006388 xmlGenericError(xmlGenericErrorContext,
6389 "====> %s : %d\n", elem->name, ret);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006390#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006391 if (ret == 0) {
6392 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
6393 } else if (ret < 0) {
6394 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006395#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006396 } else {
6397 xmlGenericError(xmlGenericErrorContext,
6398 "Element %s content check succeeded\n",
6399 elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006400
6401#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006402 }
6403 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00006404 }
6405 /*
6406 * Verify that all attributes were Schemas-validated
6407 */
6408 xmlSchemaCheckAttributes(ctxt, elem);
6409 ctxt->attrNr = ctxt->attrBase;
6410 ctxt->attrBase = attrBase;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006411
6412 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006413}
6414
6415/**
6416 * xmlSchemaValidateDocument:
6417 * @ctxt: a schema validation context
6418 * @doc: a parsed document tree
6419 *
6420 * Validate a document tree in memory.
6421 *
6422 * Returns 0 if the document is schemas valid, a positive error code
6423 * number otherwise and -1 in case of internal or API error.
6424 */
6425static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006426xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6427{
Daniel Veillard4255d502002-04-16 15:50:10 +00006428 xmlNodePtr root;
6429 xmlSchemaElementPtr elemDecl;
6430
6431 root = xmlDocGetRootElement(doc);
6432 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006433 xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, "document has no root\n", NULL, NULL);
6434 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006435 }
6436 if (root->ns != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006437 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6438 root->name, root->ns->href, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006439 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006440 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6441 root->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006442 /*
6443 * special case whe elementFormDefault is unqualified for top-level elem.
6444 */
6445 if ((elemDecl == NULL) && (root->ns != NULL) &&
6446 (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) &&
6447 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6448 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6449 root->name, NULL, NULL);
6450 }
6451
Daniel Veillard4255d502002-04-16 15:50:10 +00006452 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006453 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", root->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006454 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006455 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, "Root element %s not toplevel\n", root->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006456 }
6457 /*
6458 * Okay, start the recursive validation
6459 */
6460 xmlSchemaValidateElement(ctxt, root);
6461
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006462 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006463}
6464
6465/************************************************************************
6466 * *
6467 * SAX Validation code *
6468 * *
6469 ************************************************************************/
6470
6471/************************************************************************
6472 * *
6473 * Validation interfaces *
6474 * *
6475 ************************************************************************/
6476
6477/**
6478 * xmlSchemaNewValidCtxt:
6479 * @schema: a precompiled XML Schemas
6480 *
6481 * Create an XML Schemas validation context based on the given schema
6482 *
6483 * Returns the validation context or NULL in case of error
6484 */
6485xmlSchemaValidCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006486xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
6487{
Daniel Veillard4255d502002-04-16 15:50:10 +00006488 xmlSchemaValidCtxtPtr ret;
6489
6490 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
6491 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006492 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006493 return (NULL);
6494 }
6495 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
6496 ret->schema = schema;
6497 ret->attrNr = 0;
6498 ret->attrMax = 10;
6499 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006500 sizeof
6501 (xmlSchemaAttrState));
Daniel Veillard4255d502002-04-16 15:50:10 +00006502 if (ret->attr == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006503 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
6504 free(ret);
6505 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006506 }
6507 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
6508 return (ret);
6509}
6510
6511/**
6512 * xmlSchemaFreeValidCtxt:
6513 * @ctxt: the schema validation context
6514 *
6515 * Free the resources associated to the schema validation context
6516 */
6517void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006518xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
6519{
Daniel Veillard4255d502002-04-16 15:50:10 +00006520 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006521 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006522 if (ctxt->attr != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006523 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00006524 if (ctxt->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006525 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00006526 xmlFree(ctxt);
6527}
6528
6529/**
6530 * xmlSchemaSetValidErrors:
6531 * @ctxt: a schema validation context
6532 * @err: the error function
6533 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00006534 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00006535 *
6536 * Set the error and warning callback informations
6537 */
6538void
6539xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006540 xmlSchemaValidityErrorFunc err,
6541 xmlSchemaValidityWarningFunc warn, void *ctx)
6542{
Daniel Veillard4255d502002-04-16 15:50:10 +00006543 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006544 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006545 ctxt->error = err;
6546 ctxt->warning = warn;
6547 ctxt->userData = ctx;
6548}
6549
6550/**
6551 * xmlSchemaValidateDoc:
6552 * @ctxt: a schema validation context
6553 * @doc: a parsed document tree
6554 *
6555 * Validate a document tree in memory.
6556 *
6557 * Returns 0 if the document is schemas valid, a positive error code
6558 * number otherwise and -1 in case of internal or API error.
6559 */
6560int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006561xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6562{
Daniel Veillard4255d502002-04-16 15:50:10 +00006563 int ret;
6564
6565 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006566 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006567
6568 ctxt->doc = doc;
6569 ret = xmlSchemaValidateDocument(ctxt, doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006570 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00006571}
6572
6573/**
6574 * xmlSchemaValidateStream:
6575 * @ctxt: a schema validation context
6576 * @input: the input to use for reading the data
6577 * @enc: an optional encoding information
6578 * @sax: a SAX handler for the resulting events
6579 * @user_data: the context to provide to the SAX handler.
6580 *
6581 * Validate a document tree in memory.
6582 *
6583 * Returns 0 if the document is schemas valid, a positive error code
6584 * number otherwise and -1 in case of internal or API error.
6585 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006586int
Daniel Veillard4255d502002-04-16 15:50:10 +00006587xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006588 xmlParserInputBufferPtr input, xmlCharEncoding enc,
6589 xmlSAXHandlerPtr sax, void *user_data)
6590{
Daniel Veillard4255d502002-04-16 15:50:10 +00006591 if ((ctxt == NULL) || (input == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006592 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006593 ctxt->input = input;
6594 ctxt->enc = enc;
6595 ctxt->sax = sax;
6596 ctxt->user_data = user_data;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006597 TODO return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006598}
6599
6600#endif /* LIBXML_SCHEMAS_ENABLED */