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