blob: be7b6ae87e5c4bfee48add261a88c4789c1be74f [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 Veillardbe9c6322003-11-22 20:37:51 +00001999 const xmlChar *name, *refNs = NULL, *ref = NULL;
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 Veillard4255d502002-04-16 15:50:10 +00002028 ret->ref = ref;
2029 ret->refNs = refNs;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002030 if ((ret->targetNamespace != NULL) &&
2031 ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) &&
2032 (xmlStrEqual(ret->targetNamespace, schema->targetNamespace)))
2033 ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT;
Daniel Veillard4255d502002-04-16 15:50:10 +00002034 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002035 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002036 child = node->children;
2037 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002038 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2039 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002040 }
2041 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002042 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
2043 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002044 }
2045 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002046 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD,
2047 "attribute %s has unexpected content\n", name,
2048 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002049 }
2050
2051 return (ret);
2052}
2053
2054/**
2055 * xmlSchemaParseAttributeGroup:
2056 * @ctxt: a schema validation context
2057 * @schema: the schema being built
2058 * @node: a subtree containing XML Schema informations
2059 *
2060 * parse a XML schema Attribute Group declaration
2061 * *WARNING* this interface is highly subject to change
2062 *
2063 * Returns the attribute group or NULL in case of error.
2064 */
2065static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002066xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
2067 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002068{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002069 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002070 xmlSchemaAttributeGroupPtr ret;
2071 xmlSchemaAttributePtr last = NULL, attr;
2072 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002073 const xmlChar *oldcontainer;
2074 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002075
2076 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2077 return (NULL);
2078 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002079 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002080 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002081
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002082 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2083 if (ref == NULL) {
2084 xmlSchemaPErr2(ctxt, node, child,
2085 XML_SCHEMAP_ATTRGRP_NONAME_NOREF,
2086 "AttributeGroup has no name nor ref\n", NULL,
2087 NULL);
2088 return (NULL);
2089 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002090 snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1);
2091 name = (const xmlChar *) buf;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002092 if (name == NULL) {
2093 xmlSchemaPErrMemory(ctxt, "creating attribute group", node);
2094 return (NULL);
2095 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002096 }
2097 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
2098 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002099 return (NULL);
2100 }
2101 ret->ref = ref;
2102 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00002103 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002104 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002105 child = node->children;
2106 ctxt->container = name;
2107 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002108 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2109 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002110 }
2111 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002112 (IS_SCHEMA(child, "attributeGroup"))) {
2113 attr = NULL;
2114 if (IS_SCHEMA(child, "attribute")) {
2115 attr = xmlSchemaParseAttribute(ctxt, schema, child);
2116 } else if (IS_SCHEMA(child, "attributeGroup")) {
2117 attr = (xmlSchemaAttributePtr)
2118 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2119 }
2120 if (attr != NULL) {
2121 if (last == NULL) {
2122 ret->attributes = attr;
2123 last = attr;
2124 } else {
2125 last->next = attr;
2126 last = attr;
2127 }
2128 }
2129 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002130 }
2131 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002132 TODO
2133 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002134 }
2135 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002136 xmlSchemaPErr2(ctxt, node, child,
2137 XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD,
2138 "attribute group %s has unexpected content\n", name,
2139 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002140 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002141 ctxt->container = oldcontainer;
2142 return (ret);
2143}
2144
2145/**
2146 * xmlSchemaParseElement:
2147 * @ctxt: a schema validation context
2148 * @schema: the schema being built
2149 * @node: a subtree containing XML Schema informations
2150 *
2151 * parse a XML schema Element declaration
2152 * *WARNING* this interface is highly subject to change
2153 *
2154 * Returns -1 in case of error, 0 if the declaration is inproper and
2155 * 1 in case of success.
2156 */
2157static xmlSchemaElementPtr
2158xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2159 xmlNodePtr node, int toplevel)
2160{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002161 const xmlChar *name, *fixed;
2162 const xmlChar *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002163 xmlSchemaElementPtr ret;
2164 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002165 const xmlChar *oldcontainer;
2166 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002167
2168 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2169 return (NULL);
2170 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002171 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002172 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002173
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002174 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2175 if (ref == NULL) {
2176 xmlSchemaPErr2(ctxt, node, child,
2177 XML_SCHEMAP_ELEM_NONAME_NOREF,
2178 "Element has no name nor ref\n", NULL, NULL);
2179 return (NULL);
2180 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002181 snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1);
2182 name = (const xmlChar *) buf;
2183 ret = xmlSchemaAddElement(ctxt, schema, name, NULL);
2184 } else {
2185 const xmlChar *local, *ns;
2186
2187 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2188 ret = xmlSchemaAddElement(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002189 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002190 if (ret != NULL)
2191 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002192 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002193 return (NULL);
2194 }
2195 ret->type = XML_SCHEMA_TYPE_ELEMENT;
2196 ret->ref = ref;
2197 ret->refNs = refNs;
2198 if (ref != NULL)
2199 ret->flags |= XML_SCHEMAS_ELEM_REF;
2200 if (toplevel)
2201 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
2202 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
2203 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2204 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
2205 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2206 ctxt->container = name;
2207
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002208 ret->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002209 ret->namedType =
2210 xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
2211 ret->substGroup =
2212 xmlGetQNameProp(ctxt, node, "substitutionGroup",
2213 &(ret->substGroupNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002214 fixed = xmlSchemaGetProp(ctxt, node, "fixed");
Daniel Veillard4255d502002-04-16 15:50:10 +00002215 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
2216 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002217
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002218 ret->value = xmlSchemaGetProp(ctxt, node, "default");
Daniel Veillard4255d502002-04-16 15:50:10 +00002219 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002220 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED,
2221 "Element %s has both default and fixed\n",
2222 ret->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002223 } else if (fixed != NULL) {
2224 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002225 ret->value = fixed;
Daniel Veillard4255d502002-04-16 15:50:10 +00002226 }
2227
2228 child = node->children;
2229 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002230 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2231 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002232 }
2233 if (IS_SCHEMA(child, "complexType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002234 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002235 child = child->next;
2236 } else if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002237 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002238 child = child->next;
2239 }
2240 while ((IS_SCHEMA(child, "unique")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002241 (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
2242 TODO child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002243 }
2244 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002245 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD,
2246 "element %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002247 }
2248
2249 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00002250 return (ret);
2251}
2252
2253/**
2254 * xmlSchemaParseUnion:
2255 * @ctxt: a schema validation context
2256 * @schema: the schema being built
2257 * @node: a subtree containing XML Schema informations
2258 *
2259 * parse a XML schema Union definition
2260 * *WARNING* this interface is highly subject to change
2261 *
2262 * Returns -1 in case of error, 0 if the declaration is inproper and
2263 * 1 in case of success.
2264 */
2265static xmlSchemaTypePtr
2266xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002267 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002268{
2269 xmlSchemaTypePtr type, subtype, last = NULL;
2270 xmlNodePtr child = NULL;
2271 xmlChar name[30];
2272
2273 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2274 return (NULL);
2275
2276
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002277 snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002278 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002279 if (type == NULL)
2280 return (NULL);
2281 type->node = node;
Daniel Veillard377e1a92004-04-16 16:30:05 +00002282 type->type = XML_SCHEMA_TYPE_UNION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002283 type->id = xmlSchemaGetProp(ctxt, node, "id");
2284 type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes");
Daniel Veillard4255d502002-04-16 15:50:10 +00002285
2286 child = node->children;
2287 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002288 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2289 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002290 }
2291 while (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002292 subtype = (xmlSchemaTypePtr)
2293 xmlSchemaParseSimpleType(ctxt, schema, child);
2294 if (subtype != NULL) {
2295 if (last == NULL) {
2296 type->subtypes = subtype;
2297 last = subtype;
2298 } else {
2299 last->next = subtype;
2300 last = subtype;
2301 }
2302 last->next = NULL;
2303 }
2304 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002305 }
2306 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002307 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD,
2308 "Union %s has unexpected content\n", type->name,
2309 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002310 }
2311 return (type);
2312}
2313
2314/**
2315 * xmlSchemaParseList:
2316 * @ctxt: a schema validation context
2317 * @schema: the schema being built
2318 * @node: a subtree containing XML Schema informations
2319 *
2320 * parse a XML schema List definition
2321 * *WARNING* this interface is highly subject to change
2322 *
2323 * Returns -1 in case of error, 0 if the declaration is inproper and
2324 * 1 in case of success.
2325 */
2326static xmlSchemaTypePtr
2327xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002328 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002329{
2330 xmlSchemaTypePtr type, subtype;
2331 xmlNodePtr child = NULL;
2332 xmlChar name[30];
2333
2334 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2335 return (NULL);
2336
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002337 snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002338 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002339 if (type == NULL)
2340 return (NULL);
2341 type->node = node;
2342 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002343 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002344 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
2345
2346 child = node->children;
2347 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002348 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2349 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002350 }
2351 subtype = NULL;
2352 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002353 subtype = (xmlSchemaTypePtr)
2354 xmlSchemaParseSimpleType(ctxt, schema, child);
2355 child = child->next;
2356 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002357 }
2358 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002359 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD,
2360 "List %s has unexpected content\n", type->name,
2361 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002362 }
2363 return (type);
2364}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002365
Daniel Veillard4255d502002-04-16 15:50:10 +00002366/**
2367 * xmlSchemaParseSimpleType:
2368 * @ctxt: a schema validation context
2369 * @schema: the schema being built
2370 * @node: a subtree containing XML Schema informations
2371 *
2372 * parse a XML schema Simple Type definition
2373 * *WARNING* this interface is highly subject to change
2374 *
2375 * Returns -1 in case of error, 0 if the declaration is inproper and
2376 * 1 in case of success.
2377 */
2378static xmlSchemaTypePtr
2379xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2380 xmlNodePtr node)
2381{
2382 xmlSchemaTypePtr type, subtype;
2383 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002384 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00002385
2386 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2387 return (NULL);
2388
2389
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002390 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002391 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002392 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002393
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002394 snprintf(buf, 99, "simpletype %d", ctxt->counter++ + 1);
2395 type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL);
2396 } else {
2397 const xmlChar *local, *ns;
2398
2399 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2400 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002401 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002402 if (type == NULL)
2403 return (NULL);
2404 type->node = node;
2405 type->type = XML_SCHEMA_TYPE_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002406 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002407
2408 child = node->children;
2409 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002410 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2411 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002412 }
2413 subtype = NULL;
2414 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002415 subtype = (xmlSchemaTypePtr)
2416 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2417 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002418 } else if (IS_SCHEMA(child, "list")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002419 subtype = (xmlSchemaTypePtr)
2420 xmlSchemaParseList(ctxt, schema, child);
2421 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002422 } else if (IS_SCHEMA(child, "union")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002423 subtype = (xmlSchemaTypePtr)
2424 xmlSchemaParseUnion(ctxt, schema, child);
2425 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002426 }
2427 type->subtypes = subtype;
2428 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002429 xmlSchemaPErr2(ctxt, node, child,
2430 XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD,
2431 "SimpleType %s has unexpected content\n",
2432 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002433 }
2434
2435 return (type);
2436}
2437
2438
2439/**
2440 * xmlSchemaParseGroup:
2441 * @ctxt: a schema validation context
2442 * @schema: the schema being built
2443 * @node: a subtree containing XML Schema informations
2444 *
2445 * parse a XML schema Group definition
2446 * *WARNING* this interface is highly subject to change
2447 *
2448 * Returns -1 in case of error, 0 if the declaration is inproper and
2449 * 1 in case of success.
2450 */
2451static xmlSchemaTypePtr
2452xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002453 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002454{
2455 xmlSchemaTypePtr type, subtype;
2456 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002457 const xmlChar *name;
2458 const xmlChar *ref = NULL, *refNs = NULL;
2459 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002460
2461 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2462 return (NULL);
2463
2464
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002465 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002466 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002467
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002468 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2469 if (ref == NULL) {
2470 xmlSchemaPErr2(ctxt, node, child,
2471 XML_SCHEMAP_GROUP_NONAME_NOREF,
2472 "Group has no name nor ref\n", NULL, NULL);
2473 return (NULL);
2474 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002475 if (refNs == NULL)
2476 refNs = schema->targetNamespace;
2477 snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1);
2478 name = (const xmlChar *) buf;
Daniel Veillard4255d502002-04-16 15:50:10 +00002479 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002480 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002481 if (type == NULL)
2482 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00002483
Daniel Veillard4255d502002-04-16 15:50:10 +00002484 type->node = node;
2485 type->type = XML_SCHEMA_TYPE_GROUP;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002486 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002487 type->ref = ref;
2488 type->refNs = refNs;
2489 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2490 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2491
2492 child = node->children;
2493 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002494 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2495 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002496 }
2497 subtype = NULL;
2498 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002499 subtype = (xmlSchemaTypePtr)
2500 xmlSchemaParseAll(ctxt, schema, child);
2501 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002502 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002503 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2504 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002505 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002506 subtype = (xmlSchemaTypePtr)
2507 xmlSchemaParseSequence(ctxt, schema, child);
2508 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002509 }
2510 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002511 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002512 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002513 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD,
2514 "Group %s has unexpected content\n", type->name,
2515 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002516 }
2517
2518 return (type);
2519}
2520
2521/**
2522 * xmlSchemaParseAll:
2523 * @ctxt: a schema validation context
2524 * @schema: the schema being built
2525 * @node: a subtree containing XML Schema informations
2526 *
2527 * parse a XML schema All definition
2528 * *WARNING* this interface is highly subject to change
2529 *
2530 * Returns -1 in case of error, 0 if the declaration is inproper and
2531 * 1 in case of success.
2532 */
2533static xmlSchemaTypePtr
2534xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002535 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002536{
2537 xmlSchemaTypePtr type, subtype, last = NULL;
2538 xmlNodePtr child = NULL;
2539 xmlChar name[30];
2540
2541 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2542 return (NULL);
2543
2544
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002545 snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002546 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002547 if (type == NULL)
2548 return (NULL);
2549 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002550 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002551 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002552 type->minOccurs = xmlGetMinOccurs(ctxt, node);
William M. Brackb15351e2003-12-27 04:34:42 +00002553 if (type->minOccurs > 1)
2554 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS,
2555 "invalid value for minOccurs (must be 0 or 1)\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002556 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
William M. Brackb15351e2003-12-27 04:34:42 +00002557 if (type->maxOccurs > 1)
2558 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS,
2559 "invalid value for maxOccurs (must be 0 or 1)\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002560
2561 child = node->children;
2562 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002563 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2564 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002565 }
2566 while (IS_SCHEMA(child, "element")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002567 subtype = (xmlSchemaTypePtr)
2568 xmlSchemaParseElement(ctxt, schema, child, 0);
2569 if (subtype != NULL) {
William M. Brackb15351e2003-12-27 04:34:42 +00002570 if (subtype->minOccurs > 1)
2571 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MINOCCURS,
2572 "invalid value for minOccurs (must be 0 or 1)\n",
2573 NULL, NULL);
2574 if (subtype->maxOccurs > 1)
2575 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MAXOCCURS,
2576 "invalid value for maxOccurs (must be 0 or 1)\n",
2577 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002578 if (last == NULL) {
2579 type->subtypes = subtype;
2580 last = subtype;
2581 } else {
2582 last->next = subtype;
2583 last = subtype;
2584 }
2585 last->next = NULL;
2586 }
2587 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002588 }
2589 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002590 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD,
2591 "All %s has unexpected content\n", type->name,
2592 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002593 }
2594
2595 return (type);
2596}
2597
2598/**
Daniel Veillard1d913862003-11-21 00:28:39 +00002599 * xmlSchemaImportSchema
2600 *
2601 * @ctxt: a schema validation context
2602 * @schemaLocation: an URI defining where to find the imported schema
2603 *
2604 * import a XML schema
2605 * *WARNING* this interface is highly subject to change
2606 *
2607 * Returns -1 in case of error and 1 in case of success.
2608 */
2609static xmlSchemaImportPtr
2610xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt,
2611 const xmlChar *schemaLocation)
2612{
2613 xmlSchemaImportPtr import;
2614 xmlSchemaParserCtxtPtr newctxt;
2615
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002616 newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
Daniel Veillard1d913862003-11-21 00:28:39 +00002617 if (newctxt == NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002618 xmlSchemaPErrMemory(ctxt, "allocating schama parser context",
Daniel Veillard1d913862003-11-21 00:28:39 +00002619 NULL);
2620 return (NULL);
2621 }
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002622 memset(newctxt, 0, sizeof(xmlSchemaParserCtxt));
2623 /* Keep the same dictionnary for parsing, really */
2624 xmlDictReference(ctxt->dict);
2625 newctxt->dict = ctxt->dict;
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002626 newctxt->includes = 0;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002627 newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1);
2628
Daniel Veillard1d913862003-11-21 00:28:39 +00002629 xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning,
2630 ctxt->userData);
2631
2632 import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport));
2633 if (import == NULL) {
2634 xmlSchemaPErrMemory(NULL, "allocating imported schema",
2635 NULL);
2636 xmlSchemaFreeParserCtxt(newctxt);
2637 return (NULL);
2638 }
2639
2640 memset(import, 0, sizeof(xmlSchemaImport));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002641 import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
Daniel Veillard1d913862003-11-21 00:28:39 +00002642 import->schema = xmlSchemaParse(newctxt);
2643
2644 if (import->schema == NULL) {
2645 /* FIXME use another error enum here ? */
2646 xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL,
2647 "failed to import schema at location %s\n",
2648 schemaLocation, NULL);
2649
2650 xmlSchemaFreeParserCtxt(newctxt);
2651 if (import->schemaLocation != NULL)
2652 xmlFree((xmlChar *)import->schemaLocation);
2653 xmlFree(import);
2654 return NULL;
2655 }
2656
2657 xmlSchemaFreeParserCtxt(newctxt);
2658 return import;
2659}
2660
2661
2662/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002663 * xmlSchemaParseImport:
2664 * @ctxt: a schema validation context
2665 * @schema: the schema being built
2666 * @node: a subtree containing XML Schema informations
2667 *
2668 * parse a XML schema Import definition
2669 * *WARNING* this interface is highly subject to change
2670 *
2671 * Returns -1 in case of error, 0 if the declaration is inproper and
2672 * 1 in case of success.
2673 */
2674static int
2675xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002676 xmlNodePtr node)
Daniel Veillard5a872412002-05-22 06:40:27 +00002677{
2678 xmlNodePtr child = NULL;
Daniel Veillard1d913862003-11-21 00:28:39 +00002679 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002680 const xmlChar *namespace;
2681 const xmlChar *schemaLocation;
Daniel Veillard1d913862003-11-21 00:28:39 +00002682 const xmlChar *previous;
Daniel Veillard5a872412002-05-22 06:40:27 +00002683 xmlURIPtr check;
2684
Daniel Veillard1d913862003-11-21 00:28:39 +00002685
Daniel Veillard5a872412002-05-22 06:40:27 +00002686 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2687 return (-1);
2688
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002689 namespace = xmlSchemaGetProp(ctxt, node, "namespace");
Daniel Veillard5a872412002-05-22 06:40:27 +00002690 if (namespace != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002691 check = xmlParseURI((const char *) namespace);
2692 if (check == NULL) {
2693 xmlSchemaPErr2(ctxt, node, child,
2694 XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI,
2695 "Import namespace attribute is not an URI: %s\n",
2696 namespace, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002697 return (-1);
2698 } else {
2699 xmlFreeURI(check);
2700 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002701 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002702 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
Daniel Veillard5a872412002-05-22 06:40:27 +00002703 if (schemaLocation != NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002704 xmlChar *base = NULL;
2705 xmlChar *URI = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002706 check = xmlParseURI((const char *) schemaLocation);
2707 if (check == NULL) {
2708 xmlSchemaPErr2(ctxt, node, child,
2709 XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI,
2710 "Import schemaLocation attribute is not an URI: %s\n",
2711 schemaLocation, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002712 return (-1);
2713 } else {
2714 xmlFreeURI(check);
2715 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002716 base = xmlNodeGetBase(node->doc, node);
2717 if (base == NULL) {
2718 URI = xmlBuildURI(schemaLocation, node->doc->URL);
2719 } else {
2720 URI = xmlBuildURI(schemaLocation, base);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002721 xmlFree(base);
Daniel Veillard1d913862003-11-21 00:28:39 +00002722 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002723 if (URI != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002724 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
2725 xmlFree(URI);
Daniel Veillard1d913862003-11-21 00:28:39 +00002726 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002727 }
2728 if (schema->schemasImports == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002729 schema->schemasImports = xmlHashCreate(10);
2730 if (schema->schemasImports == NULL) {
2731 xmlSchemaPErr2(ctxt, node, child,
2732 XML_SCHEMAP_FAILED_BUILD_IMPORT,
2733 "Internal: failed to build import table\n",
2734 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002735 return (-1);
2736 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002737 }
2738 if (namespace == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002739 import = xmlHashLookup(schema->schemasImports,
2740 XML_SCHEMAS_DEFAULT_NAMESPACE);
2741 if (import != NULL)
2742 previous = import->schemaLocation;
2743 else
2744 previous = NULL;
2745
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002746 if (schemaLocation != NULL) {
2747 if (previous != NULL) {
2748 if (!xmlStrEqual(schemaLocation, previous)) {
2749 xmlSchemaPErr2(ctxt, node, child,
2750 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2751 "Redefining import for default namespace with a different URI: %s\n",
2752 schemaLocation, NULL);
2753 }
2754 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002755 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2756 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002757 return (-1);
2758 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002759 xmlHashAddEntry(schema->schemasImports,
2760 XML_SCHEMAS_DEFAULT_NAMESPACE,
Daniel Veillard1d913862003-11-21 00:28:39 +00002761 import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002762 }
2763 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002764 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002765 import = xmlHashLookup(schema->schemasImports, namespace);
2766 if (import != NULL)
2767 previous = import->schemaLocation;
2768 else
2769 previous = NULL;
2770
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002771 if (schemaLocation != NULL) {
2772 if (previous != NULL) {
2773 if (!xmlStrEqual(schemaLocation, previous)) {
2774 xmlSchemaPErr2(ctxt, node, child,
2775 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2776 "Redefining import for namespace %s with a different URI: %s\n",
2777 namespace, schemaLocation);
2778 }
2779 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002780 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2781 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002782 return (-1);
2783 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002784 xmlHashAddEntry(schema->schemasImports,
Daniel Veillard1d913862003-11-21 00:28:39 +00002785 namespace, import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002786 }
2787 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002788 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002789
2790 child = node->children;
2791 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002792 /*
2793 * the annotations here are simply discarded ...
2794 */
2795 child = child->next;
Daniel Veillard5a872412002-05-22 06:40:27 +00002796 }
2797 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002798 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD,
2799 "Import has unexpected content\n", NULL, NULL);
2800 return (-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002801 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002802 return (1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002803}
2804
2805/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002806 * xmlSchemaCleanupDoc:
2807 * @ctxt: a schema validation context
2808 * @node: the root of the document.
2809 *
2810 * removes unwanted nodes in a schemas document tree
2811 */
2812static void
2813xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root)
2814{
2815 xmlNodePtr delete, cur;
2816
2817 if ((ctxt == NULL) || (root == NULL)) return;
2818
2819 /*
2820 * Remove all the blank text nodes
2821 */
2822 delete = NULL;
2823 cur = root;
2824 while (cur != NULL) {
2825 if (delete != NULL) {
2826 xmlUnlinkNode(delete);
2827 xmlFreeNode(delete);
2828 delete = NULL;
2829 }
2830 if (cur->type == XML_TEXT_NODE) {
2831 if (IS_BLANK_NODE(cur)) {
2832 if (xmlNodeGetSpacePreserve(cur) != 1) {
2833 delete = cur;
2834 }
2835 }
2836 } else if ((cur->type != XML_ELEMENT_NODE) &&
2837 (cur->type != XML_CDATA_SECTION_NODE)) {
2838 delete = cur;
2839 goto skip_children;
2840 }
2841
2842 /*
2843 * Skip to next node
2844 */
2845 if (cur->children != NULL) {
2846 if ((cur->children->type != XML_ENTITY_DECL) &&
2847 (cur->children->type != XML_ENTITY_REF_NODE) &&
2848 (cur->children->type != XML_ENTITY_NODE)) {
2849 cur = cur->children;
2850 continue;
2851 }
2852 }
2853 skip_children:
2854 if (cur->next != NULL) {
2855 cur = cur->next;
2856 continue;
2857 }
2858
2859 do {
2860 cur = cur->parent;
2861 if (cur == NULL)
2862 break;
2863 if (cur == root) {
2864 cur = NULL;
2865 break;
2866 }
2867 if (cur->next != NULL) {
2868 cur = cur->next;
2869 break;
2870 }
2871 } while (cur != NULL);
2872 }
2873 if (delete != NULL) {
2874 xmlUnlinkNode(delete);
2875 xmlFreeNode(delete);
2876 delete = NULL;
2877 }
2878}
2879
2880/**
2881 * xmlSchemaParseSchemaTopLevel:
2882 * @ctxt: a schema validation context
2883 * @schema: the schemas
2884 * @nodes: the list of top level nodes
2885 *
2886 * Returns the internal XML Schema structure built from the resource or
2887 * NULL in case of error
2888 */
2889static void
2890xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt,
2891 xmlSchemaPtr schema, xmlNodePtr nodes)
2892{
2893 xmlNodePtr child;
2894 xmlSchemaAnnotPtr annot;
2895
2896 if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL))
2897 return;
2898
2899 child = nodes;
2900 while ((IS_SCHEMA(child, "include")) ||
2901 (IS_SCHEMA(child, "import")) ||
2902 (IS_SCHEMA(child, "redefine")) ||
2903 (IS_SCHEMA(child, "annotation"))) {
2904 if (IS_SCHEMA(child, "annotation")) {
2905 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2906 if (schema->annot == NULL)
2907 schema->annot = annot;
2908 else
2909 xmlSchemaFreeAnnot(annot);
2910 } else if (IS_SCHEMA(child, "import")) {
2911 xmlSchemaParseImport(ctxt, schema, child);
2912 } else if (IS_SCHEMA(child, "include")) {
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002913 ctxt->includes++;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002914 xmlSchemaParseInclude(ctxt, schema, child);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00002915 ctxt->includes--;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002916 } else if (IS_SCHEMA(child, "redefine")) {
2917 TODO
2918 }
2919 child = child->next;
2920 }
2921 while (child != NULL) {
2922 if (IS_SCHEMA(child, "complexType")) {
2923 xmlSchemaParseComplexType(ctxt, schema, child);
2924 child = child->next;
2925 } else if (IS_SCHEMA(child, "simpleType")) {
2926 xmlSchemaParseSimpleType(ctxt, schema, child);
2927 child = child->next;
2928 } else if (IS_SCHEMA(child, "element")) {
2929 xmlSchemaParseElement(ctxt, schema, child, 1);
2930 child = child->next;
2931 } else if (IS_SCHEMA(child, "attribute")) {
2932 xmlSchemaParseAttribute(ctxt, schema, child);
2933 child = child->next;
2934 } else if (IS_SCHEMA(child, "attributeGroup")) {
2935 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2936 child = child->next;
2937 } else if (IS_SCHEMA(child, "group")) {
2938 xmlSchemaParseGroup(ctxt, schema, child);
2939 child = child->next;
2940 } else if (IS_SCHEMA(child, "notation")) {
2941 xmlSchemaParseNotation(ctxt, schema, child);
2942 child = child->next;
2943 } else {
2944 xmlSchemaPErr2(ctxt, NULL, child,
2945 XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD,
2946 "Schemas: unexpected element %s here \n",
2947 child->name, NULL);
2948 child = child->next;
2949 }
2950 while (IS_SCHEMA(child, "annotation")) {
2951 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2952 if (schema->annot == NULL)
2953 schema->annot = annot;
2954 else
2955 xmlSchemaFreeAnnot(annot);
2956 child = child->next;
2957 }
2958 }
2959}
2960
2961/**
2962 * xmlSchemaParseInclude:
2963 * @ctxt: a schema validation context
2964 * @schema: the schema being built
2965 * @node: a subtree containing XML Schema informations
2966 *
2967 * parse a XML schema Include definition
2968 *
2969 * Returns -1 in case of error, 0 if the declaration is inproper and
2970 * 1 in case of success.
2971 */
2972static int
2973xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2974 xmlNodePtr node)
2975{
2976 xmlNodePtr child = NULL;
2977 const xmlChar *schemaLocation;
2978 xmlURIPtr check;
2979 xmlDocPtr doc;
2980 xmlNodePtr root;
2981 xmlSchemaIncludePtr include;
2982
2983
2984 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2985 return (-1);
2986
2987 /*
2988 * Preliminary step, extract the URI-Reference for the include and
2989 * make an URI from the base.
2990 */
2991 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
2992 if (schemaLocation != NULL) {
2993 xmlChar *base = NULL;
2994 xmlChar *URI = NULL;
2995 check = xmlParseURI((const char *) schemaLocation);
2996 if (check == NULL) {
2997 xmlSchemaPErr2(ctxt, node, child,
2998 XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI,
2999 "Include schemaLocation attribute is not an URI: %s\n",
3000 schemaLocation, NULL);
3001 return (-1);
3002 } else {
3003 xmlFreeURI(check);
3004 }
3005 base = xmlNodeGetBase(node->doc, node);
3006 if (base == NULL) {
3007 URI = xmlBuildURI(schemaLocation, node->doc->URL);
3008 } else {
3009 URI = xmlBuildURI(schemaLocation, base);
3010 xmlFree(base);
3011 }
3012 if (URI != NULL) {
3013 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
3014 xmlFree(URI);
3015 }
3016 } else {
3017 xmlSchemaPErr2(ctxt, node, child,
3018 XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI,
3019 "Include schemaLocation attribute missing\n",
3020 NULL, NULL);
3021 return (-1);
3022 }
3023
3024 child = node->children;
3025 while (IS_SCHEMA(child, "annotation")) {
3026 /*
3027 * the annotations here are simply discarded ...
3028 */
3029 child = child->next;
3030 }
3031 if (child != NULL) {
3032 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD,
3033 "Include has unexpected content\n", NULL, NULL);
3034 return (-1);
3035 }
3036
3037 /*
3038 * First step is to parse the input document into an DOM/Infoset
3039 */
3040 doc = xmlReadFile((const char *) schemaLocation, NULL,
3041 SCHEMAS_PARSE_OPTIONS);
3042 if (doc == NULL) {
3043 xmlSchemaPErr(ctxt, NULL,
3044 XML_SCHEMAP_FAILED_LOAD,
3045 "xmlSchemaParse: could not load %s\n",
3046 ctxt->URL, NULL);
3047 return(-1);
3048 }
3049
3050 /*
3051 * Then extract the root of the schema
3052 */
3053 root = xmlDocGetRootElement(doc);
3054 if (root == NULL) {
3055 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3056 XML_SCHEMAP_NOROOT,
3057 "schemas %s has no root", schemaLocation, NULL);
3058 xmlFreeDoc(doc);
3059 return (-1);
3060 }
3061
3062 /*
3063 * Remove all the blank text nodes
3064 */
3065 xmlSchemaCleanupDoc(ctxt, root);
3066
3067 /*
3068 * Check the schemas top level element
3069 */
3070 if (!IS_SCHEMA(root, "schema")) {
3071 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3072 XML_SCHEMAP_NOT_SCHEMA,
3073 "File %s is not a schemas", schemaLocation, NULL);
3074 xmlFreeDoc(doc);
3075 return (-1);
3076 }
3077
3078 /*
3079 * register the include
3080 */
3081 include = (xmlSchemaIncludePtr) xmlMalloc(sizeof(xmlSchemaInclude));
3082 if (include == NULL) {
3083 xmlSchemaPErrMemory(ctxt, "allocating included schema", NULL);
3084 xmlFreeDoc(doc);
3085 return (-1);
3086 }
3087
3088 memset(include, 0, sizeof(xmlSchemaInclude));
3089 include->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
3090 include->doc = doc;
3091 include->next = schema->includes;
3092 schema->includes = include;
3093
3094
3095 /*
3096 * parse the declarations in the included file like if they
3097 * were in the original file.
3098 */
3099 xmlSchemaParseSchemaTopLevel(ctxt, schema, root->children);
3100
3101 return (1);
3102}
3103
3104/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003105 * xmlSchemaParseChoice:
3106 * @ctxt: a schema validation context
3107 * @schema: the schema being built
3108 * @node: a subtree containing XML Schema informations
3109 *
3110 * parse a XML schema Choice definition
3111 * *WARNING* this interface is highly subject to change
3112 *
3113 * Returns -1 in case of error, 0 if the declaration is inproper and
3114 * 1 in case of success.
3115 */
3116static xmlSchemaTypePtr
3117xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003118 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003119{
3120 xmlSchemaTypePtr type, subtype, last = NULL;
3121 xmlNodePtr child = NULL;
3122 xmlChar name[30];
3123
3124 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3125 return (NULL);
3126
3127
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003128 snprintf((char *) name, 30, "choice %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003129 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003130 if (type == NULL)
3131 return (NULL);
3132 type->node = node;
3133 type->type = XML_SCHEMA_TYPE_CHOICE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003134 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003135 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3136 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3137
3138 child = node->children;
3139 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003140 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3141 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003142 }
3143 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003144 (IS_SCHEMA(child, "group")) ||
3145 (IS_SCHEMA(child, "any")) ||
3146 (IS_SCHEMA(child, "choice")) ||
3147 (IS_SCHEMA(child, "sequence"))) {
3148 subtype = NULL;
3149 if (IS_SCHEMA(child, "element")) {
3150 subtype = (xmlSchemaTypePtr)
3151 xmlSchemaParseElement(ctxt, schema, child, 0);
3152 } else if (IS_SCHEMA(child, "group")) {
3153 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3154 } else if (IS_SCHEMA(child, "any")) {
3155 subtype = xmlSchemaParseAny(ctxt, schema, child);
3156 } else if (IS_SCHEMA(child, "sequence")) {
3157 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3158 } else if (IS_SCHEMA(child, "choice")) {
3159 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3160 }
3161 if (subtype != NULL) {
3162 if (last == NULL) {
3163 type->subtypes = subtype;
3164 last = subtype;
3165 } else {
3166 last->next = subtype;
3167 last = subtype;
3168 }
3169 last->next = NULL;
3170 }
3171 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003172 }
3173 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003174 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_CHOICE_CHILD,
3175 "Choice %s has unexpected content\n", type->name,
3176 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003177 }
3178
3179 return (type);
3180}
3181
3182/**
3183 * xmlSchemaParseSequence:
3184 * @ctxt: a schema validation context
3185 * @schema: the schema being built
3186 * @node: a subtree containing XML Schema informations
3187 *
3188 * parse a XML schema Sequence definition
3189 * *WARNING* this interface is highly subject to change
3190 *
3191 * Returns -1 in case of error, 0 if the declaration is inproper and
3192 * 1 in case of success.
3193 */
3194static xmlSchemaTypePtr
3195xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003196 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003197{
3198 xmlSchemaTypePtr type, subtype, last = NULL;
3199 xmlNodePtr child = NULL;
3200 xmlChar name[30];
3201
3202 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3203 return (NULL);
3204
3205
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003206 snprintf((char *) name, 30, "sequence %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003207 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003208 if (type == NULL)
3209 return (NULL);
3210 type->node = node;
3211 type->type = XML_SCHEMA_TYPE_SEQUENCE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003212 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003213 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3214 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3215
3216 child = node->children;
3217 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003218 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3219 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003220 }
3221 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003222 (IS_SCHEMA(child, "group")) ||
3223 (IS_SCHEMA(child, "any")) ||
3224 (IS_SCHEMA(child, "choice")) ||
3225 (IS_SCHEMA(child, "sequence"))) {
3226 subtype = NULL;
3227 if (IS_SCHEMA(child, "element")) {
3228 subtype = (xmlSchemaTypePtr)
3229 xmlSchemaParseElement(ctxt, schema, child, 0);
3230 } else if (IS_SCHEMA(child, "group")) {
3231 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3232 } else if (IS_SCHEMA(child, "any")) {
3233 subtype = xmlSchemaParseAny(ctxt, schema, child);
3234 } else if (IS_SCHEMA(child, "choice")) {
3235 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3236 } else if (IS_SCHEMA(child, "sequence")) {
3237 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3238 }
3239 if (subtype != NULL) {
3240 if (last == NULL) {
3241 type->subtypes = subtype;
3242 last = subtype;
3243 } else {
3244 last->next = subtype;
3245 last = subtype;
3246 }
3247 last->next = NULL;
3248 }
3249 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003250 }
3251 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003252 xmlSchemaPErr2(ctxt, node, child,
3253 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
3254 "Sequence %s has unexpected content\n", type->name,
3255 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003256 }
3257
3258 return (type);
3259}
3260
3261/**
3262 * xmlSchemaParseRestriction:
3263 * @ctxt: a schema validation context
3264 * @schema: the schema being built
3265 * @node: a subtree containing XML Schema informations
3266 * @simple: is that part of a simple type.
3267 *
3268 * parse a XML schema Restriction definition
3269 * *WARNING* this interface is highly subject to change
3270 *
3271 * Returns the type definition or NULL in case of error
3272 */
3273static xmlSchemaTypePtr
3274xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3275 xmlNodePtr node, int simple)
3276{
3277 xmlSchemaTypePtr type, subtype;
3278 xmlSchemaFacetPtr facet, lastfacet = NULL;
3279 xmlNodePtr child = NULL;
3280 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003281 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003282
3283 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3284 return (NULL);
3285
3286 oldcontainer = ctxt->container;
3287
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003288 snprintf((char *) name, 30, "restriction %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003289 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003290 if (type == NULL)
3291 return (NULL);
3292 type->node = node;
3293 type->type = XML_SCHEMA_TYPE_RESTRICTION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003294 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003295 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3296 if ((!simple) && (type->base == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003297 xmlSchemaPErr2(ctxt, node, child,
3298 XML_SCHEMAP_RESTRICTION_NONAME_NOREF,
3299 "Restriction %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003300 }
3301 ctxt->container = name;
3302
3303 child = node->children;
3304 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003305 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3306 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003307 }
3308 subtype = NULL;
3309
3310 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003311 subtype = (xmlSchemaTypePtr)
3312 xmlSchemaParseAll(ctxt, schema, child);
3313 child = child->next;
3314 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003315 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003316 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3317 child = child->next;
3318 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003319 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003320 subtype = (xmlSchemaTypePtr)
3321 xmlSchemaParseSequence(ctxt, schema, child);
3322 child = child->next;
3323 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003324 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003325 subtype = (xmlSchemaTypePtr)
3326 xmlSchemaParseGroup(ctxt, schema, child);
3327 child = child->next;
3328 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003329 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003330 if (IS_SCHEMA(child, "simpleType")) {
3331 subtype = (xmlSchemaTypePtr)
3332 xmlSchemaParseSimpleType(ctxt, schema, child);
3333 child = child->next;
3334 type->baseType = subtype;
3335 }
3336 /*
3337 * Facets
3338 */
Daniel Veillard4255d502002-04-16 15:50:10 +00003339 while ((IS_SCHEMA(child, "minInclusive")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003340 (IS_SCHEMA(child, "minExclusive")) ||
3341 (IS_SCHEMA(child, "maxInclusive")) ||
3342 (IS_SCHEMA(child, "maxExclusive")) ||
3343 (IS_SCHEMA(child, "totalDigits")) ||
3344 (IS_SCHEMA(child, "fractionDigits")) ||
3345 (IS_SCHEMA(child, "pattern")) ||
3346 (IS_SCHEMA(child, "enumeration")) ||
3347 (IS_SCHEMA(child, "whiteSpace")) ||
3348 (IS_SCHEMA(child, "length")) ||
3349 (IS_SCHEMA(child, "maxLength")) ||
3350 (IS_SCHEMA(child, "minLength"))) {
3351 facet = xmlSchemaParseFacet(ctxt, schema, child);
3352 if (facet != NULL) {
3353 if (lastfacet == NULL) {
3354 type->facets = facet;
3355 lastfacet = facet;
3356 } else {
3357 lastfacet->next = facet;
3358 lastfacet = facet;
3359 }
3360 lastfacet->next = NULL;
3361 }
3362 child = child->next;
3363 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003364 }
3365 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3366 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003367 xmlSchemaPErr2(ctxt, node, child,
3368 XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD,
3369 "Restriction %s has unexpected content\n",
3370 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003371 }
3372 ctxt->container = oldcontainer;
3373 return (type);
3374}
3375
3376/**
3377 * xmlSchemaParseExtension:
3378 * @ctxt: a schema validation context
3379 * @schema: the schema being built
3380 * @node: a subtree containing XML Schema informations
3381 *
3382 * parse a XML schema Extension definition
3383 * *WARNING* this interface is highly subject to change
3384 *
3385 * Returns the type definition or NULL in case of error
3386 */
3387static xmlSchemaTypePtr
3388xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003389 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003390{
3391 xmlSchemaTypePtr type, subtype;
3392 xmlNodePtr child = NULL;
3393 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003394 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003395
3396 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3397 return (NULL);
3398
3399 oldcontainer = ctxt->container;
3400
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003401 snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003402 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003403 if (type == NULL)
3404 return (NULL);
3405 type->node = node;
3406 type->type = XML_SCHEMA_TYPE_EXTENSION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003407 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003408 ctxt->container = name;
3409
3410 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3411 if (type->base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003412 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_EXTENSION_NO_BASE,
3413 "Extension %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003414 }
3415 child = node->children;
3416 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003417 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3418 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003419 }
3420 subtype = NULL;
3421
3422 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003423 subtype = xmlSchemaParseAll(ctxt, schema, child);
3424 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003425 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003426 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3427 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003428 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003429 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3430 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003431 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003432 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3433 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003434 }
3435 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003436 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003437 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3438 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003439 xmlSchemaPErr2(ctxt, node, child,
3440 XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD,
3441 "Extension %s has unexpected content\n", type->name,
3442 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003443 }
3444 ctxt->container = oldcontainer;
3445 return (type);
3446}
3447
3448/**
3449 * xmlSchemaParseSimpleContent:
3450 * @ctxt: a schema validation context
3451 * @schema: the schema being built
3452 * @node: a subtree containing XML Schema informations
3453 *
3454 * parse a XML schema SimpleContent definition
3455 * *WARNING* this interface is highly subject to change
3456 *
3457 * Returns the type definition or NULL in case of error
3458 */
3459static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003460xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt,
3461 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003462{
3463 xmlSchemaTypePtr type, subtype;
3464 xmlNodePtr child = NULL;
3465 xmlChar name[30];
3466
3467 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3468 return (NULL);
3469
3470
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003471 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003472 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003473 if (type == NULL)
3474 return (NULL);
3475 type->node = node;
3476 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003477 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003478
3479 child = node->children;
3480 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003481 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3482 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003483 }
3484 subtype = NULL;
3485 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003486 subtype = (xmlSchemaTypePtr)
3487 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3488 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003489 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003490 subtype = (xmlSchemaTypePtr)
3491 xmlSchemaParseExtension(ctxt, schema, child);
3492 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003493 }
3494 type->subtypes = subtype;
3495 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003496 xmlSchemaPErr2(ctxt, node, child,
3497 XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD,
3498 "SimpleContent %s has unexpected content\n",
3499 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003500 }
3501 return (type);
3502}
3503
3504/**
3505 * xmlSchemaParseComplexContent:
3506 * @ctxt: a schema validation context
3507 * @schema: the schema being built
3508 * @node: a subtree containing XML Schema informations
3509 *
3510 * parse a XML schema ComplexContent definition
3511 * *WARNING* this interface is highly subject to change
3512 *
3513 * Returns the type definition or NULL in case of error
3514 */
3515static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003516xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt,
3517 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003518{
3519 xmlSchemaTypePtr type, subtype;
3520 xmlNodePtr child = NULL;
3521 xmlChar name[30];
3522
3523 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3524 return (NULL);
3525
3526
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003527 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003528 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003529 if (type == NULL)
3530 return (NULL);
3531 type->node = node;
3532 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003533 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003534
3535 child = node->children;
3536 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003537 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3538 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003539 }
3540 subtype = NULL;
3541 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003542 subtype = (xmlSchemaTypePtr)
3543 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3544 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003545 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003546 subtype = (xmlSchemaTypePtr)
3547 xmlSchemaParseExtension(ctxt, schema, child);
3548 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003549 }
3550 type->subtypes = subtype;
3551 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003552 xmlSchemaPErr2(ctxt, node, child,
3553 XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD,
3554 "ComplexContent %s has unexpected content\n",
3555 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003556 }
3557 return (type);
3558}
3559
3560/**
3561 * xmlSchemaParseComplexType:
3562 * @ctxt: a schema validation context
3563 * @schema: the schema being built
3564 * @node: a subtree containing XML Schema informations
3565 *
3566 * parse a XML schema Complex Type definition
3567 * *WARNING* this interface is highly subject to change
3568 *
3569 * Returns the type definition or NULL in case of error
3570 */
3571static xmlSchemaTypePtr
3572xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3573 xmlNodePtr node)
3574{
3575 xmlSchemaTypePtr type, subtype;
3576 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003577 const xmlChar *name;
3578 const xmlChar *oldcontainer;
Daniel Veillard1aefc862004-03-04 11:40:48 +00003579 const xmlChar *mixed;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003580 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00003581
3582 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3583 return (NULL);
3584
3585 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003586 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00003587 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003588
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003589 snprintf(buf, 99, "anontype %d", ctxt->counter++ + 1);
3590 name = (const xmlChar *)buf;
3591 type = xmlSchemaAddType(ctxt, schema, name, NULL);
3592 } else {
3593 const xmlChar *local, *ns;
3594
3595 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
3596 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00003597 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003598 if (type == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003599 return (NULL);
3600 }
Daniel Veillard1aefc862004-03-04 11:40:48 +00003601
3602 mixed = xmlSchemaGetProp(ctxt, node, "mixed");
3603 if (mixed != NULL)
3604 type->flags |= XML_SCHEMAS_TYPE_MIXED;
3605
Daniel Veillard4255d502002-04-16 15:50:10 +00003606 type->node = node;
3607 type->type = XML_SCHEMA_TYPE_COMPLEX;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003608 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003609 ctxt->container = name;
3610
3611 child = node->children;
3612 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003613 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3614 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003615 }
3616 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003617 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
3618 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003619 } else if (IS_SCHEMA(child, "complexContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003620 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
3621 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003622 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003623 subtype = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003624
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003625 if (IS_SCHEMA(child, "all")) {
3626 subtype = xmlSchemaParseAll(ctxt, schema, child);
3627 child = child->next;
3628 } else if (IS_SCHEMA(child, "choice")) {
3629 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3630 child = child->next;
3631 } else if (IS_SCHEMA(child, "sequence")) {
3632 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3633 child = child->next;
3634 } else if (IS_SCHEMA(child, "group")) {
3635 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3636 child = child->next;
3637 }
3638 if (subtype != NULL)
3639 type->subtypes = subtype;
3640 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
Daniel Veillard4255d502002-04-16 15:50:10 +00003641 }
3642 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003643 xmlSchemaPErr2(ctxt, node, child,
3644 XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD,
3645 "ComplexType %s has unexpected content\n",
3646 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003647 }
3648 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003649 return (type);
3650}
3651
Daniel Veillard4255d502002-04-16 15:50:10 +00003652/**
3653 * xmlSchemaParseSchema:
3654 * @ctxt: a schema validation context
3655 * @node: a subtree containing XML Schema informations
3656 *
3657 * parse a XML schema definition from a node set
3658 * *WARNING* this interface is highly subject to change
3659 *
3660 * Returns the internal XML Schema structure built from the resource or
3661 * NULL in case of error
3662 */
3663static xmlSchemaPtr
3664xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3665{
3666 xmlSchemaPtr schema = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003667 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003668 const xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003669 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003670
3671 if ((ctxt == NULL) || (node == NULL))
3672 return (NULL);
3673
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003674 nberrors = ctxt->nberrors;
3675 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003676 if (IS_SCHEMA(node, "schema")) {
3677 schema = xmlSchemaNewSchema(ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003678 if (schema == NULL)
3679 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003680 val = xmlSchemaGetProp(ctxt, node, "targetNamespace");
3681 if (val != NULL) {
3682 schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1);
3683 } else {
3684 schema->targetNamespace = NULL;
3685 }
3686 schema->id = xmlSchemaGetProp(ctxt, node, "id");
3687 schema->version = xmlSchemaGetProp(ctxt, node, "version");
3688 val = xmlSchemaGetProp(ctxt, node, "elementFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003689 if (val != NULL) {
3690 if (xmlStrEqual(val, BAD_CAST "qualified"))
3691 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3692 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3693 xmlSchemaPErr2(ctxt, node, child,
3694 XML_SCHEMAP_ELEMFORMDEFAULT_VALUE,
3695 "Invalid value %s for elementFormDefault\n",
3696 val, NULL);
3697 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003698 } else {
3699 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3700 }
3701 val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003702 if (val != NULL) {
3703 if (xmlStrEqual(val, BAD_CAST "qualified"))
3704 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3705 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3706 xmlSchemaPErr2(ctxt, node, child,
3707 XML_SCHEMAP_ATTRFORMDEFAULT_VALUE,
3708 "Invalid value %s for attributeFormDefault\n",
3709 val, NULL);
3710 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003711 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003712
Daniel Veillardbd2904b2003-11-25 15:38:59 +00003713 xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children);
3714 } else {
3715 xmlDocPtr doc;
3716
3717 doc = node->doc;
3718
3719 if ((doc != NULL) && (doc->URL != NULL)) {
3720 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3721 XML_SCHEMAP_NOT_SCHEMA,
3722 "File %s is not a schemas", doc->URL, NULL);
3723 } else {
3724 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3725 XML_SCHEMAP_NOT_SCHEMA,
3726 "File is not a schemas", NULL, NULL);
3727 }
3728 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003729 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003730 if (ctxt->nberrors != 0) {
3731 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003732 xmlSchemaFree(schema);
3733 schema = NULL;
3734 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003735 }
3736 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003737#ifdef DEBUG
3738 if (schema == NULL)
3739 xmlGenericError(xmlGenericErrorContext,
3740 "xmlSchemaParse() failed\n");
3741#endif
3742
3743 return (schema);
3744}
3745
3746/************************************************************************
3747 * *
3748 * Validating using Schemas *
3749 * *
3750 ************************************************************************/
3751
3752/************************************************************************
3753 * *
3754 * Reading/Writing Schemas *
3755 * *
3756 ************************************************************************/
3757
3758/**
3759 * xmlSchemaNewParserCtxt:
3760 * @URL: the location of the schema
3761 *
3762 * Create an XML Schemas parse context for that file/resource expected
3763 * to contain an XML Schemas file.
3764 *
3765 * Returns the parser context or NULL in case of error
3766 */
3767xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003768xmlSchemaNewParserCtxt(const char *URL)
3769{
Daniel Veillard4255d502002-04-16 15:50:10 +00003770 xmlSchemaParserCtxtPtr ret;
3771
3772 if (URL == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003773 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003774
3775 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3776 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003777 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3778 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003779 return (NULL);
3780 }
3781 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003782 ret->dict = xmlDictCreate();
3783 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
Daniel Veillardb0f397e2003-12-23 23:30:53 +00003784 ret->includes = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003785 return (ret);
3786}
3787
3788/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003789 * xmlSchemaNewMemParserCtxt:
3790 * @buffer: a pointer to a char array containing the schemas
3791 * @size: the size of the array
3792 *
3793 * Create an XML Schemas parse context for that memory buffer expected
3794 * to contain an XML Schemas file.
3795 *
3796 * Returns the parser context or NULL in case of error
3797 */
3798xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003799xmlSchemaNewMemParserCtxt(const char *buffer, int size)
3800{
Daniel Veillard6045c902002-10-09 21:13:59 +00003801 xmlSchemaParserCtxtPtr ret;
3802
3803 if ((buffer == NULL) || (size <= 0))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003804 return (NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003805
3806 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3807 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003808 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3809 NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003810 return (NULL);
3811 }
3812 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3813 ret->buffer = buffer;
3814 ret->size = size;
William M. Brackcf9eadf2003-12-25 13:24:05 +00003815 ret->dict = xmlDictCreate();
Daniel Veillard6045c902002-10-09 21:13:59 +00003816 return (ret);
3817}
3818
3819/**
Daniel Veillard9d751502003-10-29 13:21:47 +00003820 * xmlSchemaNewDocParserCtxt:
3821 * @doc: a preparsed document tree
3822 *
3823 * Create an XML Schemas parse context for that document.
3824 * NB. The document may be modified during the parsing process.
3825 *
3826 * Returns the parser context or NULL in case of error
3827 */
3828xmlSchemaParserCtxtPtr
3829xmlSchemaNewDocParserCtxt(xmlDocPtr doc)
3830{
3831 xmlSchemaParserCtxtPtr ret;
3832
3833 if (doc == NULL)
3834 return (NULL);
3835
3836 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3837 if (ret == NULL) {
3838 xmlSchemaPErrMemory(NULL, "allocating schema parser context",
3839 NULL);
3840 return (NULL);
3841 }
3842 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3843 ret->doc = doc;
William M. Brackcf9eadf2003-12-25 13:24:05 +00003844 ret->dict = xmlDictCreate();
Daniel Veillarddda22c12004-01-24 08:31:30 +00003845 /* The application has responsibility for the document */
3846 ret->preserve = 1;
Daniel Veillard9d751502003-10-29 13:21:47 +00003847
3848 return (ret);
3849}
3850
3851/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003852 * xmlSchemaFreeParserCtxt:
3853 * @ctxt: the schema parser context
3854 *
3855 * Free the resources associated to the schema parser context
3856 */
3857void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003858xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt)
3859{
Daniel Veillard4255d502002-04-16 15:50:10 +00003860 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003861 return;
Daniel Veillarddda22c12004-01-24 08:31:30 +00003862 if (ctxt->doc != NULL && !ctxt->preserve)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003863 xmlFreeDoc(ctxt->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003864 xmlDictFree(ctxt->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +00003865 xmlFree(ctxt);
3866}
3867
3868/************************************************************************
3869 * *
3870 * Building the content models *
3871 * *
3872 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003873
Daniel Veillard4255d502002-04-16 15:50:10 +00003874/**
3875 * xmlSchemaBuildAContentModel:
3876 * @type: the schema type definition
3877 * @ctxt: the schema parser context
3878 * @name: the element name whose content is being built
3879 *
3880 * Generate the automata sequence needed for that type
3881 */
3882static void
3883xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003884 xmlSchemaParserCtxtPtr ctxt,
3885 const xmlChar * name)
3886{
Daniel Veillard4255d502002-04-16 15:50:10 +00003887 if (type == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003888 xmlGenericError(xmlGenericErrorContext,
3889 "Found unexpected type = NULL in %s content model\n",
3890 name);
3891 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003892 }
3893 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003894 case XML_SCHEMA_TYPE_ANY:
3895 /* TODO : handle the namespace too */
3896 /* TODO : make that a specific transition type */
3897 TODO ctxt->state =
3898 xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL,
3899 BAD_CAST "*", NULL);
3900 break;
3901 case XML_SCHEMA_TYPE_ELEMENT:{
3902 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard32370232002-10-16 14:08:14 +00003903
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003904 /* TODO : handle the namespace too */
3905 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003906
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003907 if (elem->maxOccurs >= UNBOUNDED) {
3908 if (elem->minOccurs > 1) {
3909 xmlAutomataStatePtr tmp;
3910 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003911
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003912 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3913 oldstate,
3914 NULL);
3915 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003916
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003917 counter = xmlAutomataNewCounter(ctxt->am,
3918 elem->minOccurs -
3919 1, UNBOUNDED);
Daniel Veillard32370232002-10-16 14:08:14 +00003920
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003921 if (elem->refDecl != NULL) {
3922 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3923 elem->refDecl,
3924 ctxt,
3925 elem->refDecl->
3926 name);
3927 } else {
3928 ctxt->state =
3929 xmlAutomataNewTransition(ctxt->am,
3930 ctxt->state, NULL,
3931 elem->name, type);
3932 }
3933 tmp = ctxt->state;
3934 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3935 counter);
3936 ctxt->state =
3937 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
3938 counter);
Daniel Veillard32370232002-10-16 14:08:14 +00003939
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003940 } else {
3941 if (elem->refDecl != NULL) {
3942 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3943 elem->refDecl,
3944 ctxt,
3945 elem->refDecl->
3946 name);
3947 } else {
3948 ctxt->state =
3949 xmlAutomataNewTransition(ctxt->am,
3950 ctxt->state, NULL,
3951 elem->name, type);
3952 }
3953 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3954 oldstate);
3955 if (elem->minOccurs == 0) {
3956 /* basically an elem* */
3957 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3958 ctxt->state);
3959 }
3960 }
3961 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3962 xmlAutomataStatePtr tmp;
3963 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003964
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003965 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3966 oldstate, NULL);
3967 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003968
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003969 counter = xmlAutomataNewCounter(ctxt->am,
3970 elem->minOccurs - 1,
3971 elem->maxOccurs - 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003972
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003973 if (elem->refDecl != NULL) {
3974 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3975 elem->refDecl, ctxt,
3976 elem->refDecl->name);
3977 } else {
3978 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3979 ctxt->state,
3980 NULL,
3981 elem->name,
3982 type);
3983 }
3984 tmp = ctxt->state;
3985 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3986 counter);
3987 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3988 NULL,
3989 counter);
3990 if (elem->minOccurs == 0) {
3991 /* basically an elem? */
3992 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3993 ctxt->state);
3994 }
Daniel Veillardb39bc392002-10-26 19:29:51 +00003995
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003996 } else {
3997 if (elem->refDecl != NULL) {
3998 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3999 elem->refDecl, ctxt,
4000 elem->refDecl->name);
4001 } else {
4002 ctxt->state = xmlAutomataNewTransition(ctxt->am,
4003 ctxt->state,
4004 NULL,
4005 elem->name,
4006 type);
4007 }
4008 if (elem->minOccurs == 0) {
4009 /* basically an elem? */
4010 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4011 ctxt->state);
4012 }
4013 }
4014 break;
4015 }
4016 case XML_SCHEMA_TYPE_SEQUENCE:{
4017 xmlSchemaTypePtr subtypes;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004018
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004019 /*
4020 * If max and min occurances are default (1) then
4021 * simply iterate over the subtypes
4022 */
4023 if ((type->minOccurs == 1) && (type->maxOccurs == 1)) {
4024 subtypes = type->subtypes;
4025 while (subtypes != NULL) {
4026 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4027 subtypes = subtypes->next;
4028 }
4029 } else {
4030 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004031
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004032 if (type->maxOccurs >= UNBOUNDED) {
4033 if (type->minOccurs > 1) {
4034 xmlAutomataStatePtr tmp;
4035 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004036
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004037 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4038 oldstate,
4039 NULL);
4040 oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004041
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004042 counter = xmlAutomataNewCounter(ctxt->am,
4043 type->
4044 minOccurs - 1,
4045 UNBOUNDED);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004046
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004047 subtypes = type->subtypes;
4048 while (subtypes != NULL) {
4049 xmlSchemaBuildAContentModel(subtypes, ctxt,
4050 name);
4051 subtypes = subtypes->next;
4052 }
4053 tmp = ctxt->state;
4054 xmlAutomataNewCountedTrans(ctxt->am, tmp,
4055 oldstate, counter);
4056 ctxt->state =
4057 xmlAutomataNewCounterTrans(ctxt->am, tmp,
4058 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004059
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004060 } else {
4061 subtypes = type->subtypes;
4062 while (subtypes != NULL) {
4063 xmlSchemaBuildAContentModel(subtypes, ctxt,
4064 name);
4065 subtypes = subtypes->next;
4066 }
4067 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
4068 oldstate);
4069 if (type->minOccurs == 0) {
4070 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4071 ctxt->state);
4072 }
4073 }
4074 } else if ((type->maxOccurs > 1)
4075 || (type->minOccurs > 1)) {
4076 xmlAutomataStatePtr tmp;
4077 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004078
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004079 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4080 oldstate,
4081 NULL);
4082 oldstate = ctxt->state;
Daniel Veillard4255d502002-04-16 15:50:10 +00004083
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004084 counter = xmlAutomataNewCounter(ctxt->am,
4085 type->minOccurs -
4086 1,
4087 type->maxOccurs -
4088 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004089
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004090 subtypes = type->subtypes;
4091 while (subtypes != NULL) {
4092 xmlSchemaBuildAContentModel(subtypes, ctxt,
4093 name);
4094 subtypes = subtypes->next;
4095 }
4096 tmp = ctxt->state;
4097 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
4098 counter);
4099 ctxt->state =
4100 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
4101 counter);
4102 if (type->minOccurs == 0) {
4103 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4104 ctxt->state);
4105 }
Daniel Veillardb509f152002-04-17 16:28:10 +00004106
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004107 } else {
4108 subtypes = type->subtypes;
4109 while (subtypes != NULL) {
4110 xmlSchemaBuildAContentModel(subtypes, ctxt,
4111 name);
4112 subtypes = subtypes->next;
4113 }
4114 if (type->minOccurs == 0) {
4115 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4116 ctxt->state);
4117 }
4118 }
4119 }
4120 break;
4121 }
4122 case XML_SCHEMA_TYPE_CHOICE:{
4123 xmlSchemaTypePtr subtypes;
4124 xmlAutomataStatePtr start, end;
Daniel Veillardb509f152002-04-17 16:28:10 +00004125
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004126 start = ctxt->state;
4127 end = xmlAutomataNewState(ctxt->am);
Daniel Veillard7646b182002-04-20 06:41:40 +00004128
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004129 /*
4130 * iterate over the subtypes and remerge the end with an
4131 * epsilon transition
4132 */
4133 if (type->maxOccurs == 1) {
4134 subtypes = type->subtypes;
4135 while (subtypes != NULL) {
4136 ctxt->state = start;
4137 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4138 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
4139 subtypes = subtypes->next;
4140 }
4141 } else {
4142 int counter;
4143 xmlAutomataStatePtr hop;
4144 int maxOccurs = type->maxOccurs == UNBOUNDED ?
4145 UNBOUNDED : type->maxOccurs - 1;
4146 int minOccurs =
4147 type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillard7646b182002-04-20 06:41:40 +00004148
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004149 /*
4150 * use a counter to keep track of the number of transtions
4151 * which went through the choice.
4152 */
4153 counter =
4154 xmlAutomataNewCounter(ctxt->am, minOccurs,
4155 maxOccurs);
4156 hop = xmlAutomataNewState(ctxt->am);
Daniel Veillard6231e842002-04-18 11:54:04 +00004157
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004158 subtypes = type->subtypes;
4159 while (subtypes != NULL) {
4160 ctxt->state = start;
4161 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4162 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
4163 subtypes = subtypes->next;
4164 }
4165 xmlAutomataNewCountedTrans(ctxt->am, hop, start,
4166 counter);
4167 xmlAutomataNewCounterTrans(ctxt->am, hop, end,
4168 counter);
4169 }
4170 if (type->minOccurs == 0) {
4171 xmlAutomataNewEpsilon(ctxt->am, start, end);
4172 }
4173 ctxt->state = end;
4174 break;
4175 }
4176 case XML_SCHEMA_TYPE_ALL:{
4177 xmlAutomataStatePtr start;
4178 xmlSchemaTypePtr subtypes;
4179 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
4180 int lax;
4181
4182 subtypes = type->subtypes;
4183 if (subtypes == NULL)
4184 break;
4185 start = ctxt->state;
4186 while (subtypes != NULL) {
4187 ctxt->state = start;
4188 elem = (xmlSchemaElementPtr) subtypes;
4189
4190 /* TODO : handle the namespace too */
4191 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
4192 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state,
4193 ctxt->state, elem->name, 1,
4194 1, subtypes);
4195 } else {
4196 xmlAutomataNewCountTrans(ctxt->am, ctxt->state,
4197 ctxt->state, elem->name,
4198 elem->minOccurs,
4199 elem->maxOccurs,
4200 subtypes);
4201 }
4202 subtypes = subtypes->next;
4203 }
4204 lax = type->minOccurs == 0;
4205 ctxt->state =
4206 xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
4207 lax);
4208 break;
4209 }
4210 case XML_SCHEMA_TYPE_RESTRICTION:
4211 if (type->subtypes != NULL)
4212 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4213 break;
4214 case XML_SCHEMA_TYPE_EXTENSION:
4215 if (type->baseType != NULL) {
4216 xmlSchemaTypePtr subtypes;
4217
4218 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
4219 subtypes = type->subtypes;
4220 while (subtypes != NULL) {
4221 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4222 subtypes = subtypes->next;
4223 }
4224 } else if (type->subtypes != NULL)
4225 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4226 break;
4227 case XML_SCHEMA_TYPE_GROUP:
4228 if (type->subtypes == NULL) {
4229 }
4230 case XML_SCHEMA_TYPE_COMPLEX:
4231 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4232 if (type->subtypes != NULL)
4233 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4234 break;
4235 default:
4236 xmlGenericError(xmlGenericErrorContext,
4237 "Found unexpected type %d in %s content model\n",
4238 type->type, name);
4239 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004240 }
4241}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004242
Daniel Veillard4255d502002-04-16 15:50:10 +00004243/**
4244 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004245 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00004246 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004247 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00004248 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004249 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00004250 */
4251static void
4252xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004253 xmlSchemaParserCtxtPtr ctxt,
4254 const xmlChar * name)
4255{
Daniel Veillard4255d502002-04-16 15:50:10 +00004256 xmlAutomataStatePtr start;
4257
Daniel Veillard4255d502002-04-16 15:50:10 +00004258 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004259 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004260 if (elem->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004261 elem->contentType = XML_SCHEMA_CONTENT_ANY;
4262 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004263 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004264 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004265 return;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004266 if ((elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC) ||
4267 (elem->subtypes->contentType == XML_SCHEMA_CONTENT_SIMPLE))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004268 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004269
4270#ifdef DEBUG_CONTENT
4271 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004272 "Building content model for %s\n", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004273#endif
4274
Daniel Veillard4255d502002-04-16 15:50:10 +00004275 ctxt->am = xmlNewAutomata();
4276 if (ctxt->am == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004277 xmlGenericError(xmlGenericErrorContext,
4278 "Cannot create automata for elem %s\n", name);
4279 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004280 }
4281 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
4282 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
4283 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00004284 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004285 if (elem->contModel == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004286 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_INTERNAL,
4287 "failed to compile %s content model\n", name, NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004288 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004289 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_NOTDETERMINIST,
4290 "Content model of %s is not determinist:\n", name,
4291 NULL);
Daniel Veillarde19fc232002-04-22 16:01:24 +00004292 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00004293#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004294 xmlGenericError(xmlGenericErrorContext,
4295 "Content model of %s:\n", name);
4296 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00004297#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00004298 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004299 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00004300 xmlFreeAutomata(ctxt->am);
4301 ctxt->am = NULL;
4302}
4303
4304/**
4305 * xmlSchemaRefFixupCallback:
4306 * @elem: the schema element context
4307 * @ctxt: the schema parser context
4308 *
4309 * Free the resources associated to the schema parser context
4310 */
4311static void
4312xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004313 xmlSchemaParserCtxtPtr ctxt,
4314 const xmlChar * name,
4315 const xmlChar * context ATTRIBUTE_UNUSED,
4316 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00004317{
4318 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004319 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004320 if (elem->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004321 xmlSchemaElementPtr elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004322
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004323 if (elem->subtypes != NULL) {
4324 xmlSchemaPErr(ctxt, elem->node,
4325 XML_SCHEMAP_INVALID_REF_AND_SUBTYPE,
4326 "Schemas: element %s have both ref and subtype\n",
4327 name, NULL);
4328 return;
4329 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004330 elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00004331
4332 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004333 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF,
4334 "Schemas: element %s ref to %s not found\n",
4335 name, elem->ref);
4336 return;
4337 }
4338 elem->refDecl = elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004339 } else if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004340 xmlSchemaTypePtr typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004341
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004342 if (elem->subtypes != NULL) {
4343 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE,
4344 "Schemas: element %s have both type and subtype\n",
4345 name, NULL);
4346 return;
4347 }
4348 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
4349 elem->namedTypeNs);
Daniel Veillard4255d502002-04-16 15:50:10 +00004350
4351 if (typeDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004352 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE,
4353 "Schemas: element %s type %s not found\n", name,
4354 elem->namedType);
4355 return;
4356 }
4357 elem->subtypes = typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004358 }
4359}
4360
Daniel Veillard377e1a92004-04-16 16:30:05 +00004361static void
4362xmlSchemaParseUnionRefCheck(xmlSchemaTypePtr typeDecl,
4363 xmlSchemaParserCtxtPtr ctxt)
4364{
4365 const xmlChar *cur, *end, *prefix, *ncName, *namespace;
4366 xmlChar *tmp;
4367 xmlSchemaTypePtr subtype;
4368 xmlNsPtr ns;
4369 int len;
4370
4371 if ((typeDecl->type != XML_SCHEMA_TYPE_UNION) || (typeDecl->ref == NULL))
4372 return;
4373
4374 cur = typeDecl->ref;
4375 do {
4376 while (IS_BLANK_CH(*cur))
4377 cur++;
4378 end = cur;
4379 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
4380 end++;
4381 if (end == cur)
4382 break;
4383 tmp = xmlStrndup(cur, end - cur);
4384 ncName = xmlSplitQName3(tmp, &len);
4385 if (ncName != NULL) {
4386 prefix = xmlDictLookup(ctxt->dict, tmp, len);
4387 } else {
4388 prefix = NULL;
4389 ncName = tmp;
4390 }
4391 ns = xmlSearchNs(typeDecl->node->doc, typeDecl->node, prefix);
4392 if (ns == NULL) {
4393 xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_PREFIX_UNDEFINED,
4394 "Union %s: the namespace of member type %s is undefined\n",
4395 typeDecl->name, (const char *) tmp);
4396 } else {
4397 namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
4398 }
4399 /* Lookup the referenced type */
4400 subtype = xmlSchemaGetType(ctxt->schema, ncName, namespace);
4401 if (subtype == NULL) {
4402 xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE,
4403 "Union %s references an unknown member type >%s<\n",
4404 typeDecl->name, (const char *) tmp);
4405 }
4406 xmlFree(tmp);
4407 cur = end;
4408 } while (*cur != 0);
4409
4410}
4411
Daniel Veillard4255d502002-04-16 15:50:10 +00004412/**
4413 * xmlSchemaTypeFixup:
4414 * @typeDecl: the schema type definition
4415 * @ctxt: the schema parser context
4416 *
4417 * Fixes the content model of the type.
4418 */
4419static void
4420xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004421 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004422{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004423 if (typeDecl == NULL)
4424 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004425 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004426 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004427 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004428 switch (typeDecl->type) {
4429 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{
4430 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
4431 if (typeDecl->subtypes != NULL)
4432 typeDecl->contentType =
4433 typeDecl->subtypes->contentType;
4434 break;
4435 }
4436 case XML_SCHEMA_TYPE_RESTRICTION:{
4437 if (typeDecl->subtypes != NULL)
4438 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004439
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004440 if (typeDecl->base != NULL) {
4441 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004442
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004443 baseType =
4444 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4445 typeDecl->baseNs);
4446 if (baseType == NULL) {
4447 xmlSchemaPErr(ctxt, typeDecl->node,
4448 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004449 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004450 name, typeDecl->base);
4451 }
4452 typeDecl->baseType = baseType;
4453 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004454 if (typeDecl->subtypes == NULL)
4455 if (typeDecl->baseType != NULL)
4456 typeDecl->contentType =
4457 typeDecl->baseType->contentType;
4458 else
4459 /* 1.1.1 */
4460 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004461 else if ((typeDecl->subtypes->subtypes == NULL) &&
4462 ((typeDecl->subtypes->type ==
4463 XML_SCHEMA_TYPE_ALL)
4464 || (typeDecl->subtypes->type ==
4465 XML_SCHEMA_TYPE_SEQUENCE)))
4466 /* 1.1.2 */
4467 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4468 else if ((typeDecl->subtypes->type ==
4469 XML_SCHEMA_TYPE_CHOICE)
4470 && (typeDecl->subtypes->subtypes == NULL))
4471 /* 1.1.3 */
4472 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4473 else {
4474 /* 1.2 and 2.X are applied at the other layer */
4475 typeDecl->contentType =
4476 XML_SCHEMA_CONTENT_ELEMENTS;
4477 }
4478 break;
4479 }
4480 case XML_SCHEMA_TYPE_EXTENSION:{
4481 xmlSchemaContentType explicitContentType;
4482 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00004483
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004484 if (typeDecl->base != NULL) {
4485 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004486
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004487 baseType =
4488 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4489 typeDecl->baseNs);
4490 if (baseType == NULL) {
4491 xmlSchemaPErr(ctxt, typeDecl->node,
4492 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004493 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004494 name, typeDecl->base);
4495 }
4496 typeDecl->baseType = baseType;
4497 }
4498 if (typeDecl->subtypes != NULL)
4499 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004500
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004501 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
4502 if (typeDecl->subtypes == NULL)
4503 /* 1.1.1 */
4504 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4505 else if ((typeDecl->subtypes->subtypes == NULL) &&
4506 ((typeDecl->subtypes->type ==
4507 XML_SCHEMA_TYPE_ALL)
4508 || (typeDecl->subtypes->type ==
4509 XML_SCHEMA_TYPE_SEQUENCE)))
4510 /* 1.1.2 */
4511 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4512 else if ((typeDecl->subtypes->type ==
4513 XML_SCHEMA_TYPE_CHOICE)
4514 && (typeDecl->subtypes->subtypes == NULL))
4515 /* 1.1.3 */
4516 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard4255d502002-04-16 15:50:10 +00004517
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004518 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
4519 typeDecl->baseNs);
4520 if (base == NULL) {
4521 xmlSchemaPErr(ctxt, typeDecl->node,
4522 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
4523 "Schemas: base type %s of type %s not found\n",
4524 typeDecl->base, name);
4525 return;
4526 }
4527 xmlSchemaTypeFixup(base, ctxt, NULL);
4528 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
4529 /* 2.1 */
4530 typeDecl->contentType = base->contentType;
4531 } else if (base->contentType ==
4532 XML_SCHEMA_CONTENT_EMPTY) {
4533 /* 2.2 imbitable ! */
4534 typeDecl->contentType =
4535 XML_SCHEMA_CONTENT_ELEMENTS;
4536 } else {
4537 /* 2.3 imbitable pareil ! */
4538 typeDecl->contentType =
4539 XML_SCHEMA_CONTENT_ELEMENTS;
4540 }
4541 break;
4542 }
4543 case XML_SCHEMA_TYPE_COMPLEX:{
4544 if (typeDecl->subtypes == NULL) {
4545 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard1aefc862004-03-04 11:40:48 +00004546
4547 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4548 typeDecl->contentType =
4549 XML_SCHEMA_CONTENT_MIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004550 } else {
4551 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4552 typeDecl->contentType =
4553 XML_SCHEMA_CONTENT_MIXED;
4554 else {
4555 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4556 NULL);
4557 if (typeDecl->subtypes != NULL)
4558 typeDecl->contentType =
4559 typeDecl->subtypes->contentType;
4560 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004561 if (typeDecl->attributes == NULL)
4562 typeDecl->attributes =
4563 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004564 }
4565 break;
4566 }
4567 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{
4568 if (typeDecl->subtypes == NULL) {
4569 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard1aefc862004-03-04 11:40:48 +00004570 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4571 typeDecl->contentType =
4572 XML_SCHEMA_CONTENT_MIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004573 } else {
4574 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4575 typeDecl->contentType =
4576 XML_SCHEMA_CONTENT_MIXED;
4577 else {
4578 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4579 NULL);
4580 if (typeDecl->subtypes != NULL)
4581 typeDecl->contentType =
4582 typeDecl->subtypes->contentType;
4583 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004584 if (typeDecl->attributes == NULL)
4585 typeDecl->attributes =
4586 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004587 }
4588 break;
4589 }
4590 case XML_SCHEMA_TYPE_SEQUENCE:
4591 case XML_SCHEMA_TYPE_GROUP:
4592 case XML_SCHEMA_TYPE_ALL:
4593 case XML_SCHEMA_TYPE_CHOICE:
4594 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
4595 break;
4596 case XML_SCHEMA_TYPE_BASIC:
4597 case XML_SCHEMA_TYPE_ANY:
4598 case XML_SCHEMA_TYPE_FACET:
4599 case XML_SCHEMA_TYPE_SIMPLE:
4600 case XML_SCHEMA_TYPE_UR:
4601 case XML_SCHEMA_TYPE_ELEMENT:
4602 case XML_SCHEMA_TYPE_ATTRIBUTE:
4603 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4604 case XML_SCHEMA_TYPE_NOTATION:
4605 case XML_SCHEMA_TYPE_LIST:
4606 case XML_SCHEMA_TYPE_UNION:
Daniel Veillard377e1a92004-04-16 16:30:05 +00004607 xmlSchemaParseUnionRefCheck(typeDecl, ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004608 case XML_SCHEMA_FACET_MININCLUSIVE:
4609 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4610 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4611 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4612 case XML_SCHEMA_FACET_TOTALDIGITS:
4613 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4614 case XML_SCHEMA_FACET_PATTERN:
4615 case XML_SCHEMA_FACET_ENUMERATION:
4616 case XML_SCHEMA_FACET_WHITESPACE:
4617 case XML_SCHEMA_FACET_LENGTH:
4618 case XML_SCHEMA_FACET_MAXLENGTH:
4619 case XML_SCHEMA_FACET_MINLENGTH:
4620 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004621 if (typeDecl->subtypes != NULL)
4622 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004623 break;
4624 }
4625 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004626#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004627 if (typeDecl->node != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004628 xmlGenericError(xmlGenericErrorContext,
4629 "Type of %s : %s:%d :", name,
4630 typeDecl->node->doc->URL,
4631 xmlGetLineNo(typeDecl->node));
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004632 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004633 xmlGenericError(xmlGenericErrorContext, "Type of %s :", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004634 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004635 switch (typeDecl->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004636 case XML_SCHEMA_CONTENT_SIMPLE:
4637 xmlGenericError(xmlGenericErrorContext, "simple\n");
4638 break;
4639 case XML_SCHEMA_CONTENT_ELEMENTS:
4640 xmlGenericError(xmlGenericErrorContext, "elements\n");
4641 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004642 case XML_SCHEMA_CONTENT_UNKNOWN:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004643 xmlGenericError(xmlGenericErrorContext, "unknown !!!\n");
4644 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004645 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004646 xmlGenericError(xmlGenericErrorContext, "empty\n");
4647 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004648 case XML_SCHEMA_CONTENT_MIXED:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004649 xmlGenericError(xmlGenericErrorContext, "mixed\n");
4650 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004651 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004652 xmlGenericError(xmlGenericErrorContext, "mixed or elems\n");
4653 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004654 case XML_SCHEMA_CONTENT_BASIC:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004655 xmlGenericError(xmlGenericErrorContext, "basic\n");
4656 break;
4657 default:
4658 xmlGenericError(xmlGenericErrorContext,
4659 "not registered !!!\n");
4660 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004661 }
4662#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00004663}
4664
4665/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004666 * xmlSchemaCheckFacet:
4667 * @facet: the facet
4668 * @typeDecl: the schema type definition
4669 * @ctxt: the schema parser context or NULL
4670 * @name: name of the type
4671 *
4672 * Checks the default values types, especially for facets
4673 *
4674 * Returns 0 if okay or -1 in cae of error
4675 */
4676int
4677xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004678 xmlSchemaTypePtr typeDecl,
4679 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004680{
4681 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
4682 int ret = 0;
4683
4684 if (nonNegativeIntegerType == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004685 nonNegativeIntegerType =
4686 xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger",
4687 xmlSchemaNs);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004688 }
4689 switch (facet->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004690 case XML_SCHEMA_FACET_MININCLUSIVE:
4691 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4692 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4693 case XML_SCHEMA_FACET_MAXEXCLUSIVE:{
4694 /*
4695 * Okay we need to validate the value
4696 * at that point.
4697 */
4698 xmlSchemaValidCtxtPtr vctxt;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004699
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004700 vctxt = xmlSchemaNewValidCtxt(NULL);
4701 if (vctxt == NULL)
4702 break;
4703 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4704 facet->value);
4705 facet->val = vctxt->value;
4706 vctxt->value = NULL;
4707 if (facet->val == NULL) {
4708 /* error code */
4709 if (ctxt != NULL) {
4710 xmlSchemaPErr(ctxt, facet->node,
4711 XML_SCHEMAP_INVALID_FACET,
4712 "Schemas: type %s facet value %s invalid\n",
4713 name, facet->value);
4714 }
4715 ret = -1;
4716 }
4717 xmlSchemaFreeValidCtxt(vctxt);
4718 break;
4719 }
4720 case XML_SCHEMA_FACET_ENUMERATION:{
4721 /*
4722 * Okay we need to validate the value
4723 * at that point.
4724 */
4725 xmlSchemaValidCtxtPtr vctxt;
4726 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004727
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004728 vctxt = xmlSchemaNewValidCtxt(NULL);
4729 if (vctxt == NULL)
4730 break;
4731 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4732 facet->value);
4733 if (tmp != 0) {
4734 if (ctxt != NULL) {
4735 xmlSchemaPErr(ctxt, facet->node,
4736 XML_SCHEMAP_INVALID_ENUM,
4737 "Schemas: type %s enumeration value %s invalid\n",
4738 name, facet->value);
4739 }
4740 ret = -1;
4741 }
4742 xmlSchemaFreeValidCtxt(vctxt);
4743 break;
4744 }
4745 case XML_SCHEMA_FACET_PATTERN:
4746 facet->regexp = xmlRegexpCompile(facet->value);
4747 if (facet->regexp == NULL) {
4748 xmlSchemaPErr(ctxt, typeDecl->node,
4749 XML_SCHEMAP_REGEXP_INVALID,
4750 "Schemas: type %s facet regexp %s invalid\n",
4751 name, facet->value);
4752 ret = -1;
4753 }
4754 break;
4755 case XML_SCHEMA_FACET_TOTALDIGITS:
4756 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4757 case XML_SCHEMA_FACET_LENGTH:
4758 case XML_SCHEMA_FACET_MAXLENGTH:
4759 case XML_SCHEMA_FACET_MINLENGTH:{
4760 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004761
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004762 tmp =
4763 xmlSchemaValidatePredefinedType(nonNegativeIntegerType,
4764 facet->value,
4765 &facet->val);
4766 if (tmp != 0) {
4767 /* error code */
4768 if (ctxt != NULL) {
4769 xmlSchemaPErr(ctxt, facet->node,
4770 XML_SCHEMAP_INVALID_FACET_VALUE,
4771 "Schemas: type %s facet value %s invalid\n",
4772 name, facet->value);
4773 }
4774 ret = -1;
4775 }
4776 break;
4777 }
4778 case XML_SCHEMA_FACET_WHITESPACE:{
4779 if (xmlStrEqual(facet->value, BAD_CAST "preserve")) {
4780 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4781 } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) {
4782 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4783 } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) {
4784 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4785 } else {
4786 if (ctxt != NULL) {
4787 xmlSchemaPErr(ctxt, facet->node,
4788 XML_SCHEMAP_INVALID_WHITE_SPACE,
4789 "Schemas: type %s whiteSpace value %s invalid\n",
4790 name, facet->value);
4791 }
4792 ret = -1;
4793 }
4794 }
4795 default:
4796 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004797 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004798 return (ret);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004799}
4800
4801/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004802 * xmlSchemaCheckDefaults:
4803 * @typeDecl: the schema type definition
4804 * @ctxt: the schema parser context
4805 *
4806 * Checks the default values types, especially for facets
4807 */
4808static void
4809xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004810 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004811{
Daniel Veillard4255d502002-04-16 15:50:10 +00004812 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004813 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004814 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004815 if (typeDecl->facets != NULL) {
4816 xmlSchemaFacetPtr facet = typeDecl->facets;
4817
4818 while (facet != NULL) {
4819 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
4820 facet = facet->next;
4821 }
4822 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004823 }
4824}
4825
4826/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004827 * xmlSchemaAttrGrpFixup:
4828 * @attrgrpDecl: the schema attribute definition
4829 * @ctxt: the schema parser context
4830 * @name: the attribute name
4831 *
4832 * Fixes finish doing the computations on the attributes definitions
4833 */
4834static void
4835xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004836 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard13e04c62002-04-23 17:51:29 +00004837{
4838 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004839 name = attrgrpDecl->name;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004840 if (attrgrpDecl->attributes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004841 return;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004842 if (attrgrpDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004843 xmlSchemaAttributeGroupPtr ref;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004844
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004845 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4846 attrgrpDecl->refNs);
4847 if (ref == NULL) {
4848 xmlSchemaPErr(ctxt, attrgrpDecl->node,
4849 XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP,
4850 "Schemas: attribute group %s reference %s not found\n",
4851 name, attrgrpDecl->ref);
4852 return;
4853 }
4854 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4855 attrgrpDecl->attributes = ref->attributes;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004856 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004857 xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF,
4858 "Schemas: attribute %s has no attributes nor reference\n",
4859 name, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004860 }
4861}
4862
4863/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004864 * xmlSchemaAttrFixup:
4865 * @attrDecl: the schema attribute definition
4866 * @ctxt: the schema parser context
4867 * @name: the attribute name
4868 *
4869 * Fixes finish doing the computations on the attributes definitions
4870 */
4871static void
4872xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004873 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004874{
4875 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004876 name = attrDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004877 if (attrDecl->subtypes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004878 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004879 if (attrDecl->typeName != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004880 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004881
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004882 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4883 attrDecl->typeNs);
4884 if (type == NULL) {
4885 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE,
4886 "Schemas: attribute %s type %s not found\n",
4887 name, attrDecl->typeName);
4888 }
4889 attrDecl->subtypes = type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004890 } else if (attrDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004891 xmlSchemaAttributePtr ref;
Daniel Veillard4255d502002-04-16 15:50:10 +00004892
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004893 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4894 attrDecl->refNs);
4895 if (ref == NULL) {
4896 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF,
4897 "Schemas: attribute %s reference %s not found\n",
4898 name, attrDecl->ref);
4899 return;
4900 }
4901 xmlSchemaAttrFixup(ref, ctxt, NULL);
4902 attrDecl->subtypes = ref->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +00004903 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004904 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF,
4905 "Schemas: attribute %s has no type nor reference\n",
4906 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004907 }
4908}
4909
4910/**
4911 * xmlSchemaParse:
4912 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004913 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004914 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004915 * XML Shema struture which can be used to validate instances.
4916 * *WARNING* this interface is highly subject to change
4917 *
4918 * Returns the internal XML Schema structure built from the resource or
4919 * NULL in case of error
4920 */
4921xmlSchemaPtr
4922xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4923{
4924 xmlSchemaPtr ret = NULL;
4925 xmlDocPtr doc;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004926 xmlNodePtr root;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004927 int nberrors;
Daniel Veillarddda22c12004-01-24 08:31:30 +00004928 int preserve = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004929
4930 xmlSchemaInitTypes();
4931
Daniel Veillard6045c902002-10-09 21:13:59 +00004932 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004933 return (NULL);
4934
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004935 nberrors = ctxt->nberrors;
4936 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004937 ctxt->counter = 0;
4938 ctxt->container = NULL;
4939
4940 /*
4941 * First step is to parse the input document into an DOM/Infoset
4942 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004943 if (ctxt->URL != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004944 doc = xmlReadFile((const char *) ctxt->URL, NULL,
4945 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004946 if (doc == NULL) {
4947 xmlSchemaPErr(ctxt, NULL,
4948 XML_SCHEMAP_FAILED_LOAD,
4949 "xmlSchemaParse: could not load %s\n",
4950 ctxt->URL, NULL);
4951 return (NULL);
4952 }
Daniel Veillard6045c902002-10-09 21:13:59 +00004953 } else if (ctxt->buffer != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004954 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
4955 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004956 if (doc == NULL) {
4957 xmlSchemaPErr(ctxt, NULL,
4958 XML_SCHEMAP_FAILED_PARSE,
4959 "xmlSchemaParse: could not parse\n",
4960 NULL, NULL);
4961 return (NULL);
4962 }
4963 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard65765282004-01-08 16:59:30 +00004964 ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1);
Daniel Veillard9d751502003-10-29 13:21:47 +00004965 } else if (ctxt->doc != NULL) {
4966 doc = ctxt->doc;
Daniel Veillarddda22c12004-01-24 08:31:30 +00004967 preserve = 1;
Daniel Veillard6045c902002-10-09 21:13:59 +00004968 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004969 xmlSchemaPErr(ctxt, NULL,
4970 XML_SCHEMAP_NOTHING_TO_PARSE,
4971 "xmlSchemaParse: could not parse\n",
4972 NULL, NULL);
4973 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004974 }
4975
4976 /*
4977 * Then extract the root and Schema parse it
4978 */
4979 root = xmlDocGetRootElement(doc);
4980 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004981 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
4982 XML_SCHEMAP_NOROOT,
4983 "schemas has no root", NULL, NULL);
Daniel Veillarddda22c12004-01-24 08:31:30 +00004984 if (!preserve) {
4985 xmlFreeDoc(doc);
4986 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004987 return (NULL);
4988 }
4989
4990 /*
4991 * Remove all the blank text nodes
4992 */
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004993 xmlSchemaCleanupDoc(ctxt, root);
Daniel Veillard4255d502002-04-16 15:50:10 +00004994
4995 /*
4996 * Then do the parsing for good
4997 */
4998 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillard1d913862003-11-21 00:28:39 +00004999 if (ret == NULL) {
Daniel Veillarddda22c12004-01-24 08:31:30 +00005000 if (!preserve) {
5001 xmlFreeDoc(doc);
5002 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005003 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00005004 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005005 ret->doc = doc;
Daniel Veillarddda22c12004-01-24 08:31:30 +00005006 ret->preserve = preserve;
Daniel Veillard4255d502002-04-16 15:50:10 +00005007
5008 /*
5009 * Then fix all the references.
5010 */
5011 ctxt->schema = ret;
5012 xmlHashScanFull(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005013 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005014
5015 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005016 * Then fixup all attributes declarations
5017 */
5018 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
5019
5020 /*
5021 * Then fixup all attributes group declarations
5022 */
5023 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup,
5024 ctxt);
5025
5026 /*
Daniel Veillard4255d502002-04-16 15:50:10 +00005027 * Then fixup all types properties
5028 */
5029 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
5030
5031 /*
5032 * Then build the content model for all elements
5033 */
5034 xmlHashScan(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005035 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005036
5037 /*
5038 * Then check the defaults part of the type like facets values
5039 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005040 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults,
5041 ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005042
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005043 if (ctxt->nberrors != 0) {
5044 xmlSchemaFree(ret);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005045 ret = NULL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00005046 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005047 return (ret);
5048}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005049
Daniel Veillard4255d502002-04-16 15:50:10 +00005050/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005051 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00005052 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00005053 * @err: the error callback
5054 * @warn: the warning callback
5055 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00005056 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00005057 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00005058 */
5059void
5060xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005061 xmlSchemaValidityErrorFunc err,
5062 xmlSchemaValidityWarningFunc warn, void *ctx)
5063{
Daniel Veillard4255d502002-04-16 15:50:10 +00005064 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005065 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00005066 ctxt->error = err;
5067 ctxt->warning = warn;
5068 ctxt->userData = ctx;
5069}
5070
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005071/**
5072 * xmlSchemaFacetTypeToString:
5073 * @type: the facet type
5074 *
5075 * Convert the xmlSchemaTypeType to a char string.
5076 *
5077 * Returns the char string representation of the facet type if the
5078 * type is a facet and an "Internal Error" string otherwise.
5079 */
5080static const char *
5081xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
5082{
5083 switch (type) {
5084 case XML_SCHEMA_FACET_PATTERN:
5085 return ("pattern");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005086 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005087 return ("maxExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005088 case XML_SCHEMA_FACET_MAXINCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005089 return ("maxInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005090 case XML_SCHEMA_FACET_MINEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005091 return ("minExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005092 case XML_SCHEMA_FACET_MININCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005093 return ("minInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005094 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005095 return ("whiteSpace");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005096 case XML_SCHEMA_FACET_ENUMERATION:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005097 return ("enumeration");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005098 case XML_SCHEMA_FACET_LENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005099 return ("length");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005100 case XML_SCHEMA_FACET_MAXLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005101 return ("maxLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005102 case XML_SCHEMA_FACET_MINLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005103 return ("minLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005104 case XML_SCHEMA_FACET_TOTALDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005105 return ("totalDigits");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005106 case XML_SCHEMA_FACET_FRACTIONDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005107 return ("fractionDigits");
5108 default:
5109 break;
5110 }
5111 return ("Internal Error");
5112}
5113
5114/**
5115 * xmlSchemaValidateFacets:
5116 * @ctxt: a schema validation context
5117 * @base: the base type
5118 * @facets: the list of facets to check
5119 * @value: the lexical repr of the value to validate
5120 * @val: the precomputed value
5121 *
5122 * Check a value against all facet conditions
5123 *
5124 * Returns 0 if the element is schemas valid, a positive error code
5125 * number otherwise and -1 in case of internal or API error.
5126 */
5127static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005128xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
5129 xmlSchemaTypePtr base,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005130 xmlSchemaFacetPtr facets, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005131{
Daniel Veillard377e1a92004-04-16 16:30:05 +00005132 return(xmlSchemaValidateFacetsInternal(ctxt, base, facets, value, 1));
5133}
5134
5135/**
5136 * xmlSchemaValidateFacetsInternal:
5137 * @ctxt: a schema validation context
5138 * @base: the base type
5139 * @facets: the list of facets to check
5140 * @value: the lexical repr of the value to validate
5141 * @val: the precomputed value
5142 * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
5143 *
5144 * Check a value against all facet conditions
5145 *
5146 * Returns 0 if the element is schemas valid, a positive error code
5147 * number otherwise and -1 in case of internal or API error.
5148 */
5149static int
5150xmlSchemaValidateFacetsInternal(xmlSchemaValidCtxtPtr ctxt,
5151 xmlSchemaTypePtr base,
5152 xmlSchemaFacetPtr facets, const xmlChar * value, int fireErrors)
5153{
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005154 int ret = 0;
5155 int tmp = 0;
5156 xmlSchemaTypeType type;
5157 xmlSchemaFacetPtr facet = facets;
5158
5159 while (facet != NULL) {
5160 type = facet->type;
5161 if (type == XML_SCHEMA_FACET_ENUMERATION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005162 tmp = 1;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005163
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005164 while (facet != NULL) {
5165 tmp =
5166 xmlSchemaValidateFacet(base, facet, value,
5167 ctxt->value);
5168 if (tmp == 0) {
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005169 return 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005170 }
5171 facet = facet->next;
5172 }
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005173 } else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005174 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005175
5176 if (tmp != 0) {
5177 ret = tmp;
Daniel Veillard377e1a92004-04-16 16:30:05 +00005178 if (fireErrors)
5179 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 +00005180 }
5181 if (facet != NULL)
5182 facet = facet->next;
5183 }
5184 return (ret);
5185}
5186
Daniel Veillard4255d502002-04-16 15:50:10 +00005187/************************************************************************
5188 * *
5189 * Simple type validation *
5190 * *
5191 ************************************************************************/
5192
5193/**
Daniel Veillard377e1a92004-04-16 16:30:05 +00005194 * xmlSchemaValidateSimpleValueUnion:
5195 * @ctxt: a schema validation context
5196 * @type: the type declaration
5197 * @value: the value to validate
5198 *
5199 * Validates a value against a union.
5200 *
5201 * Returns 0 if the value is valid, a positive error code
5202 * number otherwise and -1 in case of internal or API error.
5203 */
5204static int
5205xmlSchemaValidateSimpleValueUnion(xmlSchemaValidCtxtPtr ctxt,
5206 xmlSchemaTypePtr type, const xmlChar * value)
5207{
5208 int ret = 0;
5209 const xmlChar *cur, *end, *prefix, *ncName;
5210 xmlChar *tmp;
5211 xmlSchemaTypePtr subtype;
5212 xmlNsPtr ns;
5213 int len;
5214
5215
5216 /* Process referenced memberTypes. */
5217 cur = type->ref;
5218 do {
5219 while (IS_BLANK_CH(*cur))
5220 cur++;
5221 end = cur;
5222 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
5223 end++;
5224 if (end == cur)
5225 break;
5226 tmp = xmlStrndup(cur, end - cur);
5227 ncName = xmlSplitQName3(tmp, &len);
5228 if (ncName != NULL) {
5229 prefix = xmlStrndup(tmp, len);
5230 /* prefix = xmlDictLookup(ctxt->doc->dict, tmp, len); */
5231 } else {
5232 prefix = NULL;
5233 ncName = tmp;
5234 }
5235 /* We won't do additional checks here, since they have been performed during parsing. */
5236 ns = xmlSearchNs(type->node->doc, type->node, prefix);
5237 /* namespace = xmlDictLookup(ctxt->doc->dict, ns->href, -1); */
5238 subtype = xmlSchemaGetType(ctxt->schema, ncName, ns->href);
5239 if (tmp != NULL)
5240 xmlFree(tmp);
5241 if (prefix != NULL)
5242 xmlFree(prefix);
5243 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
5244 if ((ret == 0) || (ret == -1)) {
5245 return (ret);
5246 }
5247 cur = end;
5248 } while (*cur != 0);
5249
5250 if (type->subtypes != NULL) {
5251 subtype = type->subtypes;
5252 do {
5253 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
5254 if ((ret == 0) || (ret == -1)) {
5255 return (ret);
5256 }
5257 subtype = subtype->next;
5258 } while (subtype != NULL);
5259 }
5260 return (ret);
5261}
5262
5263/**
Daniel Veillard4255d502002-04-16 15:50:10 +00005264 * xmlSchemaValidateSimpleValue:
5265 * @ctxt: a schema validation context
5266 * @type: the type declaration
5267 * @value: the value to validate
5268 *
5269 * Validate a value against a simple type
5270 *
5271 * Returns 0 if the value is valid, a positive error code
5272 * number otherwise and -1 in case of internal or API error.
5273 */
5274static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005275xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005276 xmlSchemaTypePtr type, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005277{
Daniel Veillard377e1a92004-04-16 16:30:05 +00005278 return (xmlSchemaValidateSimpleValueInternal(ctxt, type, value, 1));
5279}
5280
5281/**
5282 * xmlSchemaValidateSimpleValue:
5283 * @ctxt: a schema validation context
5284 * @type: the type declaration
5285 * @value: the value to validate
5286 * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
5287 *
5288 * Validate a value against a simple type
5289 *
5290 * Returns 0 if the value is valid, a positive error code
5291 * number otherwise and -1 in case of internal or API error.
5292 */
5293static int
5294xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt,
5295 xmlSchemaTypePtr type, const xmlChar * value, int fireErrors)
5296{
Daniel Veillard4255d502002-04-16 15:50:10 +00005297 int ret = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005298
Daniel Veillard4255d502002-04-16 15:50:10 +00005299 /*
5300 * First normalize the value accordingly to Schema Datatype
5301 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
5302 */
5303 /*
5304 * Then check the normalized value against the lexical space of the
5305 * type.
5306 */
5307 if (type->type == XML_SCHEMA_TYPE_BASIC) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005308 if (ctxt->value != NULL) {
5309 xmlSchemaFreeValue(ctxt->value);
5310 ctxt->value = NULL;
5311 }
5312 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
5313 ctxt->cur);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005314 if ((fireErrors) && (ret != 0)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005315 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 +00005316 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005317 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005318 xmlSchemaTypePtr base;
5319 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005320
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005321 base = type->baseType;
5322 if (base != NULL) {
Daniel Veillard377e1a92004-04-16 16:30:05 +00005323 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005324 } else if (type->subtypes != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005325 TODO
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005326 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005327
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005328 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005329 * Do not validate facets or attributes when working on
5330 * building the Schemas
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005331 */
5332 if (ctxt->schema != NULL) {
5333 if (ret == 0) {
5334 facet = type->facets;
Daniel Veillard377e1a92004-04-16 16:30:05 +00005335 ret = xmlSchemaValidateFacetsInternal(ctxt, base, facet, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005336 }
5337 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005338 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005339 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00005340
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005341 base = type->subtypes;
5342 if (base != NULL) {
Daniel Veillard377e1a92004-04-16 16:30:05 +00005343 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005344 } else {
5345 TODO}
Daniel Veillard4255d502002-04-16 15:50:10 +00005346 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005347 xmlSchemaTypePtr base;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005348 const xmlChar *cur, *end;
5349 xmlChar *tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005350 int ret2;
Daniel Veillard4255d502002-04-16 15:50:10 +00005351
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005352 base = type->subtypes;
5353 if (base == NULL) {
5354 xmlSchemaVErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL,
5355 "Internal: List type %s has no base type\n",
5356 type->name, NULL);
5357 return (-1);
5358 }
5359 cur = value;
5360 do {
William M. Brack76e95df2003-10-18 16:20:14 +00005361 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005362 cur++;
5363 end = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00005364 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005365 end++;
5366 if (end == cur)
5367 break;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005368 tmp = xmlStrndup(cur, end - cur);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005369 ret2 = xmlSchemaValidateSimpleValueInternal(ctxt, base, tmp, fireErrors);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005370 xmlFree(tmp);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005371 if (ret2 != 0)
5372 ret = 1;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005373 cur = end;
5374 } while (*cur != 0);
Daniel Veillard377e1a92004-04-16 16:30:05 +00005375 } else if (type->type == XML_SCHEMA_TYPE_UNION) {
5376 ret = xmlSchemaValidateSimpleValueUnion(ctxt, type, value);
5377 if ((fireErrors) && (ret != 0)) {
5378 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, "Failed to validate type %s\n", type->name, NULL);
5379 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005380 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005381 TODO
5382 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005383 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005384}
5385
5386/************************************************************************
5387 * *
5388 * DOM Validation code *
5389 * *
5390 ************************************************************************/
5391
5392static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005393 xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005394static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005395 xmlNodePtr elem,
5396 xmlSchemaAttributePtr attributes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005397static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005398 xmlNodePtr elem,
5399 xmlSchemaElementPtr elemDecl,
5400 xmlSchemaTypePtr type);
Daniel Veillard4255d502002-04-16 15:50:10 +00005401
5402/**
5403 * xmlSchemaRegisterAttributes:
5404 * @ctxt: a schema validation context
5405 * @attrs: a list of attributes
5406 *
5407 * Register the list of attributes as the set to be validated on that element
5408 *
5409 * Returns -1 in case of error, 0 otherwise
5410 */
5411static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005412xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs)
5413{
Daniel Veillard4255d502002-04-16 15:50:10 +00005414 while (attrs != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005415 if ((attrs->ns != NULL) &&
5416 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
5417 attrs = attrs->next;
5418 continue;
5419 }
5420 if (ctxt->attrNr >= ctxt->attrMax) {
5421 xmlSchemaAttrStatePtr tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00005422
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005423 ctxt->attrMax *= 2;
5424 tmp = (xmlSchemaAttrStatePtr)
5425 xmlRealloc(ctxt->attr, ctxt->attrMax *
5426 sizeof(xmlSchemaAttrState));
5427 if (tmp == NULL) {
5428 xmlSchemaVErrMemory(ctxt, "registering attributes", NULL);
5429 ctxt->attrMax /= 2;
5430 return (-1);
5431 }
5432 ctxt->attr = tmp;
5433 }
5434 ctxt->attr[ctxt->attrNr].attr = attrs;
5435 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
5436 ctxt->attrNr++;
5437 attrs = attrs->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005438 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005439 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005440}
5441
5442/**
5443 * xmlSchemaCheckAttributes:
5444 * @ctxt: a schema validation context
5445 * @node: the node carrying it.
5446 *
5447 * Check that the registered set of attributes on the current node
5448 * has been properly validated.
5449 *
5450 * Returns 0 if validity constraints are met, 1 otherwise.
5451 */
5452static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005453xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5454{
Daniel Veillard4255d502002-04-16 15:50:10 +00005455 int ret = 0;
5456 int i;
5457
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005458 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
5459 if (ctxt->attr[i].attr == NULL)
5460 break;
5461 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
5462 ret = 1;
5463 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, "Attribute %s on %s is unknown\n", ctxt->attr[i].attr->name, node->name);
5464 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005465 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005466 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005467}
5468
5469/**
5470 * xmlSchemaValidateSimpleContent:
5471 * @ctxt: a schema validation context
5472 * @elem: an element
5473 * @type: the type declaration
5474 *
5475 * Validate the content of an element expected to be a simple type
5476 *
5477 * Returns 0 if the element is schemas valid, a positive error code
5478 * number otherwise and -1 in case of internal or API error.
5479 */
5480static int
5481xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005482 xmlNodePtr node ATTRIBUTE_UNUSED)
5483{
Daniel Veillard4255d502002-04-16 15:50:10 +00005484 xmlNodePtr child;
5485 xmlSchemaTypePtr type, base;
5486 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005487 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00005488
5489 child = ctxt->node;
5490 type = ctxt->type;
5491
5492 /*
5493 * Validation Rule: Element Locally Valid (Type): 3.1.3
5494 */
5495 value = xmlNodeGetContent(child);
5496 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
5497 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005498 case XML_SCHEMA_TYPE_RESTRICTION:{
5499 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005500
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005501 base = type->baseType;
5502 if (base != NULL) {
5503 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5504 } else {
5505 TODO}
5506 if (ret == 0) {
5507 facet = type->facets;
5508 ret =
5509 xmlSchemaValidateFacets(ctxt, base, facet, value);
5510 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005511 if ((ret == 0) && (type->attributes != NULL)) {
5512 ret = xmlSchemaValidateAttributes(ctxt, node,
5513 type->attributes);
5514 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005515 break;
5516 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005517 case XML_SCHEMA_TYPE_EXTENSION:{
5518 TODO
5519 break;
5520 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005521 default:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005522 TODO
5523 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005524 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005525 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005526
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005527 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005528}
5529
5530/**
5531 * xmlSchemaValidateCheckNodeList
5532 * @nodelist: the list of nodes
5533 *
5534 * Check the node list is only made of text nodes and entities pointing
5535 * to text nodes
5536 *
5537 * Returns 1 if true, 0 if false and -1 in case of error
5538 */
5539static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005540xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist)
5541{
Daniel Veillard4255d502002-04-16 15:50:10 +00005542 while (nodelist != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005543 if (nodelist->type == XML_ENTITY_REF_NODE) {
5544 TODO /* implement recursion in the entity content */
5545 }
5546 if ((nodelist->type != XML_TEXT_NODE) &&
5547 (nodelist->type != XML_COMMENT_NODE) &&
5548 (nodelist->type != XML_PI_NODE) &&
5549 (nodelist->type != XML_PI_NODE)) {
5550 return (0);
5551 }
5552 nodelist = nodelist->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005553 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005554 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005555}
5556
5557/**
5558 * xmlSchemaSkipIgnored:
5559 * @ctxt: a schema validation context
5560 * @type: the current type context
5561 * @node: the top node.
5562 *
5563 * Skip ignorable nodes in that context
5564 *
5565 * Returns the new sibling
5566 * number otherwise and -1 in case of internal or API error.
5567 */
5568static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00005569xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005570 xmlSchemaTypePtr type, xmlNodePtr node)
5571{
Daniel Veillard4255d502002-04-16 15:50:10 +00005572 int mixed = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005573
Daniel Veillard4255d502002-04-16 15:50:10 +00005574 /*
5575 * TODO complete and handle entities
5576 */
5577 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005578 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
Daniel Veillard4255d502002-04-16 15:50:10 +00005579 while ((node != NULL) &&
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005580 ((node->type == XML_COMMENT_NODE) ||
5581 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
5582 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
5583 (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) {
5584 node = node->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005585 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005586 return (node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005587}
5588
5589/**
5590 * xmlSchemaValidateCallback:
5591 * @ctxt: a schema validation context
5592 * @name: the name of the element detected (might be NULL)
5593 * @type: the type
5594 *
5595 * A transition has been made in the automata associated to an element
5596 * content model
5597 */
5598static void
5599xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005600 const xmlChar * name ATTRIBUTE_UNUSED,
5601 xmlSchemaTypePtr type, xmlNodePtr node)
5602{
Daniel Veillard4255d502002-04-16 15:50:10 +00005603 xmlSchemaTypePtr oldtype = ctxt->type;
5604 xmlNodePtr oldnode = ctxt->node;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005605
Daniel Veillard4255d502002-04-16 15:50:10 +00005606#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00005607 xmlGenericError(xmlGenericErrorContext,
5608 "xmlSchemaValidateCallback: %s, %s, %s\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005609 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005610#endif
5611 ctxt->type = type;
5612 ctxt->node = node;
5613 xmlSchemaValidateContent(ctxt, node);
5614 ctxt->type = oldtype;
5615 ctxt->node = oldnode;
5616}
5617
5618
5619#if 0
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005620
Daniel Veillard4255d502002-04-16 15:50:10 +00005621/**
5622 * xmlSchemaValidateSimpleRestrictionType:
5623 * @ctxt: a schema validation context
5624 * @node: the top node.
5625 *
5626 * Validate the content of a restriction type.
5627 *
5628 * Returns 0 if the element is schemas valid, a positive error code
5629 * number otherwise and -1 in case of internal or API error.
5630 */
5631static int
5632xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
5633 xmlNodePtr node)
5634{
5635 xmlNodePtr child;
5636 xmlSchemaTypePtr type;
5637 int ret;
5638
5639 child = ctxt->node;
5640 type = ctxt->type;
5641
5642 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005643 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005644 return (-1);
5645 }
5646 /*
5647 * Only text and text based entities references shall be found there
5648 */
5649 ret = xmlSchemaValidateCheckNodeList(child);
5650 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005651 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005652 return (-1);
5653 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005654 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 +00005655 return (-1);
5656 }
5657 ctxt->type = type->subtypes;
5658 xmlSchemaValidateContent(ctxt, node);
5659 ctxt->type = type;
5660 return (ret);
5661}
5662#endif
5663
5664/**
5665 * xmlSchemaValidateSimpleType:
5666 * @ctxt: a schema validation context
5667 * @node: the top node.
5668 *
5669 * Validate the content of an simple type.
5670 *
5671 * Returns 0 if the element is schemas valid, a positive error code
5672 * number otherwise and -1 in case of internal or API error.
5673 */
5674static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005675xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5676{
Daniel Veillard4255d502002-04-16 15:50:10 +00005677 xmlNodePtr child;
5678 xmlSchemaTypePtr type;
5679 xmlAttrPtr attr;
5680 int ret;
5681
5682 child = ctxt->node;
5683 type = ctxt->type;
5684
5685 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005686 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s\n", node->name, NULL);
5687 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005688 }
5689 /*
5690 * Only text and text based entities references shall be found there
5691 */
5692 ret = xmlSchemaValidateCheckNodeList(child);
5693 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005694 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
5695 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005696 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005697 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, "Element %s content is not a simple type\n", node->name, NULL);
5698 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005699 }
5700 /*
5701 * Validation Rule: Element Locally Valid (Type): 3.1.1
5702 */
5703 attr = node->properties;
5704 while (attr != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005705 if ((attr->ns == NULL) ||
5706 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
5707 ((!xmlStrEqual(attr->name, BAD_CAST "type")) &&
5708 (!xmlStrEqual(attr->name, BAD_CAST "nil")) &&
5709 (!xmlStrEqual(attr->name, BAD_CAST "schemasLocation")) &&
5710 (!xmlStrEqual
5711 (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) {
5712 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDATTR, "Element %s: attribute %s should not be present\n", node->name, attr->name);
5713 return (ctxt->err);
5714 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005715 }
5716
5717 ctxt->type = type->subtypes;
5718 ret = xmlSchemaValidateSimpleContent(ctxt, node);
5719 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005720 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005721}
5722
5723/**
5724 * xmlSchemaValidateElementType:
5725 * @ctxt: a schema validation context
5726 * @node: the top node.
5727 *
5728 * Validate the content of an element type.
5729 * Validation Rule: Element Locally Valid (Complex Type)
5730 *
5731 * Returns 0 if the element is schemas valid, a positive error code
5732 * number otherwise and -1 in case of internal or API error.
5733 */
5734static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005735xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5736{
Daniel Veillard4255d502002-04-16 15:50:10 +00005737 xmlNodePtr child;
5738 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005739 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
Daniel Veillard4255d502002-04-16 15:50:10 +00005740 xmlSchemaElementPtr decl;
5741 int ret, attrBase;
5742
5743 oldregexp = ctxt->regexp;
5744
5745 child = ctxt->node;
5746 type = ctxt->type;
5747
5748 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005749 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateElementType\n", node->name, NULL);
5750 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005751 }
5752 if (child == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005753 if (type->minOccurs > 0) {
5754 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, "Element %s: missing child %s\n", node->name, type->name);
5755 }
5756 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005757 }
5758
5759 /*
5760 * Verify the element matches
5761 */
5762 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005763 xmlSchemaVErr3(ctxt, node, XML_SCHEMAS_ERR_WRONGELEM, "Element %s: missing child %s found %s\n", node->name, type->name, child->name);
5764 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005765 }
5766 /*
5767 * Verify the attributes
5768 */
5769 attrBase = ctxt->attrBase;
5770 ctxt->attrBase = ctxt->attrNr;
5771 xmlSchemaRegisterAttributes(ctxt, child->properties);
5772 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
5773 /*
5774 * Verify the element content recursively
5775 */
5776 decl = (xmlSchemaElementPtr) type;
5777 oldregexp = ctxt->regexp;
5778 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005779 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5780 (xmlRegExecCallbacks)
5781 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005782#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005783 xmlGenericError(xmlGenericErrorContext, "====> %s\n", node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005784#endif
5785 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005786 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr) type,
5787 type->subtypes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005788
5789 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005790 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005791#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005792 xmlGenericError(xmlGenericErrorContext,
5793 "====> %s : %d\n", node->name, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005794#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005795 if (ret == 0) {
5796 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", node->name, NULL);
5797 } else if (ret < 0) {
5798 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failure\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005799#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005800 } else {
5801 xmlGenericError(xmlGenericErrorContext,
5802 "Element %s content check succeeded\n",
5803 node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005804
5805#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005806 }
5807 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00005808 }
5809 /*
5810 * Verify that all attributes were Schemas-validated
5811 */
5812 xmlSchemaCheckAttributes(ctxt, node);
5813 ctxt->attrNr = ctxt->attrBase;
5814 ctxt->attrBase = attrBase;
5815
5816 ctxt->regexp = oldregexp;
5817
5818 ctxt->node = child;
5819 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005820 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005821}
5822
5823/**
5824 * xmlSchemaValidateBasicType:
5825 * @ctxt: a schema validation context
5826 * @node: the top node.
5827 *
5828 * Validate the content of an element expected to be a basic type type
5829 *
5830 * Returns 0 if the element is schemas valid, a positive error code
5831 * number otherwise and -1 in case of internal or API error.
5832 */
5833static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005834xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5835{
Daniel Veillard4255d502002-04-16 15:50:10 +00005836 int ret;
5837 xmlNodePtr child, cur;
5838 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005839 xmlChar *value; /* lexical representation */
Daniel Veillard4255d502002-04-16 15:50:10 +00005840
5841 child = ctxt->node;
5842 type = ctxt->type;
5843
5844 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005845 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateBasicType\n", node->name, NULL);
5846 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005847 }
5848 /*
5849 * First check the content model of the node.
5850 */
5851 cur = child;
5852 while (cur != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005853 switch (cur->type) {
5854 case XML_TEXT_NODE:
5855 case XML_CDATA_SECTION_NODE:
5856 case XML_PI_NODE:
5857 case XML_COMMENT_NODE:
5858 case XML_XINCLUDE_START:
5859 case XML_XINCLUDE_END:
5860 break;
5861 case XML_ENTITY_REF_NODE:
5862 case XML_ENTITY_NODE:
5863 TODO break;
5864 case XML_ELEMENT_NODE:
5865 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: child %s should not be present\n", node->name, cur->name);
5866 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005867 case XML_ATTRIBUTE_NODE:
5868 case XML_DOCUMENT_NODE:
5869 case XML_DOCUMENT_TYPE_NODE:
5870 case XML_DOCUMENT_FRAG_NODE:
5871 case XML_NOTATION_NODE:
5872 case XML_HTML_DOCUMENT_NODE:
5873 case XML_DTD_NODE:
5874 case XML_ELEMENT_DECL:
5875 case XML_ATTRIBUTE_DECL:
5876 case XML_ENTITY_DECL:
5877 case XML_NAMESPACE_DECL:
5878#ifdef LIBXML_DOCB_ENABLED
5879 case XML_DOCB_DOCUMENT_NODE:
5880#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005881 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: node type of node unexpected here\n", node->name, NULL);
5882 return (ctxt->err);
5883 }
5884 cur = cur->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005885 }
5886 if (child == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005887 value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005888 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005889 value = xmlNodeGetContent(child->parent);
Daniel Veillard4255d502002-04-16 15:50:10 +00005890
5891 if (ctxt->value != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005892 xmlSchemaFreeValue(ctxt->value);
5893 ctxt->value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005894 }
5895 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5896 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005897 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005898 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005899 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 +00005900 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005901 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005902}
5903
5904/**
5905 * xmlSchemaValidateComplexType:
5906 * @ctxt: a schema validation context
5907 * @node: the top node.
5908 *
5909 * Validate the content of an element expected to be a complex type type
5910 * xmlschema-1.html#cvc-complex-type
5911 * Validation Rule: Element Locally Valid (Complex Type)
5912 *
5913 * Returns 0 if the element is schemas valid, a positive error code
5914 * number otherwise and -1 in case of internal or API error.
5915 */
5916static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005917xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5918{
Daniel Veillard4255d502002-04-16 15:50:10 +00005919 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005920 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005921 int ret;
5922
5923 child = ctxt->node;
5924 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005925 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005926
Daniel Veillard4255d502002-04-16 15:50:10 +00005927 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005928 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005929 if (type->baseType != NULL) {
5930 } else if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005931 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is supposed to be empty\n", node->name, NULL);
5932 }
5933 if (type->attributes != NULL) {
5934 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5935 }
5936 subtype = type->subtypes;
5937 while (subtype != NULL) {
5938 ctxt->type = subtype;
5939 xmlSchemaValidateComplexType(ctxt, node);
5940 subtype = subtype->next;
5941 }
5942 break;
5943 case XML_SCHEMA_CONTENT_ELEMENTS:
5944 case XML_SCHEMA_CONTENT_MIXED:
5945 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5946 /*
5947 * Skip ignorable nodes in that context
5948 */
5949 child = xmlSchemaSkipIgnored(ctxt, type, child);
5950 while (child != NULL) {
5951 if (child->type == XML_ELEMENT_NODE) {
5952 ret = xmlRegExecPushString(ctxt->regexp,
5953 child->name, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005954#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005955 if (ret < 0)
5956 xmlGenericError(xmlGenericErrorContext,
5957 " --> %s Error\n", child->name);
5958 else
5959 xmlGenericError(xmlGenericErrorContext,
5960 " --> %s\n", child->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005961#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005962 }
5963 child = child->next;
5964 /*
5965 * Skip ignorable nodes in that context
5966 */
5967 child = xmlSchemaSkipIgnored(ctxt, type, child);
5968 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005969 if (type->attributes != NULL) {
5970 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5971 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005972 break;
5973 case XML_SCHEMA_CONTENT_BASIC:{
5974 if (type->subtypes != NULL) {
5975 ctxt->type = type->subtypes;
5976 xmlSchemaValidateComplexType(ctxt, node);
5977 }
5978 if (type->baseType != NULL) {
5979 ctxt->type = type->baseType;
5980 xmlSchemaValidateBasicType(ctxt, node);
5981 }
5982 if (type->attributes != NULL) {
5983 xmlSchemaValidateAttributes(ctxt, node,
5984 type->attributes);
5985 }
5986 ctxt->type = type;
5987 break;
5988 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005989 case XML_SCHEMA_CONTENT_SIMPLE:{
5990 if (type->subtypes != NULL) {
5991 ctxt->type = type->subtypes;
5992 xmlSchemaValidateComplexType(ctxt, node);
5993 }
5994 if (type->baseType != NULL) {
5995 ctxt->type = type->baseType;
5996 xmlSchemaValidateComplexType(ctxt, node);
5997 }
5998 if (type->attributes != NULL) {
5999 xmlSchemaValidateAttributes(ctxt, node,
6000 type->attributes);
6001 }
6002 ctxt->type = type;
6003 break;
6004 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006005 default:
6006 TODO xmlGenericError(xmlGenericErrorContext,
6007 "unimplemented content type %d\n",
6008 type->contentType);
Daniel Veillard4255d502002-04-16 15:50:10 +00006009 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006010 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006011}
6012
6013/**
6014 * xmlSchemaValidateContent:
6015 * @ctxt: a schema validation context
6016 * @elem: an element
6017 * @type: the type declaration
6018 *
6019 * Validate the content of an element against the type.
6020 *
6021 * Returns 0 if the element is schemas valid, a positive error code
6022 * number otherwise and -1 in case of internal or API error.
6023 */
6024static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006025xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
6026{
Daniel Veillard4255d502002-04-16 15:50:10 +00006027 xmlNodePtr child;
6028 xmlSchemaTypePtr type;
6029
6030 child = ctxt->node;
6031 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00006032 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00006033
Daniel Veillarde19fc232002-04-22 16:01:24 +00006034 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00006035 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00006036
Daniel Veillard4255d502002-04-16 15:50:10 +00006037 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006038 case XML_SCHEMA_TYPE_ANY:
6039 /* Any type will do it, fine */
6040 TODO /* handle recursivity */
6041 break;
6042 case XML_SCHEMA_TYPE_COMPLEX:
6043 xmlSchemaValidateComplexType(ctxt, node);
6044 break;
6045 case XML_SCHEMA_TYPE_ELEMENT:{
6046 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
6047
6048 /*
6049 * Handle element reference here
6050 */
6051 if (decl->ref != NULL) {
6052 if (decl->refDecl == NULL) {
6053 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: element reference %s not resolved\n", decl->ref, NULL);
6054 return (-1);
6055 }
6056 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
6057 decl = decl->refDecl;
6058 }
6059 xmlSchemaValidateElementType(ctxt, node);
6060 ctxt->type = type;
6061 break;
6062 }
6063 case XML_SCHEMA_TYPE_BASIC:
6064 xmlSchemaValidateBasicType(ctxt, node);
6065 break;
6066 case XML_SCHEMA_TYPE_FACET:
6067 TODO break;
6068 case XML_SCHEMA_TYPE_SIMPLE:
6069 xmlSchemaValidateSimpleType(ctxt, node);
6070 break;
6071 case XML_SCHEMA_TYPE_SEQUENCE:
6072 TODO break;
6073 case XML_SCHEMA_TYPE_CHOICE:
6074 TODO break;
6075 case XML_SCHEMA_TYPE_ALL:
6076 TODO break;
6077 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
6078 TODO break;
6079 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
6080 TODO break;
6081 case XML_SCHEMA_TYPE_UR:
6082 TODO break;
6083 case XML_SCHEMA_TYPE_RESTRICTION:
6084 /*xmlSchemaValidateRestrictionType(ctxt, node); */
6085 TODO break;
6086 case XML_SCHEMA_TYPE_EXTENSION:
6087 TODO break;
6088 case XML_SCHEMA_TYPE_ATTRIBUTE:
6089 TODO break;
6090 case XML_SCHEMA_TYPE_GROUP:
6091 TODO break;
6092 case XML_SCHEMA_TYPE_NOTATION:
6093 TODO break;
6094 case XML_SCHEMA_TYPE_LIST:
6095 TODO break;
6096 case XML_SCHEMA_TYPE_UNION:
6097 TODO break;
6098 case XML_SCHEMA_FACET_MININCLUSIVE:
6099 TODO break;
6100 case XML_SCHEMA_FACET_MINEXCLUSIVE:
6101 TODO break;
6102 case XML_SCHEMA_FACET_MAXINCLUSIVE:
6103 TODO break;
6104 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
6105 TODO break;
6106 case XML_SCHEMA_FACET_TOTALDIGITS:
6107 TODO break;
6108 case XML_SCHEMA_FACET_FRACTIONDIGITS:
6109 TODO break;
6110 case XML_SCHEMA_FACET_PATTERN:
6111 TODO break;
6112 case XML_SCHEMA_FACET_ENUMERATION:
6113 TODO break;
6114 case XML_SCHEMA_FACET_WHITESPACE:
6115 TODO break;
6116 case XML_SCHEMA_FACET_LENGTH:
6117 TODO break;
6118 case XML_SCHEMA_FACET_MAXLENGTH:
6119 TODO break;
6120 case XML_SCHEMA_FACET_MINLENGTH:
6121 TODO break;
6122 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
6123 TODO break;
Daniel Veillard4255d502002-04-16 15:50:10 +00006124 }
6125 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
6126
6127 if (ctxt->node == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006128 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006129 ctxt->node = ctxt->node->next;
6130 ctxt->type = type->next;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006131 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006132}
6133
6134/**
6135 * xmlSchemaValidateType:
6136 * @ctxt: a schema validation context
6137 * @elem: an element
6138 * @type: the list of type declarations
6139 *
6140 * Validate the content of an element against the types.
6141 *
6142 * Returns 0 if the element is schemas valid, a positive error code
6143 * number otherwise and -1 in case of internal or API error.
6144 */
6145static int
6146xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006147 xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type)
6148{
Daniel Veillard4255d502002-04-16 15:50:10 +00006149 xmlChar *nil;
6150
Daniel Veillard2db8c122003-07-08 12:16:59 +00006151 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006152 return (0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00006153
Daniel Veillard4255d502002-04-16 15:50:10 +00006154 /*
6155 * 3.3.4 : 2
6156 */
6157 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006158 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, "Element %s is abstract\n", elem->name, NULL);
6159 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006160 }
6161 /*
6162 * 3.3.4: 3
6163 */
6164 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
6165 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006166 /* 3.3.4: 3.2 */
6167 if (xmlStrEqual(nil, BAD_CAST "true")) {
6168 if (elem->children != NULL) {
6169 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is not empty\n", elem->name, NULL);
6170 return (ctxt->err);
6171 }
6172 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
6173 (elemDecl->value != NULL)) {
6174 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_HAVEDEFAULT, "Empty element %s cannot get a fixed value\n", elem->name, NULL);
6175 return (ctxt->err);
6176 }
6177 }
Daniel Veillard4255d502002-04-16 15:50:10 +00006178 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006179 /* 3.3.4: 3.1 */
6180 if (nil != NULL) {
6181 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTNILLABLE, "Element %s with xs:nil but not nillable\n", elem->name, NULL);
6182 xmlFree(nil);
6183 return (ctxt->err);
6184 }
Daniel Veillard4255d502002-04-16 15:50:10 +00006185 }
6186
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006187 /* TODO 3.3.4: 4 if the element carries xs:type */
Daniel Veillard4255d502002-04-16 15:50:10 +00006188
6189 ctxt->type = elemDecl->subtypes;
6190 ctxt->node = elem->children;
6191 xmlSchemaValidateContent(ctxt, elem);
6192 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006193
6194 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006195}
6196
6197
6198/**
6199 * xmlSchemaValidateAttributes:
6200 * @ctxt: a schema validation context
6201 * @elem: an element
6202 * @attributes: the list of attribute declarations
6203 *
6204 * Validate the attributes of an element.
6205 *
6206 * Returns 0 if the element is schemas valid, a positive error code
6207 * number otherwise and -1 in case of internal or API error.
6208 */
6209static int
6210xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006211 xmlSchemaAttributePtr attributes)
6212{
Daniel Veillard4255d502002-04-16 15:50:10 +00006213 int i, ret;
6214 xmlAttrPtr attr;
6215 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00006216 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00006217
6218 if (attributes == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006219 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006220 while (attributes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006221 /*
6222 * Handle attribute groups
6223 */
6224 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
6225 group = (xmlSchemaAttributeGroupPtr) attributes;
6226 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
6227 attributes = group->next;
6228 continue;
6229 }
6230 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
6231 attr = ctxt->attr[i].attr;
6232 if (attr == NULL)
6233 continue;
6234 if (attributes->ref != NULL) {
6235 if (!xmlStrEqual(attr->name, attributes->ref))
6236 continue;
6237 if (attr->ns != NULL) {
6238 if ((attributes->refNs == NULL) ||
6239 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
6240 continue;
6241 } else if (attributes->refNs != NULL) {
6242 continue;
6243 }
6244 } else {
6245 if (!xmlStrEqual(attr->name, attributes->name))
6246 continue;
6247 /*
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006248 * handle the namespaces checks here
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006249 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006250 if (attr->ns == NULL) {
6251 /*
6252 * accept an unqualified attribute only if the declaration
6253 * is unqualified or if the schemas allowed it.
6254 */
6255 if ((attributes->targetNamespace != NULL) &&
6256 ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0))
6257 continue;
6258 } else {
6259 if (attributes->targetNamespace == NULL)
6260 continue;
6261 if (!xmlStrEqual(attributes->targetNamespace,
6262 attr->ns->href))
6263 continue;
6264 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006265 }
6266 ctxt->cur = (xmlNodePtr) attributes;
6267 if (attributes->subtypes == NULL) {
6268 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL);
6269 continue;
6270 }
6271 value = xmlNodeListGetString(elem->doc, attr->children, 1);
6272 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
6273 value);
6274 if (ret != 0) {
6275 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_ATTRINVALID, "attribute %s on %s does not match type\n", attr->name, elem->name);
6276 } else {
6277 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
6278 }
6279 if (value != NULL) {
6280 xmlFree(value);
6281 }
6282 }
6283 attributes = attributes->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00006284 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006285 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006286}
6287
6288/**
6289 * xmlSchemaValidateElement:
6290 * @ctxt: a schema validation context
6291 * @elem: an element
6292 *
6293 * Validate an element in a tree
6294 *
6295 * Returns 0 if the element is schemas valid, a positive error code
6296 * number otherwise and -1 in case of internal or API error.
6297 */
6298static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006299xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem)
6300{
Daniel Veillard4255d502002-04-16 15:50:10 +00006301 xmlSchemaElementPtr elemDecl;
6302 int ret, attrBase;
6303
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006304 if (elem->ns != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006305 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6306 elem->name, elem->ns->href, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006307 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006308 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6309 elem->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006310 }
6311 /*
6312 * special case whe elementFormDefault is unqualified for top-level elem.
6313 */
6314 if ((elemDecl == NULL) && (elem->ns != NULL) &&
6315 (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) &&
6316 (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) &&
6317 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6318 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6319 elem->name, NULL, NULL);
6320 }
6321
Daniel Veillard4255d502002-04-16 15:50:10 +00006322 /*
6323 * 3.3.4 : 1
6324 */
6325 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006326 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", elem->name, NULL);
6327 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006328 }
6329 if (elemDecl->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006330 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTYPE, "Element %s has no type\n", elem->name, NULL);
6331 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006332 }
6333 /*
6334 * Verify the attributes
6335 */
6336 attrBase = ctxt->attrBase;
6337 ctxt->attrBase = ctxt->attrNr;
6338 xmlSchemaRegisterAttributes(ctxt, elem->properties);
6339 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
6340 /*
6341 * Verify the element content recursively
6342 */
6343 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006344 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
6345 (xmlRegExecCallbacks)
6346 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00006347#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006348 xmlGenericError(xmlGenericErrorContext, "====> %s\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006349#endif
6350 }
6351 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006352 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006353 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006354#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006355 xmlGenericError(xmlGenericErrorContext,
6356 "====> %s : %d\n", elem->name, ret);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006357#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006358 if (ret == 0) {
6359 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
6360 } else if (ret < 0) {
6361 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006362#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006363 } else {
6364 xmlGenericError(xmlGenericErrorContext,
6365 "Element %s content check succeeded\n",
6366 elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006367
6368#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006369 }
6370 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00006371 }
6372 /*
6373 * Verify that all attributes were Schemas-validated
6374 */
6375 xmlSchemaCheckAttributes(ctxt, elem);
6376 ctxt->attrNr = ctxt->attrBase;
6377 ctxt->attrBase = attrBase;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006378
6379 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006380}
6381
6382/**
6383 * xmlSchemaValidateDocument:
6384 * @ctxt: a schema validation context
6385 * @doc: a parsed document tree
6386 *
6387 * Validate a document tree in memory.
6388 *
6389 * Returns 0 if the document is schemas valid, a positive error code
6390 * number otherwise and -1 in case of internal or API error.
6391 */
6392static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006393xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6394{
Daniel Veillard4255d502002-04-16 15:50:10 +00006395 xmlNodePtr root;
6396 xmlSchemaElementPtr elemDecl;
6397
6398 root = xmlDocGetRootElement(doc);
6399 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006400 xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, "document has no root\n", NULL, NULL);
6401 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006402 }
6403 if (root->ns != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006404 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6405 root->name, root->ns->href, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006406 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006407 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6408 root->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006409 /*
6410 * special case whe elementFormDefault is unqualified for top-level elem.
6411 */
6412 if ((elemDecl == NULL) && (root->ns != NULL) &&
6413 (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) &&
6414 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6415 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6416 root->name, NULL, NULL);
6417 }
6418
Daniel Veillard4255d502002-04-16 15:50:10 +00006419 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006420 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", root->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006421 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006422 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, "Root element %s not toplevel\n", root->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006423 }
6424 /*
6425 * Okay, start the recursive validation
6426 */
6427 xmlSchemaValidateElement(ctxt, root);
6428
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006429 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006430}
6431
6432/************************************************************************
6433 * *
6434 * SAX Validation code *
6435 * *
6436 ************************************************************************/
6437
6438/************************************************************************
6439 * *
6440 * Validation interfaces *
6441 * *
6442 ************************************************************************/
6443
6444/**
6445 * xmlSchemaNewValidCtxt:
6446 * @schema: a precompiled XML Schemas
6447 *
6448 * Create an XML Schemas validation context based on the given schema
6449 *
6450 * Returns the validation context or NULL in case of error
6451 */
6452xmlSchemaValidCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006453xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
6454{
Daniel Veillard4255d502002-04-16 15:50:10 +00006455 xmlSchemaValidCtxtPtr ret;
6456
6457 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
6458 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006459 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006460 return (NULL);
6461 }
6462 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
6463 ret->schema = schema;
6464 ret->attrNr = 0;
6465 ret->attrMax = 10;
6466 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006467 sizeof
6468 (xmlSchemaAttrState));
Daniel Veillard4255d502002-04-16 15:50:10 +00006469 if (ret->attr == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006470 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
6471 free(ret);
6472 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006473 }
6474 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
6475 return (ret);
6476}
6477
6478/**
6479 * xmlSchemaFreeValidCtxt:
6480 * @ctxt: the schema validation context
6481 *
6482 * Free the resources associated to the schema validation context
6483 */
6484void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006485xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
6486{
Daniel Veillard4255d502002-04-16 15:50:10 +00006487 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006488 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006489 if (ctxt->attr != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006490 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00006491 if (ctxt->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006492 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00006493 xmlFree(ctxt);
6494}
6495
6496/**
6497 * xmlSchemaSetValidErrors:
6498 * @ctxt: a schema validation context
6499 * @err: the error function
6500 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00006501 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00006502 *
6503 * Set the error and warning callback informations
6504 */
6505void
6506xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006507 xmlSchemaValidityErrorFunc err,
6508 xmlSchemaValidityWarningFunc warn, void *ctx)
6509{
Daniel Veillard4255d502002-04-16 15:50:10 +00006510 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006511 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006512 ctxt->error = err;
6513 ctxt->warning = warn;
6514 ctxt->userData = ctx;
6515}
6516
6517/**
6518 * xmlSchemaValidateDoc:
6519 * @ctxt: a schema validation context
6520 * @doc: a parsed document tree
6521 *
6522 * Validate a document tree in memory.
6523 *
6524 * Returns 0 if the document is schemas valid, a positive error code
6525 * number otherwise and -1 in case of internal or API error.
6526 */
6527int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006528xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6529{
Daniel Veillard4255d502002-04-16 15:50:10 +00006530 int ret;
6531
6532 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006533 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006534
6535 ctxt->doc = doc;
6536 ret = xmlSchemaValidateDocument(ctxt, doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006537 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00006538}
6539
6540/**
6541 * xmlSchemaValidateStream:
6542 * @ctxt: a schema validation context
6543 * @input: the input to use for reading the data
6544 * @enc: an optional encoding information
6545 * @sax: a SAX handler for the resulting events
6546 * @user_data: the context to provide to the SAX handler.
6547 *
6548 * Validate a document tree in memory.
6549 *
6550 * Returns 0 if the document is schemas valid, a positive error code
6551 * number otherwise and -1 in case of internal or API error.
6552 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006553int
Daniel Veillard4255d502002-04-16 15:50:10 +00006554xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006555 xmlParserInputBufferPtr input, xmlCharEncoding enc,
6556 xmlSAXHandlerPtr sax, void *user_data)
6557{
Daniel Veillard4255d502002-04-16 15:50:10 +00006558 if ((ctxt == NULL) || (input == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006559 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006560 ctxt->input = input;
6561 ctxt->enc = enc;
6562 ctxt->sax = sax;
6563 ctxt->user_data = user_data;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006564 TODO return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006565}
6566
6567#endif /* LIBXML_SCHEMAS_ENABLED */