blob: 91e53c649f1769c7e178a405b37d65559e27a94c [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemas.c : implementation of the XML Schema handling and
3 * schema validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
Daniel Veillard5a872412002-05-22 06:40:27 +000020#include <libxml/uri.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000021
22#include <libxml/xmlschemas.h>
23#include <libxml/schemasInternals.h>
24#include <libxml/xmlschemastypes.h>
25#include <libxml/xmlautomata.h>
26#include <libxml/xmlregexp.h>
Daniel Veillardbe9c6322003-11-22 20:37:51 +000027#include <libxml/dict.h>
Daniel Veillard4255d502002-04-16 15:50:10 +000028
Daniel Veillarda84c0b32003-06-02 16:58:46 +000029/* #define DEBUG 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000030
Daniel Veillard82bbbd42003-05-11 20:16:09 +000031/* #define DEBUG_CONTENT 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000032
Daniel Veillard82bbbd42003-05-11 20:16:09 +000033/* #define DEBUG_TYPE 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000034
Daniel Veillard118aed72002-09-24 14:13:13 +000035/* #define DEBUG_CONTENT_REGEXP 1 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000036
Daniel Veillard4255d502002-04-16 15:50:10 +000037/* #define DEBUG_AUTOMATA 1 */
38
39#define UNBOUNDED (1 << 30)
40#define TODO \
41 xmlGenericError(xmlGenericErrorContext, \
42 "Unimplemented block at %s:%d\n", \
43 __FILE__, __LINE__);
44
Daniel Veillard5a872412002-05-22 06:40:27 +000045#define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar *)"the default namespace"
46
Daniel Veillard4255d502002-04-16 15:50:10 +000047/*
48 * The XML Schemas namespaces
49 */
50static const xmlChar *xmlSchemaNs = (const xmlChar *)
51 "http://www.w3.org/2001/XMLSchema";
52
53static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
54 "http://www.w3.org/2001/XMLSchema-instance";
55
56#define IS_SCHEMA(node, type) \
57 ((node != NULL) && (node->ns != NULL) && \
58 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
59 (xmlStrEqual(node->ns->href, xmlSchemaNs)))
60
61#define XML_SCHEMAS_PARSE_ERROR 1
62
Daniel Veillardbd2904b2003-11-25 15:38:59 +000063#define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT
64
Daniel Veillard4255d502002-04-16 15:50:10 +000065struct _xmlSchemaParserCtxt {
Daniel Veillardd0c9c322003-10-10 00:49:42 +000066 void *userData; /* user specific data block */
67 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
68 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillarde19fc232002-04-22 16:01:24 +000069 xmlSchemaValidError err;
Daniel Veillardd0c9c322003-10-10 00:49:42 +000070 int nberrors;
Daniel Veillard659e71e2003-10-10 14:10:40 +000071 xmlStructuredErrorFunc serror;
Daniel Veillard4255d502002-04-16 15:50:10 +000072
Daniel Veillardbe9c6322003-11-22 20:37:51 +000073 xmlSchemaPtr topschema; /* The main schema */
74 xmlHashTablePtr namespaces; /* Hash table of namespaces to schemas */
75
Daniel Veillardd0c9c322003-10-10 00:49:42 +000076 xmlSchemaPtr schema; /* The schema in use */
Daniel Veillardbe9c6322003-11-22 20:37:51 +000077 const xmlChar *container; /* the current element, group, ... */
Daniel Veillard4255d502002-04-16 15:50:10 +000078 int counter;
79
Daniel Veillardbe9c6322003-11-22 20:37:51 +000080 const xmlChar *URL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +000081 xmlDocPtr doc;
Daniel Veillard4255d502002-04-16 15:50:10 +000082
Daniel Veillardd0c9c322003-10-10 00:49:42 +000083 const char *buffer;
84 int size;
Daniel Veillard6045c902002-10-09 21:13:59 +000085
Daniel Veillard4255d502002-04-16 15:50:10 +000086 /*
87 * Used to build complex element content models
88 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +000089 xmlAutomataPtr am;
Daniel Veillard4255d502002-04-16 15:50:10 +000090 xmlAutomataStatePtr start;
91 xmlAutomataStatePtr end;
92 xmlAutomataStatePtr state;
Daniel Veillardbe9c6322003-11-22 20:37:51 +000093
94 xmlDictPtr dict; /* dictionnary for interned string names */
Daniel Veillard4255d502002-04-16 15:50:10 +000095};
96
97
98#define XML_SCHEMAS_ATTR_UNKNOWN 1
99#define XML_SCHEMAS_ATTR_CHECKED 2
100
101typedef struct _xmlSchemaAttrState xmlSchemaAttrState;
102typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr;
103struct _xmlSchemaAttrState {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000104 xmlAttrPtr attr;
105 int state;
Daniel Veillard4255d502002-04-16 15:50:10 +0000106};
107
108/**
109 * xmlSchemaValidCtxt:
110 *
111 * A Schemas validation context
112 */
113
114struct _xmlSchemaValidCtxt {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000115 void *userData; /* user specific data block */
116 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */
117 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000118 xmlStructuredErrorFunc serror;
Daniel Veillard4255d502002-04-16 15:50:10 +0000119
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000120 xmlSchemaPtr schema; /* The schema in use */
121 xmlDocPtr doc;
Daniel Veillard4255d502002-04-16 15:50:10 +0000122 xmlParserInputBufferPtr input;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000123 xmlCharEncoding enc;
124 xmlSAXHandlerPtr sax;
125 void *user_data;
Daniel Veillard4255d502002-04-16 15:50:10 +0000126
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000127 xmlDocPtr myDoc;
128 int err;
129 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +0000130
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000131 xmlNodePtr node;
132 xmlNodePtr cur;
133 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +0000134
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000135 xmlRegExecCtxtPtr regexp;
136 xmlSchemaValPtr value;
Daniel Veillard4255d502002-04-16 15:50:10 +0000137
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000138 int attrNr;
139 int attrBase;
140 int attrMax;
141 xmlSchemaAttrStatePtr attr;
Daniel Veillard4255d502002-04-16 15:50:10 +0000142};
143
Daniel Veillard1d913862003-11-21 00:28:39 +0000144/*
145 * These are the entries in the schemas importSchemas hash table
146 */
147typedef struct _xmlSchemaImport xmlSchemaImport;
148typedef xmlSchemaImport *xmlSchemaImportPtr;
149struct _xmlSchemaImport {
150 const xmlChar *schemaLocation;
151 xmlSchemaPtr schema;
152};
Daniel Veillard4255d502002-04-16 15:50:10 +0000153
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000154/*
155 * These are the entries associated to includes in a schemas
156 */
157typedef struct _xmlSchemaInclude xmlSchemaInclude;
158typedef xmlSchemaInclude *xmlSchemaIncludePtr;
159struct _xmlSchemaInclude {
160 xmlSchemaIncludePtr next;
161
162 const xmlChar *schemaLocation;
163 xmlDocPtr doc;
164};
165
Daniel Veillard4255d502002-04-16 15:50:10 +0000166/************************************************************************
167 * *
168 * Some predeclarations *
169 * *
170 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000171static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
172 xmlSchemaTypePtr type,
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000173 const xmlChar * value);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000174
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000175static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt,
176 xmlSchemaPtr schema,
177 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000178/************************************************************************
179 * *
180 * Datatype error handlers *
181 * *
182 ************************************************************************/
183
184/**
185 * xmlSchemaPErrMemory:
186 * @node: a context node
187 * @extra: extra informations
188 *
189 * Handle an out of memory condition
190 */
191static void
192xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt,
193 const char *extra, xmlNodePtr node)
194{
195 if (ctxt != NULL)
196 ctxt->nberrors++;
197 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
198 extra);
199}
200
201/**
202 * xmlSchemaPErr:
203 * @ctxt: the parsing context
204 * @node: the context node
205 * @error: the error code
206 * @msg: the error message
207 * @str1: extra data
208 * @str2: extra data
209 *
210 * Handle a parser error
211 */
212static void
213xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error,
214 const char *msg, const xmlChar * str1, const xmlChar * str2)
215{
216 xmlGenericErrorFunc channel = NULL;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000217 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000218 void *data = NULL;
219
220 if (ctxt != NULL) {
221 ctxt->nberrors++;
222 channel = ctxt->error;
223 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000224 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000225 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000226 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000227 error, XML_ERR_ERROR, NULL, 0,
228 (const char *) str1, (const char *) str2, NULL, 0, 0,
229 msg, str1, str2);
230}
231
232/**
233 * xmlSchemaPErr2:
234 * @ctxt: the parsing context
235 * @node: the context node
236 * @node: the current child
237 * @error: the error code
238 * @msg: the error message
239 * @str1: extra data
240 * @str2: extra data
241 *
242 * Handle a parser error
243 */
244static void
245xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
246 xmlNodePtr child, int error,
247 const char *msg, const xmlChar * str1, const xmlChar * str2)
248{
249 if (child != NULL)
250 xmlSchemaPErr(ctxt, child, error, msg, str1, str2);
251 else
252 xmlSchemaPErr(ctxt, node, error, msg, str1, str2);
253}
254
255/**
256 * xmlSchemaVTypeErrMemory:
257 * @node: a context node
258 * @extra: extra informations
259 *
260 * Handle an out of memory condition
261 */
262static void
263xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt,
264 const char *extra, xmlNodePtr node)
265{
266 if (ctxt != NULL) {
267 ctxt->nberrors++;
268 ctxt->err = XML_SCHEMAS_ERR_INTERNAL;
269 }
270 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
271 extra);
272}
273
274/**
275 * xmlSchemaVErr3:
276 * @ctxt: the validation context
277 * @node: the context node
278 * @error: the error code
279 * @msg: the error message
280 * @str1: extra data
281 * @str2: extra data
282 * @str3: extra data
283 *
284 * Handle a validation error
285 */
286static void
287xmlSchemaVErr3(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
288 const char *msg, const xmlChar *str1, const xmlChar *str2,
289 const xmlChar *str3)
290{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000291 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000292 xmlGenericErrorFunc channel = NULL;
293 void *data = NULL;
294
295 if (ctxt != NULL) {
296 ctxt->nberrors++;
297 ctxt->err = error;
298 channel = ctxt->error;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000299 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000300 data = ctxt->userData;
301 }
302 /* reajust to global error numbers */
303 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000304 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000305 error, XML_ERR_ERROR, NULL, 0,
306 (const char *) str1, (const char *) str2,
307 (const char *) str3, 0, 0,
308 msg, str1, str2, str3);
309}
310/**
311 * xmlSchemaVErr:
312 * @ctxt: the validation context
313 * @node: the context node
314 * @error: the error code
315 * @msg: the error message
316 * @str1: extra data
317 * @str2: extra data
318 *
319 * Handle a validation error
320 */
321static void
322xmlSchemaVErr(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error,
323 const char *msg, const xmlChar * str1, const xmlChar * str2)
324{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000325 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000326 xmlGenericErrorFunc channel = NULL;
327 void *data = NULL;
328
329 if (ctxt != NULL) {
330 ctxt->nberrors++;
331 ctxt->err = error;
332 channel = ctxt->error;
333 data = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000334 schannel = ctxt->serror;
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000335 }
336 /* reajust to global error numbers */
337 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000338 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000339 error, XML_ERR_ERROR, NULL, 0,
340 (const char *) str1, (const char *) str2, NULL, 0, 0,
341 msg, str1, str2);
342}
Daniel Veillard4255d502002-04-16 15:50:10 +0000343
344/************************************************************************
345 * *
346 * Allocation functions *
347 * *
348 ************************************************************************/
349
350/**
351 * xmlSchemaNewSchema:
352 * @ctxt: a schema validation context (optional)
353 *
354 * Allocate a new Schema structure.
355 *
356 * Returns the newly allocated structure or NULL in case or error
357 */
358static xmlSchemaPtr
359xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
360{
361 xmlSchemaPtr ret;
362
363 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
364 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000365 xmlSchemaPErrMemory(ctxt, "allocating schema", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +0000366 return (NULL);
367 }
368 memset(ret, 0, sizeof(xmlSchema));
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000369 xmlDictReference(ctxt->dict);
370 ret->dict = ctxt->dict;
Daniel Veillard4255d502002-04-16 15:50:10 +0000371
372 return (ret);
373}
374
375/**
376 * xmlSchemaNewFacet:
Daniel Veillard4255d502002-04-16 15:50:10 +0000377 *
378 * Allocate a new Facet structure.
379 *
380 * Returns the newly allocated structure or NULL in case or error
381 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000382xmlSchemaFacetPtr
383xmlSchemaNewFacet(void)
Daniel Veillard4255d502002-04-16 15:50:10 +0000384{
385 xmlSchemaFacetPtr ret;
386
387 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
388 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +0000389 return (NULL);
390 }
391 memset(ret, 0, sizeof(xmlSchemaFacet));
392
393 return (ret);
394}
395
396/**
397 * xmlSchemaNewAnnot:
398 * @ctxt: a schema validation context (optional)
399 * @node: a node
400 *
401 * Allocate a new annotation structure.
402 *
403 * Returns the newly allocated structure or NULL in case or error
404 */
405static xmlSchemaAnnotPtr
406xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
407{
408 xmlSchemaAnnotPtr ret;
409
410 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
411 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000412 xmlSchemaPErrMemory(ctxt, "allocating annotation", node);
Daniel Veillard4255d502002-04-16 15:50:10 +0000413 return (NULL);
414 }
415 memset(ret, 0, sizeof(xmlSchemaAnnot));
416 ret->content = node;
417 return (ret);
418}
419
420/**
Daniel Veillardfdc91562002-07-01 21:52:03 +0000421 * xmlSchemaFreeAnnot:
422 * @annot: a schema type structure
423 *
424 * Deallocate a annotation structure
425 */
426static void
427xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
428{
429 if (annot == NULL)
430 return;
431 xmlFree(annot);
432}
433
434/**
Daniel Veillard1d913862003-11-21 00:28:39 +0000435 * xmlSchemaFreeImport:
436 * @import: a schema import structure
437 *
438 * Deallocate an import structure
439 */
440static void
441xmlSchemaFreeImport(xmlSchemaImportPtr import)
442{
443 if (import == NULL)
444 return;
445
446 xmlSchemaFree(import->schema);
Daniel Veillard1d913862003-11-21 00:28:39 +0000447 xmlFree(import);
448}
449
450/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000451 * xmlSchemaFreeInclude:
452 * @include: a schema include structure
453 *
454 * Deallocate an include structure
455 */
456static void
457xmlSchemaFreeInclude(xmlSchemaIncludePtr include)
458{
459 if (include == NULL)
460 return;
461
462 xmlFreeDoc(include->doc);
463 xmlFree(include);
464}
465
466/**
467 * xmlSchemaFreeIncludeList:
468 * @includes: a schema include list
469 *
470 * Deallocate an include structure
471 */
472static void
473xmlSchemaFreeIncludeList(xmlSchemaIncludePtr includes)
474{
475 xmlSchemaIncludePtr next;
476
477 while (includes != NULL) {
478 next = includes->next;
479 xmlSchemaFreeInclude(includes);
480 includes = next;
481 }
482}
483
484/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000485 * xmlSchemaFreeNotation:
486 * @schema: a schema notation structure
487 *
488 * Deallocate a Schema Notation structure.
489 */
490static void
491xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
492{
493 if (nota == NULL)
494 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000495 xmlFree(nota);
496}
497
498/**
499 * xmlSchemaFreeAttribute:
500 * @schema: a schema attribute structure
501 *
502 * Deallocate a Schema Attribute structure.
503 */
504static void
505xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
506{
507 if (attr == NULL)
508 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000509 xmlFree(attr);
510}
511
512/**
513 * xmlSchemaFreeAttributeGroup:
514 * @schema: a schema attribute group structure
515 *
516 * Deallocate a Schema Attribute Group structure.
517 */
518static void
519xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr)
520{
521 if (attr == NULL)
522 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000523 xmlFree(attr);
524}
525
526/**
527 * xmlSchemaFreeElement:
528 * @schema: a schema element structure
529 *
530 * Deallocate a Schema Element structure.
531 */
532static void
533xmlSchemaFreeElement(xmlSchemaElementPtr elem)
534{
535 if (elem == NULL)
536 return;
Daniel Veillard32370232002-10-16 14:08:14 +0000537 if (elem->annot != NULL)
538 xmlSchemaFreeAnnot(elem->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000539 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000540 xmlRegFreeRegexp(elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +0000541 xmlFree(elem);
542}
543
544/**
545 * xmlSchemaFreeFacet:
546 * @facet: a schema facet structure
547 *
548 * Deallocate a Schema Facet structure.
549 */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000550void
Daniel Veillard4255d502002-04-16 15:50:10 +0000551xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
552{
553 if (facet == NULL)
554 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000555 if (facet->val != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000556 xmlSchemaFreeValue(facet->val);
Daniel Veillard4255d502002-04-16 15:50:10 +0000557 if (facet->regexp != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000558 xmlRegFreeRegexp(facet->regexp);
Daniel Veillardfdc91562002-07-01 21:52:03 +0000559 if (facet->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000560 xmlSchemaFreeAnnot(facet->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000561 xmlFree(facet);
562}
563
564/**
565 * xmlSchemaFreeType:
566 * @type: a schema type structure
567 *
568 * Deallocate a Schema Type structure.
569 */
570void
571xmlSchemaFreeType(xmlSchemaTypePtr type)
572{
573 if (type == NULL)
574 return;
Daniel Veillard4255d502002-04-16 15:50:10 +0000575 if (type->annot != NULL)
Daniel Veillard32370232002-10-16 14:08:14 +0000576 xmlSchemaFreeAnnot(type->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000577 if (type->facets != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000578 xmlSchemaFacetPtr facet, next;
Daniel Veillard4255d502002-04-16 15:50:10 +0000579
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000580 facet = type->facets;
581 while (facet != NULL) {
582 next = facet->next;
583 xmlSchemaFreeFacet(facet);
584 facet = next;
585 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000586 }
587 xmlFree(type);
588}
589
590/**
Daniel Veillard4255d502002-04-16 15:50:10 +0000591 * xmlSchemaFree:
592 * @schema: a schema structure
593 *
594 * Deallocate a Schema structure.
595 */
596void
597xmlSchemaFree(xmlSchemaPtr schema)
598{
599 if (schema == NULL)
600 return;
601
Daniel Veillard4255d502002-04-16 15:50:10 +0000602 if (schema->notaDecl != NULL)
603 xmlHashFree(schema->notaDecl,
604 (xmlHashDeallocator) xmlSchemaFreeNotation);
605 if (schema->attrDecl != NULL)
606 xmlHashFree(schema->attrDecl,
607 (xmlHashDeallocator) xmlSchemaFreeAttribute);
608 if (schema->attrgrpDecl != NULL)
609 xmlHashFree(schema->attrgrpDecl,
610 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup);
611 if (schema->elemDecl != NULL)
612 xmlHashFree(schema->elemDecl,
613 (xmlHashDeallocator) xmlSchemaFreeElement);
614 if (schema->typeDecl != NULL)
615 xmlHashFree(schema->typeDecl,
616 (xmlHashDeallocator) xmlSchemaFreeType);
Daniel Veillarda84c0b32003-06-02 16:58:46 +0000617 if (schema->groupDecl != NULL)
618 xmlHashFree(schema->groupDecl,
619 (xmlHashDeallocator) xmlSchemaFreeType);
Daniel Veillard1d913862003-11-21 00:28:39 +0000620 if (schema->schemasImports != NULL)
621 xmlHashFree(schema->schemasImports,
622 (xmlHashDeallocator) xmlSchemaFreeImport);
Daniel Veillardbd2904b2003-11-25 15:38:59 +0000623 if (schema->includes != NULL) {
624 xmlSchemaFreeIncludeList((xmlSchemaIncludePtr) schema->includes);
625 }
Daniel Veillard4255d502002-04-16 15:50:10 +0000626 if (schema->annot != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000627 xmlSchemaFreeAnnot(schema->annot);
Daniel Veillard4255d502002-04-16 15:50:10 +0000628 if (schema->doc != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000629 xmlFreeDoc(schema->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000630 xmlDictFree(schema->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +0000631
632 xmlFree(schema);
633}
634
635/************************************************************************
636 * *
Daniel Veillard4255d502002-04-16 15:50:10 +0000637 * Debug functions *
638 * *
639 ************************************************************************/
640
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000641#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000642
Daniel Veillard4255d502002-04-16 15:50:10 +0000643/**
644 * xmlSchemaElementDump:
645 * @elem: an element
646 * @output: the file output
647 *
648 * Dump the element
649 */
650static void
651xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000652 const xmlChar * name ATTRIBUTE_UNUSED,
653 const xmlChar * context ATTRIBUTE_UNUSED,
654 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +0000655{
656 if (elem == NULL)
657 return;
658
659 fprintf(output, "Element ");
660 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000661 fprintf(output, "toplevel ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000662 fprintf(output, ": %s ", elem->name);
663 if (namespace != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000664 fprintf(output, "namespace '%s' ", namespace);
665
Daniel Veillard4255d502002-04-16 15:50:10 +0000666 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000667 fprintf(output, "nillable ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000668 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000669 fprintf(output, "global ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000670 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000671 fprintf(output, "default ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000672 if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000673 fprintf(output, "fixed ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000674 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000675 fprintf(output, "abstract ");
Daniel Veillard4255d502002-04-16 15:50:10 +0000676 if (elem->flags & XML_SCHEMAS_ELEM_REF)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000677 fprintf(output, "ref '%s' ", elem->ref);
Daniel Veillard4255d502002-04-16 15:50:10 +0000678 if (elem->id != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000679 fprintf(output, "id '%s' ", elem->id);
Daniel Veillard4255d502002-04-16 15:50:10 +0000680 fprintf(output, "\n");
681 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000682 fprintf(output, " ");
683 if (elem->minOccurs != 1)
684 fprintf(output, "min: %d ", elem->minOccurs);
685 if (elem->maxOccurs >= UNBOUNDED)
686 fprintf(output, "max: unbounded\n");
687 else if (elem->maxOccurs != 1)
688 fprintf(output, "max: %d\n", elem->maxOccurs);
689 else
690 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000691 }
692 if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000693 fprintf(output, " type: %s", elem->namedType);
694 if (elem->namedTypeNs != NULL)
695 fprintf(output, " ns %s\n", elem->namedTypeNs);
696 else
697 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000698 }
699 if (elem->substGroup != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000700 fprintf(output, " substitutionGroup: %s", elem->substGroup);
701 if (elem->substGroupNs != NULL)
702 fprintf(output, " ns %s\n", elem->substGroupNs);
703 else
704 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000705 }
706 if (elem->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000707 fprintf(output, " default: %s", elem->value);
Daniel Veillard4255d502002-04-16 15:50:10 +0000708}
709
710/**
711 * xmlSchemaAnnotDump:
712 * @output: the file output
713 * @annot: a annotation
714 *
715 * Dump the annotation
716 */
717static void
718xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
719{
720 xmlChar *content;
721
722 if (annot == NULL)
723 return;
724
725 content = xmlNodeGetContent(annot->content);
726 if (content != NULL) {
727 fprintf(output, " Annot: %s\n", content);
728 xmlFree(content);
729 } else
730 fprintf(output, " Annot: empty\n");
731}
732
733/**
734 * xmlSchemaTypeDump:
735 * @output: the file output
736 * @type: a type structure
737 *
738 * Dump a SchemaType structure
739 */
740static void
741xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
742{
743 if (type == NULL) {
744 fprintf(output, "Type: NULL\n");
745 return;
746 }
747 fprintf(output, "Type: ");
748 if (type->name != NULL)
749 fprintf(output, "%s, ", type->name);
750 else
751 fprintf(output, "no name");
752 switch (type->type) {
753 case XML_SCHEMA_TYPE_BASIC:
754 fprintf(output, "basic ");
755 break;
756 case XML_SCHEMA_TYPE_SIMPLE:
757 fprintf(output, "simple ");
758 break;
759 case XML_SCHEMA_TYPE_COMPLEX:
760 fprintf(output, "complex ");
761 break;
762 case XML_SCHEMA_TYPE_SEQUENCE:
763 fprintf(output, "sequence ");
764 break;
765 case XML_SCHEMA_TYPE_CHOICE:
766 fprintf(output, "choice ");
767 break;
768 case XML_SCHEMA_TYPE_ALL:
769 fprintf(output, "all ");
770 break;
771 case XML_SCHEMA_TYPE_UR:
772 fprintf(output, "ur ");
773 break;
774 case XML_SCHEMA_TYPE_RESTRICTION:
775 fprintf(output, "restriction ");
776 break;
777 case XML_SCHEMA_TYPE_EXTENSION:
778 fprintf(output, "extension ");
779 break;
780 default:
781 fprintf(output, "unknowntype%d ", type->type);
782 break;
783 }
784 if (type->base != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000785 fprintf(output, "base %s, ", type->base);
Daniel Veillard4255d502002-04-16 15:50:10 +0000786 }
787 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000788 case XML_SCHEMA_CONTENT_UNKNOWN:
789 fprintf(output, "unknown ");
790 break;
791 case XML_SCHEMA_CONTENT_EMPTY:
792 fprintf(output, "empty ");
793 break;
794 case XML_SCHEMA_CONTENT_ELEMENTS:
795 fprintf(output, "element ");
796 break;
797 case XML_SCHEMA_CONTENT_MIXED:
798 fprintf(output, "mixed ");
799 break;
800 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
801 fprintf(output, "mixed_or_elems ");
802 break;
803 case XML_SCHEMA_CONTENT_BASIC:
804 fprintf(output, "basic ");
805 break;
806 case XML_SCHEMA_CONTENT_SIMPLE:
807 fprintf(output, "simple ");
808 break;
809 case XML_SCHEMA_CONTENT_ANY:
810 fprintf(output, "any ");
811 break;
Daniel Veillard4255d502002-04-16 15:50:10 +0000812 }
813 fprintf(output, "\n");
814 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000815 fprintf(output, " ");
816 if (type->minOccurs != 1)
817 fprintf(output, "min: %d ", type->minOccurs);
818 if (type->maxOccurs >= UNBOUNDED)
819 fprintf(output, "max: unbounded\n");
820 else if (type->maxOccurs != 1)
821 fprintf(output, "max: %d\n", type->maxOccurs);
822 else
823 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000824 }
825 if (type->annot != NULL)
826 xmlSchemaAnnotDump(output, type->annot);
827 if (type->subtypes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000828 xmlSchemaTypePtr sub = type->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +0000829
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000830 fprintf(output, " subtypes: ");
831 while (sub != NULL) {
832 fprintf(output, "%s ", sub->name);
833 sub = sub->next;
834 }
835 fprintf(output, "\n");
Daniel Veillard4255d502002-04-16 15:50:10 +0000836 }
837
838}
839
840/**
841 * xmlSchemaDump:
842 * @output: the file output
843 * @schema: a schema structure
844 *
845 * Dump a Schema structure.
846 */
847void
848xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
849{
850 if (schema == NULL) {
851 fprintf(output, "Schemas: NULL\n");
852 return;
853 }
854 fprintf(output, "Schemas: ");
855 if (schema->name != NULL)
856 fprintf(output, "%s, ", schema->name);
857 else
858 fprintf(output, "no name, ");
859 if (schema->targetNamespace != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000860 fprintf(output, "%s", (const char *) schema->targetNamespace);
Daniel Veillard4255d502002-04-16 15:50:10 +0000861 else
862 fprintf(output, "no target namespace");
863 fprintf(output, "\n");
864 if (schema->annot != NULL)
865 xmlSchemaAnnotDump(output, schema->annot);
866
867 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump,
868 output);
869 xmlHashScanFull(schema->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +0000870 (xmlHashScannerFull) xmlSchemaElementDump, output);
Daniel Veillard4255d502002-04-16 15:50:10 +0000871}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000872#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard4255d502002-04-16 15:50:10 +0000873
874/************************************************************************
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000875 * *
876 * Utilities *
877 * *
878 ************************************************************************/
879/**
880 * numberedString:
881 * @prefix: the string prefix
882 * @number: the number
883 *
884 * Build a new numbered string
885 *
886 * Returns the new string
887 */
888
889/**
890 * xmlSchemaGetProp:
891 * @ctxt: the parser context
892 * @node: the node
893 * @name: the property name
894 *
895 * Read a attribute value and internalize the string
896 *
897 * Returns the string or NULL if not present.
898 */
899static const xmlChar *
900xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
901 const char *name)
902{
903 xmlChar *val;
904 const xmlChar *ret;
905
906 val = xmlGetProp(node, BAD_CAST name);
907 if (val == NULL)
908 return(NULL);
909 ret = xmlDictLookup(ctxt->dict, val, -1);
910 xmlFree(val);
911 return(ret);
912}
913
914/**
915 * xmlSchemaGetNamespace:
916 * @ctxt: the parser context
917 * @schema: the schemas containing the declaration
918 * @node: the node
919 * @qname: the QName to analyze
920 *
921 * Find the namespace name for the given declaration.
922 *
923 * Returns the local name for that declaration, as well as the namespace name
924 */
925static const xmlChar *
926xmlSchemaGetNamespace(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
927 xmlNodePtr node, const xmlChar *qname,
928 const xmlChar **namespace) {
929 int len;
930 const xmlChar *name, *prefix, *def = NULL;
931 xmlNsPtr ns;
932
933 *namespace = NULL;
934
935 if (xmlStrEqual(node->name, BAD_CAST "element") ||
936 xmlStrEqual(node->name, BAD_CAST "attribute") ||
937 xmlStrEqual(node->name, BAD_CAST "simpleType") ||
938 xmlStrEqual(node->name, BAD_CAST "complexType")) {
939 def = xmlSchemaGetProp(ctxt, node, "targetNamespace");
940 }
941
942 qname = xmlDictLookup(ctxt->dict, qname, -1); /* intern the string */
943 name = xmlSplitQName3(qname, &len);
944 if (name == NULL) {
945 if (def == NULL) {
946 if (xmlStrEqual(node->name, BAD_CAST "element")) {
947 if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
948 *namespace = schema->targetNamespace;
949 } else if (xmlStrEqual(node->name, BAD_CAST "attribute")) {
950 if (schema->flags & XML_SCHEMAS_QUALIF_ATTR)
951 *namespace = schema->targetNamespace;
952 } else if ((xmlStrEqual(node->name, BAD_CAST "simpleType")) ||
953 (xmlStrEqual(node->name, BAD_CAST "complexType"))) {
954 *namespace = schema->targetNamespace;
955 }
956 } else {
957 *namespace = def;
958 }
959 return(qname);
960 }
961 name = xmlDictLookup(ctxt->dict, name, -1);
962 prefix = xmlDictLookup(ctxt->dict, qname, len);
963 if (def != NULL) {
964 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_DEF_AND_PREFIX,
965 "%s: presence of both prefix %s and targetNamespace\n",
966 node->name, prefix);
967 }
968 ns = xmlSearchNs(node->doc, node, prefix);
969 if (ns == NULL) {
970 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
971 "%s: the QName prefix %s is undefined\n",
972 node->name, prefix);
973 return(name);
974 }
975 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
976 return(name);
977}
978
979/************************************************************************
Daniel Veillard4255d502002-04-16 15:50:10 +0000980 * *
981 * Parsing functions *
982 * *
983 ************************************************************************/
984
985/**
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000986 * xmlSchemaGetElem:
987 * @schema: the schemas context
988 * @name: the element name
989 * @ns: the element namespace
Daniel Veillardf2a12832003-11-24 13:04:35 +0000990 * @level: how deep is the request
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000991 *
992 * Lookup a an element in the schemas or the accessible schemas
993 *
994 * Returns the element definition or NULL if not found.
995 */
996static xmlSchemaElementPtr
997xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardf2a12832003-11-24 13:04:35 +0000998 const xmlChar * namespace, int level)
Daniel Veillardbe9c6322003-11-22 20:37:51 +0000999{
1000 xmlSchemaElementPtr ret;
Daniel Veillardf2a12832003-11-24 13:04:35 +00001001 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001002
1003 if ((name == NULL) || (schema == NULL))
1004 return (NULL);
1005
1006 if (namespace == NULL) {
1007 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001008 if ((ret != NULL) &&
1009 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001010 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001011 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001012 } else if ((schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0) {
1013 if (xmlStrEqual(namespace, schema->targetNamespace))
1014 ret = xmlHashLookup2(schema->elemDecl, name, NULL);
1015 else
1016 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001017 if ((ret != NULL) &&
1018 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001019 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001020 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001021 } else {
1022 ret = xmlHashLookup2(schema->elemDecl, name, namespace);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001023 if ((ret != NULL) &&
1024 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001025 return (ret);
Daniel Veillardf2a12832003-11-24 13:04:35 +00001026 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001027 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00001028 if (level > 0)
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001029 import = xmlHashLookup(schema->schemasImports, namespace);
1030 if (import != NULL)
Daniel Veillardf2a12832003-11-24 13:04:35 +00001031 ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001032#ifdef DEBUG
1033 if (ret == NULL) {
1034 if (namespace == NULL)
1035 fprintf(stderr, "Unable to lookup type %s", name);
1036 else
1037 fprintf(stderr, "Unable to lookup type %s:%s", name,
1038 namespace);
1039 }
1040#endif
1041 return (ret);
1042}
1043
1044/**
Daniel Veillard4255d502002-04-16 15:50:10 +00001045 * xmlSchemaGetType:
1046 * @schema: the schemas context
1047 * @name: the type name
1048 * @ns: the type namespace
1049 *
1050 * Lookup a type in the schemas or the predefined types
1051 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001052 * Returns the group definition or NULL if not found.
Daniel Veillard4255d502002-04-16 15:50:10 +00001053 */
1054static xmlSchemaTypePtr
1055xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001056 const xmlChar * namespace)
1057{
Daniel Veillard4255d502002-04-16 15:50:10 +00001058 xmlSchemaTypePtr ret;
Daniel Veillard1d913862003-11-21 00:28:39 +00001059 xmlSchemaImportPtr import;
Daniel Veillard4255d502002-04-16 15:50:10 +00001060
1061 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001062 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001063 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001064 ret = xmlHashLookup2(schema->typeDecl, name, namespace);
1065 if (ret != NULL)
1066 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001067 }
1068 ret = xmlSchemaGetPredefinedType(name, namespace);
Daniel Veillard1d913862003-11-21 00:28:39 +00001069 if (ret != NULL)
1070 return (ret);
1071 import = xmlHashLookup(schema->schemasImports, namespace);
1072 if (import != NULL)
1073 ret = xmlSchemaGetType(import->schema, name, namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001074#ifdef DEBUG
1075 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001076 if (namespace == NULL)
1077 fprintf(stderr, "Unable to lookup type %s", name);
1078 else
1079 fprintf(stderr, "Unable to lookup type %s:%s", name,
1080 namespace);
Daniel Veillard4255d502002-04-16 15:50:10 +00001081 }
1082#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001083 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001084}
1085
1086/************************************************************************
1087 * *
1088 * Parsing functions *
1089 * *
1090 ************************************************************************/
1091
1092#define IS_BLANK_NODE(n) \
1093 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content)))
1094
1095/**
1096 * xmlSchemaIsBlank:
1097 * @str: a string
1098 *
1099 * Check if a string is ignorable
1100 *
1101 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
1102 */
1103static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001104xmlSchemaIsBlank(xmlChar * str)
1105{
Daniel Veillard4255d502002-04-16 15:50:10 +00001106 if (str == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001107 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001108 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00001109 if (!(IS_BLANK_CH(*str)))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001110 return (0);
1111 str++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001112 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001113 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001114}
1115
1116/**
1117 * xmlSchemaAddNotation:
1118 * @ctxt: a schema validation context
1119 * @schema: the schema being built
1120 * @name: the item name
1121 *
1122 * Add an XML schema Attrribute declaration
1123 * *WARNING* this interface is highly subject to change
1124 *
1125 * Returns the new struture or NULL in case of error
1126 */
1127static xmlSchemaNotationPtr
1128xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001129 const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001130{
1131 xmlSchemaNotationPtr ret = NULL;
1132 int val;
1133
1134 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1135 return (NULL);
1136
1137 if (schema->notaDecl == NULL)
1138 schema->notaDecl = xmlHashCreate(10);
1139 if (schema->notaDecl == NULL)
1140 return (NULL);
1141
1142 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
1143 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001144 xmlSchemaPErrMemory(ctxt, "add annotation", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001145 return (NULL);
1146 }
1147 memset(ret, 0, sizeof(xmlSchemaNotation));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001148 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001149 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace,
1150 ret);
1151 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001152 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1153 XML_SCHEMAP_REDEFINED_NOTATION,
1154 "Notation %s already defined\n",
1155 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001156 xmlFree(ret);
1157 return (NULL);
1158 }
1159 return (ret);
1160}
1161
1162
1163/**
1164 * xmlSchemaAddAttribute:
1165 * @ctxt: a schema validation context
1166 * @schema: the schema being built
1167 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001168 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001169 *
1170 * Add an XML schema Attrribute declaration
1171 * *WARNING* this interface is highly subject to change
1172 *
1173 * Returns the new struture or NULL in case of error
1174 */
1175static xmlSchemaAttributePtr
1176xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001177 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001178{
1179 xmlSchemaAttributePtr ret = NULL;
1180 int val;
1181
1182 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1183 return (NULL);
1184
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001185#ifdef DEBUG
1186 fprintf(stderr, "Adding attribute %s\n", name);
1187 if (namespace != NULL)
1188 fprintf(stderr, " target namespace %s\n", namespace);
1189#endif
1190
Daniel Veillard4255d502002-04-16 15:50:10 +00001191 if (schema->attrDecl == NULL)
1192 schema->attrDecl = xmlHashCreate(10);
1193 if (schema->attrDecl == NULL)
1194 return (NULL);
1195
1196 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
1197 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001198 xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001199 return (NULL);
1200 }
1201 memset(ret, 0, sizeof(xmlSchemaAttribute));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001202 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1203 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001204 val = xmlHashAddEntry3(schema->attrDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001205 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001206 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001207 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1208 XML_SCHEMAP_REDEFINED_ATTR,
1209 "Attribute %s already defined\n",
1210 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001211 xmlFree(ret);
1212 return (NULL);
1213 }
1214 return (ret);
1215}
1216
1217/**
1218 * xmlSchemaAddAttributeGroup:
1219 * @ctxt: a schema validation context
1220 * @schema: the schema being built
1221 * @name: the item name
1222 *
1223 * Add an XML schema Attrribute Group declaration
1224 *
1225 * Returns the new struture or NULL in case of error
1226 */
1227static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001228xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1229 xmlSchemaPtr schema, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00001230{
1231 xmlSchemaAttributeGroupPtr ret = NULL;
1232 int val;
1233
1234 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1235 return (NULL);
1236
1237 if (schema->attrgrpDecl == NULL)
1238 schema->attrgrpDecl = xmlHashCreate(10);
1239 if (schema->attrgrpDecl == NULL)
1240 return (NULL);
1241
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001242 ret =
1243 (xmlSchemaAttributeGroupPtr)
1244 xmlMalloc(sizeof(xmlSchemaAttributeGroup));
Daniel Veillard4255d502002-04-16 15:50:10 +00001245 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001246 xmlSchemaPErrMemory(ctxt, "allocating attribute group", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001247 return (NULL);
1248 }
1249 memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001250 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001251 val = xmlHashAddEntry3(schema->attrgrpDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001252 schema->targetNamespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001253 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001254 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1255 XML_SCHEMAP_REDEFINED_ATTRGROUP,
1256 "Attribute group %s already defined\n",
1257 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001258 xmlFree(ret);
1259 return (NULL);
1260 }
1261 return (ret);
1262}
1263
1264/**
1265 * xmlSchemaAddElement:
1266 * @ctxt: a schema validation context
1267 * @schema: the schema being built
1268 * @name: the type name
1269 * @namespace: the type namespace
1270 *
1271 * Add an XML schema Element declaration
1272 * *WARNING* this interface is highly subject to change
1273 *
1274 * Returns the new struture or NULL in case of error
1275 */
1276static xmlSchemaElementPtr
1277xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1278 const xmlChar * name, const xmlChar * namespace)
1279{
1280 xmlSchemaElementPtr ret = NULL;
1281 int val;
1282
1283 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1284 return (NULL);
1285
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001286#ifdef DEBUG
1287 fprintf(stderr, "Adding element %s\n", name);
1288 if (namespace != NULL)
1289 fprintf(stderr, " target namespace %s\n", namespace);
1290#endif
1291
Daniel Veillard4255d502002-04-16 15:50:10 +00001292 if (schema->elemDecl == NULL)
1293 schema->elemDecl = xmlHashCreate(10);
1294 if (schema->elemDecl == NULL)
1295 return (NULL);
1296
1297 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
1298 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001299 xmlSchemaPErrMemory(ctxt, "allocating element", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001300 return (NULL);
1301 }
1302 memset(ret, 0, sizeof(xmlSchemaElement));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001303 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1304 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001305 val = xmlHashAddEntry3(schema->elemDecl, name,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001306 namespace, ctxt->container, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001307 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001308 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00001309
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001310 snprintf(buf, 99, "privatieelem %d", ctxt->counter++ + 1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001311 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf,
1312 namespace, ret);
1313 if (val != 0) {
1314 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1315 XML_SCHEMAP_REDEFINED_ELEMENT,
1316 "Element %s already defined\n",
1317 name, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001318 xmlFree(ret);
1319 return (NULL);
1320 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001321 }
1322 return (ret);
1323}
1324
1325/**
1326 * xmlSchemaAddType:
1327 * @ctxt: a schema validation context
1328 * @schema: the schema being built
1329 * @name: the item name
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001330 * @namespace: the namespace
Daniel Veillard4255d502002-04-16 15:50:10 +00001331 *
1332 * Add an XML schema Simple Type definition
1333 * *WARNING* this interface is highly subject to change
1334 *
1335 * Returns the new struture or NULL in case of error
1336 */
1337static xmlSchemaTypePtr
1338xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001339 const xmlChar * name, const xmlChar * namespace)
Daniel Veillard4255d502002-04-16 15:50:10 +00001340{
1341 xmlSchemaTypePtr ret = NULL;
1342 int val;
1343
1344 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1345 return (NULL);
1346
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001347#ifdef DEBUG
1348 fprintf(stderr, "Adding type %s\n", name);
1349 if (namespace != NULL)
1350 fprintf(stderr, " target namespace %s\n", namespace);
1351#endif
1352
Daniel Veillard4255d502002-04-16 15:50:10 +00001353 if (schema->typeDecl == NULL)
1354 schema->typeDecl = xmlHashCreate(10);
1355 if (schema->typeDecl == NULL)
1356 return (NULL);
1357
1358 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1359 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001360 xmlSchemaPErrMemory(ctxt, "allocating type", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001361 return (NULL);
1362 }
1363 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001364 ret->name = xmlDictLookup(ctxt->dict, name, -1);
1365 val = xmlHashAddEntry2(schema->typeDecl, name, namespace, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001366 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001367 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1368 XML_SCHEMAP_REDEFINED_TYPE,
1369 "Type %s already defined\n",
1370 name, NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001371 xmlFree(ret);
1372 return (NULL);
1373 }
1374 ret->minOccurs = 1;
1375 ret->maxOccurs = 1;
1376
1377 return (ret);
1378}
1379
1380/**
1381 * xmlSchemaAddGroup:
1382 * @ctxt: a schema validation context
1383 * @schema: the schema being built
1384 * @name: the group name
1385 *
1386 * Add an XML schema Group definition
1387 *
1388 * Returns the new struture or NULL in case of error
1389 */
1390static xmlSchemaTypePtr
1391xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001392 const xmlChar * name)
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001393{
1394 xmlSchemaTypePtr ret = NULL;
1395 int val;
1396
1397 if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
1398 return (NULL);
1399
1400 if (schema->groupDecl == NULL)
1401 schema->groupDecl = xmlHashCreate(10);
1402 if (schema->groupDecl == NULL)
1403 return (NULL);
1404
1405 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
1406 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001407 xmlSchemaPErrMemory(ctxt, "adding group", NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001408 return (NULL);
1409 }
1410 memset(ret, 0, sizeof(xmlSchemaType));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001411 ret->name = xmlDictLookup(ctxt->dict, name, -1);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001412 val =
1413 xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace,
1414 ret);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00001415 if (val != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001416 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc,
1417 XML_SCHEMAP_REDEFINED_GROUP,
1418 "Group %s already defined\n",
1419 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001420 xmlFree(ret);
1421 return (NULL);
1422 }
1423 ret->minOccurs = 1;
1424 ret->maxOccurs = 1;
1425
1426 return (ret);
1427}
1428
1429/************************************************************************
1430 * *
1431 * Utilities for parsing *
1432 * *
1433 ************************************************************************/
1434
1435/**
1436 * xmlGetQNameProp:
1437 * @ctxt: a schema validation context
1438 * @node: a subtree containing XML Schema informations
1439 * @name: the attribute name
1440 * @namespace: the result namespace if any
1441 *
1442 * Extract a QName Attribute value
1443 *
1444 * Returns the NCName or NULL if not found, and also update @namespace
1445 * with the namespace URI
1446 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001447static const xmlChar *
Daniel Veillard4255d502002-04-16 15:50:10 +00001448xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001449 const char *name, const xmlChar ** namespace)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001450{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001451 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001452 xmlNsPtr ns;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001453 const xmlChar *ret, *prefix;
1454 int len;
Daniel Veillard4255d502002-04-16 15:50:10 +00001455
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001456 *namespace = NULL;
1457 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001458 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001459 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001460
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001461 ret = xmlSplitQName3(val, &len);
1462 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001463 return (val);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001464 }
1465 ret = xmlDictLookup(ctxt->dict, ret, -1);
1466 prefix = xmlDictLookup(ctxt->dict, val, len);
Daniel Veillard4255d502002-04-16 15:50:10 +00001467
1468 ns = xmlSearchNs(node->doc, node, prefix);
1469 if (ns == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001470 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED,
1471 "Attribute %s: the QName prefix %s is undefined\n",
1472 (const xmlChar *) name, prefix);
Daniel Veillard4255d502002-04-16 15:50:10 +00001473 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001474 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001475 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001476 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001477}
1478
1479/**
1480 * xmlGetMaxOccurs:
1481 * @ctxt: a schema validation context
1482 * @node: a subtree containing XML Schema informations
1483 *
1484 * Get the maxOccurs property
1485 *
1486 * Returns the default if not found, or the value
1487 */
1488static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001489xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1490{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001491 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001492 int ret = 0;
1493
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001494 val = xmlSchemaGetProp(ctxt, node, "maxOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001495 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001496 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001497
1498 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001499 return (UNBOUNDED); /* encoding it with -1 might be another option */
Daniel Veillard4255d502002-04-16 15:50:10 +00001500 }
1501
1502 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001503 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001504 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001505 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001506 ret = ret * 10 + (*cur - '0');
1507 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001508 }
William M. Brack76e95df2003-10-18 16:20:14 +00001509 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001510 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001511 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001512 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS,
1513 "invalid value for maxOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001514 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001515 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001516 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001517}
1518
1519/**
1520 * xmlGetMinOccurs:
1521 * @ctxt: a schema validation context
1522 * @node: a subtree containing XML Schema informations
1523 *
1524 * Get the minOccurs property
1525 *
1526 * Returns the default if not found, or the value
1527 */
1528static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001529xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
1530{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001531 const xmlChar *val, *cur;
Daniel Veillard4255d502002-04-16 15:50:10 +00001532 int ret = 0;
1533
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001534 val = xmlSchemaGetProp(ctxt, node, "minOccurs");
Daniel Veillard4255d502002-04-16 15:50:10 +00001535 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001536 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001537
1538 cur = val;
William M. Brack76e95df2003-10-18 16:20:14 +00001539 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001540 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001541 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001542 ret = ret * 10 + (*cur - '0');
1543 cur++;
Daniel Veillard4255d502002-04-16 15:50:10 +00001544 }
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 if (*cur != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001548 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS,
1549 "invalid value for minOccurs: %s\n", val, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001550 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00001551 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001552 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00001553}
1554
1555/**
1556 * xmlGetBooleanProp:
1557 * @ctxt: a schema validation context
1558 * @node: a subtree containing XML Schema informations
1559 * @name: the attribute name
1560 * @def: the default value
1561 *
1562 * Get is a bolean property is set
1563 *
1564 * Returns the default if not found, 0 if found to be false,
1565 * 1 if found to be true
1566 */
1567static int
1568xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001569 const char *name, int def)
1570{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001571 const xmlChar *val;
Daniel Veillard4255d502002-04-16 15:50:10 +00001572
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001573 val = xmlSchemaGetProp(ctxt, node, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00001574 if (val == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001575 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001576
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001577 if (xmlStrEqual(val, BAD_CAST "true"))
1578 def = 1;
1579 else if (xmlStrEqual(val, BAD_CAST "false"))
1580 def = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00001581 else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001582 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_BOOLEAN,
1583 "Attribute %s: the value %s is not boolean\n",
1584 (const xmlChar *) name, val);
Daniel Veillard4255d502002-04-16 15:50:10 +00001585 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001586 return (def);
Daniel Veillard4255d502002-04-16 15:50:10 +00001587}
1588
1589/************************************************************************
1590 * *
1591 * Shema extraction from an Infoset *
1592 * *
1593 ************************************************************************/
1594static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
1595 ctxt, xmlSchemaPtr schema,
1596 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001597static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr
1598 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001599 xmlSchemaPtr schema,
1600 xmlNodePtr node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001601static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr
1602 ctxt,
Daniel Veillard4255d502002-04-16 15:50:10 +00001603 xmlSchemaPtr schema,
1604 xmlNodePtr node,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001605 int simple);
Daniel Veillard4255d502002-04-16 15:50:10 +00001606static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt,
1607 xmlSchemaPtr schema,
1608 xmlNodePtr node);
1609static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt,
1610 xmlSchemaPtr schema,
1611 xmlNodePtr node);
1612static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr
1613 ctxt,
1614 xmlSchemaPtr schema,
1615 xmlNodePtr node);
1616static xmlSchemaAttributeGroupPtr
1617xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
1618 xmlSchemaPtr schema, xmlNodePtr node);
1619static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt,
1620 xmlSchemaPtr schema,
1621 xmlNodePtr node);
1622static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
1623 xmlSchemaPtr schema,
1624 xmlNodePtr node);
1625static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001626xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1627 xmlSchemaPtr schema, xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00001628
1629/**
1630 * xmlSchemaParseAttrDecls:
1631 * @ctxt: a schema validation context
1632 * @schema: the schema being built
1633 * @node: a subtree containing XML Schema informations
1634 * @type: the hosting type
1635 *
1636 * parse a XML schema attrDecls declaration corresponding to
1637 * <!ENTITY % attrDecls
1638 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
1639 */
1640static xmlNodePtr
1641xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1642 xmlNodePtr child, xmlSchemaTypePtr type)
1643{
1644 xmlSchemaAttributePtr lastattr, attr;
1645
1646 lastattr = NULL;
1647 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001648 (IS_SCHEMA(child, "attributeGroup"))) {
1649 attr = NULL;
1650 if (IS_SCHEMA(child, "attribute")) {
1651 attr = xmlSchemaParseAttribute(ctxt, schema, child);
1652 } else if (IS_SCHEMA(child, "attributeGroup")) {
1653 attr = (xmlSchemaAttributePtr)
1654 xmlSchemaParseAttributeGroup(ctxt, schema, child);
1655 }
1656 if (attr != NULL) {
1657 if (lastattr == NULL) {
1658 type->attributes = attr;
1659 lastattr = attr;
1660 } else {
1661 lastattr->next = attr;
1662 lastattr = attr;
1663 }
1664 }
1665 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001666 }
1667 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001668 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child);
1669 if (attr != NULL) {
1670 if (lastattr == NULL) {
1671 type->attributes = attr;
1672 lastattr = attr;
1673 } else {
1674 lastattr->next = attr;
1675 lastattr = attr;
1676 }
1677 }
1678 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001679 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001680 return (child);
Daniel Veillard4255d502002-04-16 15:50:10 +00001681}
1682
1683/**
1684 * xmlSchemaParseAnnotation:
1685 * @ctxt: a schema validation context
1686 * @schema: the schema being built
1687 * @node: a subtree containing XML Schema informations
1688 *
1689 * parse a XML schema Attrribute declaration
1690 * *WARNING* this interface is highly subject to change
1691 *
1692 * Returns -1 in case of error, 0 if the declaration is inproper and
1693 * 1 in case of success.
1694 */
1695static xmlSchemaAnnotPtr
1696xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1697 xmlNodePtr node)
1698{
1699 xmlSchemaAnnotPtr ret;
1700
1701 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1702 return (NULL);
1703 ret = xmlSchemaNewAnnot(ctxt, node);
1704
1705 return (ret);
1706}
1707
1708/**
1709 * xmlSchemaParseFacet:
1710 * @ctxt: a schema validation context
1711 * @schema: the schema being built
1712 * @node: a subtree containing XML Schema informations
1713 *
1714 * parse a XML schema Facet declaration
1715 * *WARNING* this interface is highly subject to change
1716 *
1717 * Returns the new type structure or NULL in case of error
1718 */
1719static xmlSchemaFacetPtr
1720xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001721 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001722{
1723 xmlSchemaFacetPtr facet;
1724 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001725 const xmlChar *value;
Daniel Veillard4255d502002-04-16 15:50:10 +00001726
1727 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1728 return (NULL);
1729
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001730 facet = xmlSchemaNewFacet();
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001731 if (facet == NULL) {
1732 xmlSchemaPErrMemory(ctxt, "allocating facet", node);
1733 return (NULL);
1734 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001735 facet->node = node;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001736 value = xmlSchemaGetProp(ctxt, node, "value");
Daniel Veillard4255d502002-04-16 15:50:10 +00001737 if (value == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001738 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE,
1739 "Facet %s has no value\n", node->name, NULL);
1740 xmlSchemaFreeFacet(facet);
Daniel Veillard4255d502002-04-16 15:50:10 +00001741 return (NULL);
1742 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001743 if (IS_SCHEMA(node, "minInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001744 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001745 } else if (IS_SCHEMA(node, "minExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001746 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001747 } else if (IS_SCHEMA(node, "maxInclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001748 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001749 } else if (IS_SCHEMA(node, "maxExclusive")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001750 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001751 } else if (IS_SCHEMA(node, "totalDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001752 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001753 } else if (IS_SCHEMA(node, "fractionDigits")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001754 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001755 } else if (IS_SCHEMA(node, "pattern")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001756 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001757 } else if (IS_SCHEMA(node, "enumeration")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001758 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001759 } else if (IS_SCHEMA(node, "whiteSpace")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001760 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001761 } else if (IS_SCHEMA(node, "length")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001762 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001763 } else if (IS_SCHEMA(node, "maxLength")) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001764 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1765 } else if (IS_SCHEMA(node, "minLength")) {
1766 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1767 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001768 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE,
1769 "Unknown facet type %s\n", node->name, NULL);
1770 xmlSchemaFreeFacet(facet);
1771 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001772 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001773 facet->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00001774 facet->value = value;
1775 child = node->children;
1776
1777 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001778 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1779 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001780 }
1781 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001782 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD,
1783 "Facet %s has unexpected child content\n",
1784 node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001785 }
1786 return (facet);
1787}
1788
1789/**
1790 * xmlSchemaParseAny:
1791 * @ctxt: a schema validation context
1792 * @schema: the schema being built
1793 * @node: a subtree containing XML Schema informations
1794 *
1795 * parse a XML schema Any declaration
1796 * *WARNING* this interface is highly subject to change
1797 *
1798 * Returns the new type structure or NULL in case of error
1799 */
1800static xmlSchemaTypePtr
1801xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1802 xmlNodePtr node)
1803{
1804 xmlSchemaTypePtr type;
1805 xmlNodePtr child = NULL;
1806 xmlChar name[30];
1807
1808 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1809 return (NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001810 snprintf((char *) name, 30, "any %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001811 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001812 if (type == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001813 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001814 type->node = node;
1815 type->type = XML_SCHEMA_TYPE_ANY;
1816 child = node->children;
1817 type->minOccurs = xmlGetMinOccurs(ctxt, node);
1818 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
1819
1820 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001821 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1822 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001823 }
1824 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001825 xmlSchemaPErr2(ctxt, node, child,
1826 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
1827 "Sequence %s has unexpected content\n", type->name,
1828 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001829 }
1830
1831 return (type);
1832}
1833
1834/**
1835 * xmlSchemaParseNotation:
1836 * @ctxt: a schema validation context
1837 * @schema: the schema being built
1838 * @node: a subtree containing XML Schema informations
1839 *
1840 * parse a XML schema Notation declaration
1841 *
1842 * Returns the new structure or NULL in case of error
1843 */
1844static xmlSchemaNotationPtr
1845xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001846 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001847{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001848 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00001849 xmlSchemaNotationPtr ret;
1850 xmlNodePtr child = NULL;
1851
1852 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1853 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001854 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00001855 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001856 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME,
1857 "Notation has no name\n", NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001858 return (NULL);
1859 }
1860 ret = xmlSchemaAddNotation(ctxt, schema, name);
1861 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001862 return (NULL);
1863 }
1864 child = node->children;
1865 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001866 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1867 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001868 }
1869 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001870 xmlSchemaPErr2(ctxt, node, child,
1871 XML_SCHEMAP_UNKNOWN_NOTATION_CHILD,
1872 "notation %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001873 }
1874
1875 return (ret);
1876}
1877
1878/**
1879 * xmlSchemaParseAnyAttribute:
1880 * @ctxt: a schema validation context
1881 * @schema: the schema being built
1882 * @node: a subtree containing XML Schema informations
1883 *
1884 * parse a XML schema AnyAttrribute declaration
1885 * *WARNING* this interface is highly subject to change
1886 *
1887 * Returns an attribute def structure or NULL
1888 */
1889static xmlSchemaAttributePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001890xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
1891 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00001892{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001893 const xmlChar *processContents;
Daniel Veillard4255d502002-04-16 15:50:10 +00001894 xmlSchemaAttributePtr ret;
1895 xmlNodePtr child = NULL;
1896 char name[100];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001897 const xmlChar *local, *ns;
1898
Daniel Veillard4255d502002-04-16 15:50:10 +00001899
1900 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1901 return (NULL);
1902
1903 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001904 local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns);
1905 ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00001906 if (ret == NULL) {
1907 return (NULL);
1908 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001909 ret->id = xmlSchemaGetProp(ctxt, node, "id");
1910 processContents = xmlSchemaGetProp(ctxt, node, "processContents");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001911 if ((processContents == NULL)
1912 || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) {
1913 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
1914 } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) {
1915 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP;
1916 } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) {
1917 ret->occurs = XML_SCHEMAS_ANYATTR_LAX;
Daniel Veillard4255d502002-04-16 15:50:10 +00001918 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001919 xmlSchemaPErr2(ctxt, node, child,
1920 XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD,
1921 "anyAttribute has unexpected content for processContents: %s\n",
1922 processContents, NULL);
1923 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT;
Daniel Veillard4255d502002-04-16 15:50:10 +00001924 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001925
1926 child = node->children;
1927 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001928 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
1929 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00001930 }
1931 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001932 xmlSchemaPErr2(ctxt, node, child,
1933 XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD,
1934 "anyAttribute %s has unexpected content\n",
1935 (const xmlChar *) name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00001936 }
1937
1938 return (ret);
1939}
1940
1941
1942/**
1943 * xmlSchemaParseAttribute:
1944 * @ctxt: a schema validation context
1945 * @schema: the schema being built
1946 * @node: a subtree containing XML Schema informations
1947 *
1948 * parse a XML schema Attrribute declaration
1949 * *WARNING* this interface is highly subject to change
1950 *
1951 * Returns -1 in case of error, 0 if the declaration is inproper and
1952 * 1 in case of success.
1953 */
1954static xmlSchemaAttributePtr
1955xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
1956 xmlNodePtr node)
1957{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001958 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00001959 xmlSchemaAttributePtr ret;
1960 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001961 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00001962
1963 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
1964 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001965 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00001966 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001967
Daniel Veillardd0c9c322003-10-10 00:49:42 +00001968 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
1969 if (ref == NULL) {
1970 xmlSchemaPErr2(ctxt, node, child,
1971 XML_SCHEMAP_ATTR_NONAME_NOREF,
1972 "Attribute has no name nor ref\n", NULL, NULL);
1973 return (NULL);
1974 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001975 if (refNs == NULL)
1976 refNs = schema->targetNamespace;
1977 snprintf(buf, 99, "anonattr %d", ctxt->counter++ + 1);
1978 name = (const xmlChar *) buf;
1979 ret = xmlSchemaAddAttribute(ctxt, schema, name, NULL);
1980 } else {
1981 const xmlChar *local, *ns;
1982
1983 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
1984 ret = xmlSchemaAddAttribute(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00001985 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001986 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00001987 return (NULL);
1988 }
Daniel Veillard4255d502002-04-16 15:50:10 +00001989 ret->ref = ref;
1990 ret->refNs = refNs;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001991 if ((ret->targetNamespace != NULL) &&
1992 ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) &&
1993 (xmlStrEqual(ret->targetNamespace, schema->targetNamespace)))
1994 ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT;
Daniel Veillard4255d502002-04-16 15:50:10 +00001995 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00001996 if ((ret->typeName != NULL) && (ret->typeNs == NULL))
1997 ret->typeNs = schema->targetNamespace;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00001998 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00001999 child = node->children;
2000 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002001 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2002 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002003 }
2004 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002005 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
2006 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002007 }
2008 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002009 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD,
2010 "attribute %s has unexpected content\n", name,
2011 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002012 }
2013
2014 return (ret);
2015}
2016
2017/**
2018 * xmlSchemaParseAttributeGroup:
2019 * @ctxt: a schema validation context
2020 * @schema: the schema being built
2021 * @node: a subtree containing XML Schema informations
2022 *
2023 * parse a XML schema Attribute Group declaration
2024 * *WARNING* this interface is highly subject to change
2025 *
2026 * Returns the attribute group or NULL in case of error.
2027 */
2028static xmlSchemaAttributeGroupPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002029xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt,
2030 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002031{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002032 const xmlChar *name, *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002033 xmlSchemaAttributeGroupPtr ret;
2034 xmlSchemaAttributePtr last = NULL, attr;
2035 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002036 const xmlChar *oldcontainer;
2037 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002038
2039 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2040 return (NULL);
2041 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002042 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002043 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002044
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002045 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2046 if (ref == NULL) {
2047 xmlSchemaPErr2(ctxt, node, child,
2048 XML_SCHEMAP_ATTRGRP_NONAME_NOREF,
2049 "AttributeGroup has no name nor ref\n", NULL,
2050 NULL);
2051 return (NULL);
2052 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002053 if (refNs == NULL)
2054 refNs = schema->targetNamespace;
2055 snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1);
2056 name = (const xmlChar *) buf;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002057 if (name == NULL) {
2058 xmlSchemaPErrMemory(ctxt, "creating attribute group", node);
2059 return (NULL);
2060 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002061 }
2062 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name);
2063 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002064 return (NULL);
2065 }
2066 ret->ref = ref;
2067 ret->refNs = refNs;
Daniel Veillard13e04c62002-04-23 17:51:29 +00002068 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00002069 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002070 child = node->children;
2071 ctxt->container = name;
2072 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002073 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2074 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002075 }
2076 while ((IS_SCHEMA(child, "attribute")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002077 (IS_SCHEMA(child, "attributeGroup"))) {
2078 attr = NULL;
2079 if (IS_SCHEMA(child, "attribute")) {
2080 attr = xmlSchemaParseAttribute(ctxt, schema, child);
2081 } else if (IS_SCHEMA(child, "attributeGroup")) {
2082 attr = (xmlSchemaAttributePtr)
2083 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2084 }
2085 if (attr != NULL) {
2086 if (last == NULL) {
2087 ret->attributes = attr;
2088 last = attr;
2089 } else {
2090 last->next = attr;
2091 last = attr;
2092 }
2093 }
2094 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002095 }
2096 if (IS_SCHEMA(child, "anyAttribute")) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002097 TODO
2098 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002099 }
2100 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002101 xmlSchemaPErr2(ctxt, node, child,
2102 XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD,
2103 "attribute group %s has unexpected content\n", name,
2104 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002105 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002106 ctxt->container = oldcontainer;
2107 return (ret);
2108}
2109
2110/**
2111 * xmlSchemaParseElement:
2112 * @ctxt: a schema validation context
2113 * @schema: the schema being built
2114 * @node: a subtree containing XML Schema informations
2115 *
2116 * parse a XML schema Element declaration
2117 * *WARNING* this interface is highly subject to change
2118 *
2119 * Returns -1 in case of error, 0 if the declaration is inproper and
2120 * 1 in case of success.
2121 */
2122static xmlSchemaElementPtr
2123xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2124 xmlNodePtr node, int toplevel)
2125{
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002126 const xmlChar *name, *fixed;
2127 const xmlChar *refNs = NULL, *ref = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00002128 xmlSchemaElementPtr ret;
2129 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002130 const xmlChar *oldcontainer;
2131 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002132
2133 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2134 return (NULL);
2135 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002136 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002137 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002138
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002139 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2140 if (ref == NULL) {
2141 xmlSchemaPErr2(ctxt, node, child,
2142 XML_SCHEMAP_ELEM_NONAME_NOREF,
2143 "Element has no name nor ref\n", NULL, NULL);
2144 return (NULL);
2145 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002146 if (refNs == NULL)
2147 refNs = schema->targetNamespace;
2148 snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1);
2149 name = (const xmlChar *) buf;
2150 ret = xmlSchemaAddElement(ctxt, schema, name, NULL);
2151 } else {
2152 const xmlChar *local, *ns;
2153
2154 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2155 ret = xmlSchemaAddElement(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002156 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002157 if (ret != NULL)
2158 ret->node = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00002159 if (ret == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002160 return (NULL);
2161 }
2162 ret->type = XML_SCHEMA_TYPE_ELEMENT;
2163 ret->ref = ref;
2164 ret->refNs = refNs;
2165 if (ref != NULL)
2166 ret->flags |= XML_SCHEMAS_ELEM_REF;
2167 if (toplevel)
2168 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
2169 if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
2170 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2171 if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
2172 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE;
2173 ctxt->container = name;
2174
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002175 ret->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002176 ret->namedType =
2177 xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002178 if ((ret->namedType != NULL) && (ret->namedTypeNs == NULL))
2179 ret->namedTypeNs = schema->targetNamespace;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002180 ret->substGroup =
2181 xmlGetQNameProp(ctxt, node, "substitutionGroup",
2182 &(ret->substGroupNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002183 fixed = xmlSchemaGetProp(ctxt, node, "fixed");
Daniel Veillard4255d502002-04-16 15:50:10 +00002184 ret->minOccurs = xmlGetMinOccurs(ctxt, node);
2185 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002186
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002187 ret->value = xmlSchemaGetProp(ctxt, node, "default");
Daniel Veillard4255d502002-04-16 15:50:10 +00002188 if ((ret->value != NULL) && (fixed != NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002189 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED,
2190 "Element %s has both default and fixed\n",
2191 ret->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002192 } else if (fixed != NULL) {
2193 ret->flags |= XML_SCHEMAS_ELEM_FIXED;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002194 ret->value = fixed;
Daniel Veillard4255d502002-04-16 15:50:10 +00002195 }
2196
2197 child = node->children;
2198 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002199 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2200 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002201 }
2202 if (IS_SCHEMA(child, "complexType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002203 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002204 child = child->next;
2205 } else if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002206 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00002207 child = child->next;
2208 }
2209 while ((IS_SCHEMA(child, "unique")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002210 (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
2211 TODO child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002212 }
2213 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002214 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD,
2215 "element %s has unexpected content\n", name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002216 }
2217
2218 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00002219 return (ret);
2220}
2221
2222/**
2223 * xmlSchemaParseUnion:
2224 * @ctxt: a schema validation context
2225 * @schema: the schema being built
2226 * @node: a subtree containing XML Schema informations
2227 *
2228 * parse a XML schema Union definition
2229 * *WARNING* this interface is highly subject to change
2230 *
2231 * Returns -1 in case of error, 0 if the declaration is inproper and
2232 * 1 in case of success.
2233 */
2234static xmlSchemaTypePtr
2235xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002236 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002237{
2238 xmlSchemaTypePtr type, subtype, last = NULL;
2239 xmlNodePtr child = NULL;
2240 xmlChar name[30];
2241
2242 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2243 return (NULL);
2244
2245
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002246 snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002247 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002248 if (type == NULL)
2249 return (NULL);
2250 type->node = node;
2251 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002252 type->id = xmlSchemaGetProp(ctxt, node, "id");
2253 type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes");
Daniel Veillard4255d502002-04-16 15:50:10 +00002254
2255 child = node->children;
2256 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002257 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2258 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002259 }
2260 while (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002261 subtype = (xmlSchemaTypePtr)
2262 xmlSchemaParseSimpleType(ctxt, schema, child);
2263 if (subtype != NULL) {
2264 if (last == NULL) {
2265 type->subtypes = subtype;
2266 last = subtype;
2267 } else {
2268 last->next = subtype;
2269 last = subtype;
2270 }
2271 last->next = NULL;
2272 }
2273 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002274 }
2275 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002276 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD,
2277 "Union %s has unexpected content\n", type->name,
2278 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002279 }
2280 return (type);
2281}
2282
2283/**
2284 * xmlSchemaParseList:
2285 * @ctxt: a schema validation context
2286 * @schema: the schema being built
2287 * @node: a subtree containing XML Schema informations
2288 *
2289 * parse a XML schema List definition
2290 * *WARNING* this interface is highly subject to change
2291 *
2292 * Returns -1 in case of error, 0 if the declaration is inproper and
2293 * 1 in case of success.
2294 */
2295static xmlSchemaTypePtr
2296xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002297 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002298{
2299 xmlSchemaTypePtr type, subtype;
2300 xmlNodePtr child = NULL;
2301 xmlChar name[30];
2302
2303 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2304 return (NULL);
2305
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002306 snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002307 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002308 if (type == NULL)
2309 return (NULL);
2310 type->node = node;
2311 type->type = XML_SCHEMA_TYPE_LIST;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002312 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002313 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002314 if ((type->ref != NULL) && (type->refNs == NULL))
2315 type->refNs = schema->targetNamespace;
Daniel Veillard4255d502002-04-16 15:50:10 +00002316
2317 child = node->children;
2318 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002319 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2320 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002321 }
2322 subtype = NULL;
2323 if (IS_SCHEMA(child, "simpleType")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002324 subtype = (xmlSchemaTypePtr)
2325 xmlSchemaParseSimpleType(ctxt, schema, child);
2326 child = child->next;
2327 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002328 }
2329 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002330 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD,
2331 "List %s has unexpected content\n", type->name,
2332 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002333 }
2334 return (type);
2335}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002336
Daniel Veillard4255d502002-04-16 15:50:10 +00002337/**
2338 * xmlSchemaParseSimpleType:
2339 * @ctxt: a schema validation context
2340 * @schema: the schema being built
2341 * @node: a subtree containing XML Schema informations
2342 *
2343 * parse a XML schema Simple Type definition
2344 * *WARNING* this interface is highly subject to change
2345 *
2346 * Returns -1 in case of error, 0 if the declaration is inproper and
2347 * 1 in case of success.
2348 */
2349static xmlSchemaTypePtr
2350xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2351 xmlNodePtr node)
2352{
2353 xmlSchemaTypePtr type, subtype;
2354 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002355 const xmlChar *name;
Daniel Veillard4255d502002-04-16 15:50:10 +00002356
2357 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2358 return (NULL);
2359
2360
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002361 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002362 if (name == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002363 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002364
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002365 snprintf(buf, 99, "simpletype %d", ctxt->counter++ + 1);
2366 type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL);
2367 } else {
2368 const xmlChar *local, *ns;
2369
2370 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
2371 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00002372 }
Daniel Veillard4255d502002-04-16 15:50:10 +00002373 if (type == NULL)
2374 return (NULL);
2375 type->node = node;
2376 type->type = XML_SCHEMA_TYPE_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002377 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002378
2379 child = node->children;
2380 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002381 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2382 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002383 }
2384 subtype = NULL;
2385 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002386 subtype = (xmlSchemaTypePtr)
2387 xmlSchemaParseRestriction(ctxt, schema, child, 1);
2388 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002389 } else if (IS_SCHEMA(child, "list")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002390 subtype = (xmlSchemaTypePtr)
2391 xmlSchemaParseList(ctxt, schema, child);
2392 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002393 } else if (IS_SCHEMA(child, "union")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002394 subtype = (xmlSchemaTypePtr)
2395 xmlSchemaParseUnion(ctxt, schema, child);
2396 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002397 }
2398 type->subtypes = subtype;
2399 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002400 xmlSchemaPErr2(ctxt, node, child,
2401 XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD,
2402 "SimpleType %s has unexpected content\n",
2403 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002404 }
2405
2406 return (type);
2407}
2408
2409
2410/**
2411 * xmlSchemaParseGroup:
2412 * @ctxt: a schema validation context
2413 * @schema: the schema being built
2414 * @node: a subtree containing XML Schema informations
2415 *
2416 * parse a XML schema Group definition
2417 * *WARNING* this interface is highly subject to change
2418 *
2419 * Returns -1 in case of error, 0 if the declaration is inproper and
2420 * 1 in case of success.
2421 */
2422static xmlSchemaTypePtr
2423xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002424 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002425{
2426 xmlSchemaTypePtr type, subtype;
2427 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002428 const xmlChar *name;
2429 const xmlChar *ref = NULL, *refNs = NULL;
2430 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00002431
2432 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2433 return (NULL);
2434
2435
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002436 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00002437 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00002438
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002439 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs);
2440 if (ref == NULL) {
2441 xmlSchemaPErr2(ctxt, node, child,
2442 XML_SCHEMAP_GROUP_NONAME_NOREF,
2443 "Group has no name nor ref\n", NULL, NULL);
2444 return (NULL);
2445 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002446 if (refNs == NULL)
2447 refNs = schema->targetNamespace;
2448 snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1);
2449 name = (const xmlChar *) buf;
Daniel Veillard4255d502002-04-16 15:50:10 +00002450 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002451 type = xmlSchemaAddGroup(ctxt, schema, name);
Daniel Veillard4255d502002-04-16 15:50:10 +00002452 if (type == NULL)
2453 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00002454
Daniel Veillard4255d502002-04-16 15:50:10 +00002455 type->node = node;
2456 type->type = XML_SCHEMA_TYPE_GROUP;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002457 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002458 type->ref = ref;
2459 type->refNs = refNs;
2460 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2461 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2462
2463 child = node->children;
2464 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002465 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2466 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002467 }
2468 subtype = NULL;
2469 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002470 subtype = (xmlSchemaTypePtr)
2471 xmlSchemaParseAll(ctxt, schema, child);
2472 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002473 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002474 subtype = xmlSchemaParseChoice(ctxt, schema, child);
2475 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002476 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002477 subtype = (xmlSchemaTypePtr)
2478 xmlSchemaParseSequence(ctxt, schema, child);
2479 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002480 }
2481 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002482 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00002483 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002484 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD,
2485 "Group %s has unexpected content\n", type->name,
2486 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002487 }
2488
2489 return (type);
2490}
2491
2492/**
2493 * xmlSchemaParseAll:
2494 * @ctxt: a schema validation context
2495 * @schema: the schema being built
2496 * @node: a subtree containing XML Schema informations
2497 *
2498 * parse a XML schema All definition
2499 * *WARNING* this interface is highly subject to change
2500 *
2501 * Returns -1 in case of error, 0 if the declaration is inproper and
2502 * 1 in case of success.
2503 */
2504static xmlSchemaTypePtr
2505xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002506 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00002507{
2508 xmlSchemaTypePtr type, subtype, last = NULL;
2509 xmlNodePtr child = NULL;
2510 xmlChar name[30];
2511
2512 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2513 return (NULL);
2514
2515
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002516 snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002517 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002518 if (type == NULL)
2519 return (NULL);
2520 type->node = node;
Daniel Veillard7646b182002-04-20 06:41:40 +00002521 type->type = XML_SCHEMA_TYPE_ALL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002522 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00002523 type->minOccurs = xmlGetMinOccurs(ctxt, node);
2524 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
2525
2526 child = node->children;
2527 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002528 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2529 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002530 }
2531 while (IS_SCHEMA(child, "element")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002532 subtype = (xmlSchemaTypePtr)
2533 xmlSchemaParseElement(ctxt, schema, child, 0);
2534 if (subtype != NULL) {
2535 if (last == NULL) {
2536 type->subtypes = subtype;
2537 last = subtype;
2538 } else {
2539 last->next = subtype;
2540 last = subtype;
2541 }
2542 last->next = NULL;
2543 }
2544 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00002545 }
2546 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002547 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD,
2548 "All %s has unexpected content\n", type->name,
2549 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00002550 }
2551
2552 return (type);
2553}
2554
2555/**
Daniel Veillard1d913862003-11-21 00:28:39 +00002556 * xmlSchemaImportSchema
2557 *
2558 * @ctxt: a schema validation context
2559 * @schemaLocation: an URI defining where to find the imported schema
2560 *
2561 * import a XML schema
2562 * *WARNING* this interface is highly subject to change
2563 *
2564 * Returns -1 in case of error and 1 in case of success.
2565 */
2566static xmlSchemaImportPtr
2567xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt,
2568 const xmlChar *schemaLocation)
2569{
2570 xmlSchemaImportPtr import;
2571 xmlSchemaParserCtxtPtr newctxt;
2572
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002573 newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
Daniel Veillard1d913862003-11-21 00:28:39 +00002574 if (newctxt == NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002575 xmlSchemaPErrMemory(ctxt, "allocating schama parser context",
Daniel Veillard1d913862003-11-21 00:28:39 +00002576 NULL);
2577 return (NULL);
2578 }
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002579 memset(newctxt, 0, sizeof(xmlSchemaParserCtxt));
2580 /* Keep the same dictionnary for parsing, really */
2581 xmlDictReference(ctxt->dict);
2582 newctxt->dict = ctxt->dict;
2583 newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1);
2584
Daniel Veillard1d913862003-11-21 00:28:39 +00002585 xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning,
2586 ctxt->userData);
2587
2588 import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport));
2589 if (import == NULL) {
2590 xmlSchemaPErrMemory(NULL, "allocating imported schema",
2591 NULL);
2592 xmlSchemaFreeParserCtxt(newctxt);
2593 return (NULL);
2594 }
2595
2596 memset(import, 0, sizeof(xmlSchemaImport));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002597 import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
Daniel Veillard1d913862003-11-21 00:28:39 +00002598 import->schema = xmlSchemaParse(newctxt);
2599
2600 if (import->schema == NULL) {
2601 /* FIXME use another error enum here ? */
2602 xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL,
2603 "failed to import schema at location %s\n",
2604 schemaLocation, NULL);
2605
2606 xmlSchemaFreeParserCtxt(newctxt);
2607 if (import->schemaLocation != NULL)
2608 xmlFree((xmlChar *)import->schemaLocation);
2609 xmlFree(import);
2610 return NULL;
2611 }
2612
2613 xmlSchemaFreeParserCtxt(newctxt);
2614 return import;
2615}
2616
2617
2618/**
Daniel Veillard5a872412002-05-22 06:40:27 +00002619 * xmlSchemaParseImport:
2620 * @ctxt: a schema validation context
2621 * @schema: the schema being built
2622 * @node: a subtree containing XML Schema informations
2623 *
2624 * parse a XML schema Import definition
2625 * *WARNING* this interface is highly subject to change
2626 *
2627 * Returns -1 in case of error, 0 if the declaration is inproper and
2628 * 1 in case of success.
2629 */
2630static int
2631xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002632 xmlNodePtr node)
Daniel Veillard5a872412002-05-22 06:40:27 +00002633{
2634 xmlNodePtr child = NULL;
Daniel Veillard1d913862003-11-21 00:28:39 +00002635 xmlSchemaImportPtr import = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002636 const xmlChar *namespace;
2637 const xmlChar *schemaLocation;
Daniel Veillard1d913862003-11-21 00:28:39 +00002638 const xmlChar *previous;
Daniel Veillard5a872412002-05-22 06:40:27 +00002639 xmlURIPtr check;
2640
Daniel Veillard1d913862003-11-21 00:28:39 +00002641
Daniel Veillard5a872412002-05-22 06:40:27 +00002642 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2643 return (-1);
2644
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002645 namespace = xmlSchemaGetProp(ctxt, node, "namespace");
Daniel Veillard5a872412002-05-22 06:40:27 +00002646 if (namespace != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002647 check = xmlParseURI((const char *) namespace);
2648 if (check == NULL) {
2649 xmlSchemaPErr2(ctxt, node, child,
2650 XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI,
2651 "Import namespace attribute is not an URI: %s\n",
2652 namespace, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002653 return (-1);
2654 } else {
2655 xmlFreeURI(check);
2656 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002657 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002658 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
Daniel Veillard5a872412002-05-22 06:40:27 +00002659 if (schemaLocation != NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002660 xmlChar *base = NULL;
2661 xmlChar *URI = NULL;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002662 check = xmlParseURI((const char *) schemaLocation);
2663 if (check == NULL) {
2664 xmlSchemaPErr2(ctxt, node, child,
2665 XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI,
2666 "Import schemaLocation attribute is not an URI: %s\n",
2667 schemaLocation, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002668 return (-1);
2669 } else {
2670 xmlFreeURI(check);
2671 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002672 base = xmlNodeGetBase(node->doc, node);
2673 if (base == NULL) {
2674 URI = xmlBuildURI(schemaLocation, node->doc->URL);
2675 } else {
2676 URI = xmlBuildURI(schemaLocation, base);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002677 xmlFree(base);
Daniel Veillard1d913862003-11-21 00:28:39 +00002678 }
Daniel Veillard1d913862003-11-21 00:28:39 +00002679 if (URI != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00002680 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
2681 xmlFree(URI);
Daniel Veillard1d913862003-11-21 00:28:39 +00002682 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002683 }
2684 if (schema->schemasImports == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002685 schema->schemasImports = xmlHashCreate(10);
2686 if (schema->schemasImports == NULL) {
2687 xmlSchemaPErr2(ctxt, node, child,
2688 XML_SCHEMAP_FAILED_BUILD_IMPORT,
2689 "Internal: failed to build import table\n",
2690 NULL, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002691 return (-1);
2692 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002693 }
2694 if (namespace == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002695 import = xmlHashLookup(schema->schemasImports,
2696 XML_SCHEMAS_DEFAULT_NAMESPACE);
2697 if (import != NULL)
2698 previous = import->schemaLocation;
2699 else
2700 previous = NULL;
2701
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002702 if (schemaLocation != NULL) {
2703 if (previous != NULL) {
2704 if (!xmlStrEqual(schemaLocation, previous)) {
2705 xmlSchemaPErr2(ctxt, node, child,
2706 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2707 "Redefining import for default namespace with a different URI: %s\n",
2708 schemaLocation, NULL);
2709 }
2710 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002711 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2712 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002713 return (-1);
2714 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002715 xmlHashAddEntry(schema->schemasImports,
2716 XML_SCHEMAS_DEFAULT_NAMESPACE,
Daniel Veillard1d913862003-11-21 00:28:39 +00002717 import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002718 }
2719 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002720 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002721 import = xmlHashLookup(schema->schemasImports, namespace);
2722 if (import != NULL)
2723 previous = import->schemaLocation;
2724 else
2725 previous = NULL;
2726
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002727 if (schemaLocation != NULL) {
2728 if (previous != NULL) {
2729 if (!xmlStrEqual(schemaLocation, previous)) {
2730 xmlSchemaPErr2(ctxt, node, child,
2731 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME,
2732 "Redefining import for namespace %s with a different URI: %s\n",
2733 namespace, schemaLocation);
2734 }
2735 } else {
Daniel Veillard1d913862003-11-21 00:28:39 +00002736 import = xmlSchemaImportSchema(ctxt, schemaLocation);
2737 if (import == NULL) {
Daniel Veillard1d913862003-11-21 00:28:39 +00002738 return (-1);
2739 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002740 xmlHashAddEntry(schema->schemasImports,
Daniel Veillard1d913862003-11-21 00:28:39 +00002741 namespace, import);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002742 }
2743 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002744 }
Daniel Veillard5a872412002-05-22 06:40:27 +00002745
2746 child = node->children;
2747 while (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002748 /*
2749 * the annotations here are simply discarded ...
2750 */
2751 child = child->next;
Daniel Veillard5a872412002-05-22 06:40:27 +00002752 }
2753 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002754 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD,
2755 "Import has unexpected content\n", NULL, NULL);
2756 return (-1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002757 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00002758 return (1);
Daniel Veillard5a872412002-05-22 06:40:27 +00002759}
2760
2761/**
Daniel Veillardbd2904b2003-11-25 15:38:59 +00002762 * xmlSchemaCleanupDoc:
2763 * @ctxt: a schema validation context
2764 * @node: the root of the document.
2765 *
2766 * removes unwanted nodes in a schemas document tree
2767 */
2768static void
2769xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root)
2770{
2771 xmlNodePtr delete, cur;
2772
2773 if ((ctxt == NULL) || (root == NULL)) return;
2774
2775 /*
2776 * Remove all the blank text nodes
2777 */
2778 delete = NULL;
2779 cur = root;
2780 while (cur != NULL) {
2781 if (delete != NULL) {
2782 xmlUnlinkNode(delete);
2783 xmlFreeNode(delete);
2784 delete = NULL;
2785 }
2786 if (cur->type == XML_TEXT_NODE) {
2787 if (IS_BLANK_NODE(cur)) {
2788 if (xmlNodeGetSpacePreserve(cur) != 1) {
2789 delete = cur;
2790 }
2791 }
2792 } else if ((cur->type != XML_ELEMENT_NODE) &&
2793 (cur->type != XML_CDATA_SECTION_NODE)) {
2794 delete = cur;
2795 goto skip_children;
2796 }
2797
2798 /*
2799 * Skip to next node
2800 */
2801 if (cur->children != NULL) {
2802 if ((cur->children->type != XML_ENTITY_DECL) &&
2803 (cur->children->type != XML_ENTITY_REF_NODE) &&
2804 (cur->children->type != XML_ENTITY_NODE)) {
2805 cur = cur->children;
2806 continue;
2807 }
2808 }
2809 skip_children:
2810 if (cur->next != NULL) {
2811 cur = cur->next;
2812 continue;
2813 }
2814
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == root) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 if (delete != NULL) {
2830 xmlUnlinkNode(delete);
2831 xmlFreeNode(delete);
2832 delete = NULL;
2833 }
2834}
2835
2836/**
2837 * xmlSchemaParseSchemaTopLevel:
2838 * @ctxt: a schema validation context
2839 * @schema: the schemas
2840 * @nodes: the list of top level nodes
2841 *
2842 * Returns the internal XML Schema structure built from the resource or
2843 * NULL in case of error
2844 */
2845static void
2846xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt,
2847 xmlSchemaPtr schema, xmlNodePtr nodes)
2848{
2849 xmlNodePtr child;
2850 xmlSchemaAnnotPtr annot;
2851
2852 if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL))
2853 return;
2854
2855 child = nodes;
2856 while ((IS_SCHEMA(child, "include")) ||
2857 (IS_SCHEMA(child, "import")) ||
2858 (IS_SCHEMA(child, "redefine")) ||
2859 (IS_SCHEMA(child, "annotation"))) {
2860 if (IS_SCHEMA(child, "annotation")) {
2861 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2862 if (schema->annot == NULL)
2863 schema->annot = annot;
2864 else
2865 xmlSchemaFreeAnnot(annot);
2866 } else if (IS_SCHEMA(child, "import")) {
2867 xmlSchemaParseImport(ctxt, schema, child);
2868 } else if (IS_SCHEMA(child, "include")) {
2869 xmlSchemaParseInclude(ctxt, schema, child);
2870 } else if (IS_SCHEMA(child, "redefine")) {
2871 TODO
2872 }
2873 child = child->next;
2874 }
2875 while (child != NULL) {
2876 if (IS_SCHEMA(child, "complexType")) {
2877 xmlSchemaParseComplexType(ctxt, schema, child);
2878 child = child->next;
2879 } else if (IS_SCHEMA(child, "simpleType")) {
2880 xmlSchemaParseSimpleType(ctxt, schema, child);
2881 child = child->next;
2882 } else if (IS_SCHEMA(child, "element")) {
2883 xmlSchemaParseElement(ctxt, schema, child, 1);
2884 child = child->next;
2885 } else if (IS_SCHEMA(child, "attribute")) {
2886 xmlSchemaParseAttribute(ctxt, schema, child);
2887 child = child->next;
2888 } else if (IS_SCHEMA(child, "attributeGroup")) {
2889 xmlSchemaParseAttributeGroup(ctxt, schema, child);
2890 child = child->next;
2891 } else if (IS_SCHEMA(child, "group")) {
2892 xmlSchemaParseGroup(ctxt, schema, child);
2893 child = child->next;
2894 } else if (IS_SCHEMA(child, "notation")) {
2895 xmlSchemaParseNotation(ctxt, schema, child);
2896 child = child->next;
2897 } else {
2898 xmlSchemaPErr2(ctxt, NULL, child,
2899 XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD,
2900 "Schemas: unexpected element %s here \n",
2901 child->name, NULL);
2902 child = child->next;
2903 }
2904 while (IS_SCHEMA(child, "annotation")) {
2905 annot = xmlSchemaParseAnnotation(ctxt, schema, child);
2906 if (schema->annot == NULL)
2907 schema->annot = annot;
2908 else
2909 xmlSchemaFreeAnnot(annot);
2910 child = child->next;
2911 }
2912 }
2913}
2914
2915/**
2916 * xmlSchemaParseInclude:
2917 * @ctxt: a schema validation context
2918 * @schema: the schema being built
2919 * @node: a subtree containing XML Schema informations
2920 *
2921 * parse a XML schema Include definition
2922 *
2923 * Returns -1 in case of error, 0 if the declaration is inproper and
2924 * 1 in case of success.
2925 */
2926static int
2927xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
2928 xmlNodePtr node)
2929{
2930 xmlNodePtr child = NULL;
2931 const xmlChar *schemaLocation;
2932 xmlURIPtr check;
2933 xmlDocPtr doc;
2934 xmlNodePtr root;
2935 xmlSchemaIncludePtr include;
2936
2937
2938 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
2939 return (-1);
2940
2941 /*
2942 * Preliminary step, extract the URI-Reference for the include and
2943 * make an URI from the base.
2944 */
2945 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation");
2946 if (schemaLocation != NULL) {
2947 xmlChar *base = NULL;
2948 xmlChar *URI = NULL;
2949 check = xmlParseURI((const char *) schemaLocation);
2950 if (check == NULL) {
2951 xmlSchemaPErr2(ctxt, node, child,
2952 XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI,
2953 "Include schemaLocation attribute is not an URI: %s\n",
2954 schemaLocation, NULL);
2955 return (-1);
2956 } else {
2957 xmlFreeURI(check);
2958 }
2959 base = xmlNodeGetBase(node->doc, node);
2960 if (base == NULL) {
2961 URI = xmlBuildURI(schemaLocation, node->doc->URL);
2962 } else {
2963 URI = xmlBuildURI(schemaLocation, base);
2964 xmlFree(base);
2965 }
2966 if (URI != NULL) {
2967 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1);
2968 xmlFree(URI);
2969 }
2970 } else {
2971 xmlSchemaPErr2(ctxt, node, child,
2972 XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI,
2973 "Include schemaLocation attribute missing\n",
2974 NULL, NULL);
2975 return (-1);
2976 }
2977
2978 child = node->children;
2979 while (IS_SCHEMA(child, "annotation")) {
2980 /*
2981 * the annotations here are simply discarded ...
2982 */
2983 child = child->next;
2984 }
2985 if (child != NULL) {
2986 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD,
2987 "Include has unexpected content\n", NULL, NULL);
2988 return (-1);
2989 }
2990
2991 /*
2992 * First step is to parse the input document into an DOM/Infoset
2993 */
2994 doc = xmlReadFile((const char *) schemaLocation, NULL,
2995 SCHEMAS_PARSE_OPTIONS);
2996 if (doc == NULL) {
2997 xmlSchemaPErr(ctxt, NULL,
2998 XML_SCHEMAP_FAILED_LOAD,
2999 "xmlSchemaParse: could not load %s\n",
3000 ctxt->URL, NULL);
3001 return(-1);
3002 }
3003
3004 /*
3005 * Then extract the root of the schema
3006 */
3007 root = xmlDocGetRootElement(doc);
3008 if (root == NULL) {
3009 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3010 XML_SCHEMAP_NOROOT,
3011 "schemas %s has no root", schemaLocation, NULL);
3012 xmlFreeDoc(doc);
3013 return (-1);
3014 }
3015
3016 /*
3017 * Remove all the blank text nodes
3018 */
3019 xmlSchemaCleanupDoc(ctxt, root);
3020
3021 /*
3022 * Check the schemas top level element
3023 */
3024 if (!IS_SCHEMA(root, "schema")) {
3025 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3026 XML_SCHEMAP_NOT_SCHEMA,
3027 "File %s is not a schemas", schemaLocation, NULL);
3028 xmlFreeDoc(doc);
3029 return (-1);
3030 }
3031
3032 /*
3033 * register the include
3034 */
3035 include = (xmlSchemaIncludePtr) xmlMalloc(sizeof(xmlSchemaInclude));
3036 if (include == NULL) {
3037 xmlSchemaPErrMemory(ctxt, "allocating included schema", NULL);
3038 xmlFreeDoc(doc);
3039 return (-1);
3040 }
3041
3042 memset(include, 0, sizeof(xmlSchemaInclude));
3043 include->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1);
3044 include->doc = doc;
3045 include->next = schema->includes;
3046 schema->includes = include;
3047
3048
3049 /*
3050 * parse the declarations in the included file like if they
3051 * were in the original file.
3052 */
3053 xmlSchemaParseSchemaTopLevel(ctxt, schema, root->children);
3054
3055 return (1);
3056}
3057
3058/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003059 * xmlSchemaParseChoice:
3060 * @ctxt: a schema validation context
3061 * @schema: the schema being built
3062 * @node: a subtree containing XML Schema informations
3063 *
3064 * parse a XML schema Choice definition
3065 * *WARNING* this interface is highly subject to change
3066 *
3067 * Returns -1 in case of error, 0 if the declaration is inproper and
3068 * 1 in case of success.
3069 */
3070static xmlSchemaTypePtr
3071xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003072 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003073{
3074 xmlSchemaTypePtr type, subtype, last = NULL;
3075 xmlNodePtr child = NULL;
3076 xmlChar name[30];
3077
3078 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3079 return (NULL);
3080
3081
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003082 snprintf((char *) name, 30, "choice %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003083 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003084 if (type == NULL)
3085 return (NULL);
3086 type->node = node;
3087 type->type = XML_SCHEMA_TYPE_CHOICE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003088 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003089 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3090 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3091
3092 child = node->children;
3093 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003094 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3095 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003096 }
3097 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003098 (IS_SCHEMA(child, "group")) ||
3099 (IS_SCHEMA(child, "any")) ||
3100 (IS_SCHEMA(child, "choice")) ||
3101 (IS_SCHEMA(child, "sequence"))) {
3102 subtype = NULL;
3103 if (IS_SCHEMA(child, "element")) {
3104 subtype = (xmlSchemaTypePtr)
3105 xmlSchemaParseElement(ctxt, schema, child, 0);
3106 } else if (IS_SCHEMA(child, "group")) {
3107 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3108 } else if (IS_SCHEMA(child, "any")) {
3109 subtype = xmlSchemaParseAny(ctxt, schema, child);
3110 } else if (IS_SCHEMA(child, "sequence")) {
3111 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3112 } else if (IS_SCHEMA(child, "choice")) {
3113 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3114 }
3115 if (subtype != NULL) {
3116 if (last == NULL) {
3117 type->subtypes = subtype;
3118 last = subtype;
3119 } else {
3120 last->next = subtype;
3121 last = subtype;
3122 }
3123 last->next = NULL;
3124 }
3125 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003126 }
3127 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003128 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_CHOICE_CHILD,
3129 "Choice %s has unexpected content\n", type->name,
3130 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003131 }
3132
3133 return (type);
3134}
3135
3136/**
3137 * xmlSchemaParseSequence:
3138 * @ctxt: a schema validation context
3139 * @schema: the schema being built
3140 * @node: a subtree containing XML Schema informations
3141 *
3142 * parse a XML schema Sequence definition
3143 * *WARNING* this interface is highly subject to change
3144 *
3145 * Returns -1 in case of error, 0 if the declaration is inproper and
3146 * 1 in case of success.
3147 */
3148static xmlSchemaTypePtr
3149xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003150 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003151{
3152 xmlSchemaTypePtr type, subtype, last = NULL;
3153 xmlNodePtr child = NULL;
3154 xmlChar name[30];
3155
3156 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3157 return (NULL);
3158
3159
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003160 snprintf((char *) name, 30, "sequence %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003161 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003162 if (type == NULL)
3163 return (NULL);
3164 type->node = node;
3165 type->type = XML_SCHEMA_TYPE_SEQUENCE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003166 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003167 type->minOccurs = xmlGetMinOccurs(ctxt, node);
3168 type->maxOccurs = xmlGetMaxOccurs(ctxt, node);
3169
3170 child = node->children;
3171 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003172 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3173 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003174 }
3175 while ((IS_SCHEMA(child, "element")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003176 (IS_SCHEMA(child, "group")) ||
3177 (IS_SCHEMA(child, "any")) ||
3178 (IS_SCHEMA(child, "choice")) ||
3179 (IS_SCHEMA(child, "sequence"))) {
3180 subtype = NULL;
3181 if (IS_SCHEMA(child, "element")) {
3182 subtype = (xmlSchemaTypePtr)
3183 xmlSchemaParseElement(ctxt, schema, child, 0);
3184 } else if (IS_SCHEMA(child, "group")) {
3185 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3186 } else if (IS_SCHEMA(child, "any")) {
3187 subtype = xmlSchemaParseAny(ctxt, schema, child);
3188 } else if (IS_SCHEMA(child, "choice")) {
3189 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3190 } else if (IS_SCHEMA(child, "sequence")) {
3191 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3192 }
3193 if (subtype != NULL) {
3194 if (last == NULL) {
3195 type->subtypes = subtype;
3196 last = subtype;
3197 } else {
3198 last->next = subtype;
3199 last = subtype;
3200 }
3201 last->next = NULL;
3202 }
3203 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003204 }
3205 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003206 xmlSchemaPErr2(ctxt, node, child,
3207 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD,
3208 "Sequence %s has unexpected content\n", type->name,
3209 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003210 }
3211
3212 return (type);
3213}
3214
3215/**
3216 * xmlSchemaParseRestriction:
3217 * @ctxt: a schema validation context
3218 * @schema: the schema being built
3219 * @node: a subtree containing XML Schema informations
3220 * @simple: is that part of a simple type.
3221 *
3222 * parse a XML schema Restriction definition
3223 * *WARNING* this interface is highly subject to change
3224 *
3225 * Returns the type definition or NULL in case of error
3226 */
3227static xmlSchemaTypePtr
3228xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3229 xmlNodePtr node, int simple)
3230{
3231 xmlSchemaTypePtr type, subtype;
3232 xmlSchemaFacetPtr facet, lastfacet = NULL;
3233 xmlNodePtr child = NULL;
3234 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003235 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003236
3237 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3238 return (NULL);
3239
3240 oldcontainer = ctxt->container;
3241
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003242 snprintf((char *) name, 30, "restriction %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003243 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003244 if (type == NULL)
3245 return (NULL);
3246 type->node = node;
3247 type->type = XML_SCHEMA_TYPE_RESTRICTION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003248 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003249 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3250 if ((!simple) && (type->base == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003251 xmlSchemaPErr2(ctxt, node, child,
3252 XML_SCHEMAP_RESTRICTION_NONAME_NOREF,
3253 "Restriction %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003254 }
3255 ctxt->container = name;
3256
3257 child = node->children;
3258 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003259 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3260 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003261 }
3262 subtype = NULL;
3263
3264 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003265 subtype = (xmlSchemaTypePtr)
3266 xmlSchemaParseAll(ctxt, schema, child);
3267 child = child->next;
3268 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003269 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003270 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3271 child = child->next;
3272 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003273 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003274 subtype = (xmlSchemaTypePtr)
3275 xmlSchemaParseSequence(ctxt, schema, child);
3276 child = child->next;
3277 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003278 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003279 subtype = (xmlSchemaTypePtr)
3280 xmlSchemaParseGroup(ctxt, schema, child);
3281 child = child->next;
3282 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003283 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003284 if (IS_SCHEMA(child, "simpleType")) {
3285 subtype = (xmlSchemaTypePtr)
3286 xmlSchemaParseSimpleType(ctxt, schema, child);
3287 child = child->next;
3288 type->baseType = subtype;
3289 }
3290 /*
3291 * Facets
3292 */
Daniel Veillard4255d502002-04-16 15:50:10 +00003293 while ((IS_SCHEMA(child, "minInclusive")) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003294 (IS_SCHEMA(child, "minExclusive")) ||
3295 (IS_SCHEMA(child, "maxInclusive")) ||
3296 (IS_SCHEMA(child, "maxExclusive")) ||
3297 (IS_SCHEMA(child, "totalDigits")) ||
3298 (IS_SCHEMA(child, "fractionDigits")) ||
3299 (IS_SCHEMA(child, "pattern")) ||
3300 (IS_SCHEMA(child, "enumeration")) ||
3301 (IS_SCHEMA(child, "whiteSpace")) ||
3302 (IS_SCHEMA(child, "length")) ||
3303 (IS_SCHEMA(child, "maxLength")) ||
3304 (IS_SCHEMA(child, "minLength"))) {
3305 facet = xmlSchemaParseFacet(ctxt, schema, child);
3306 if (facet != NULL) {
3307 if (lastfacet == NULL) {
3308 type->facets = facet;
3309 lastfacet = facet;
3310 } else {
3311 lastfacet->next = facet;
3312 lastfacet = facet;
3313 }
3314 lastfacet->next = NULL;
3315 }
3316 child = child->next;
3317 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003318 }
3319 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3320 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003321 xmlSchemaPErr2(ctxt, node, child,
3322 XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD,
3323 "Restriction %s has unexpected content\n",
3324 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003325 }
3326 ctxt->container = oldcontainer;
3327 return (type);
3328}
3329
3330/**
3331 * xmlSchemaParseExtension:
3332 * @ctxt: a schema validation context
3333 * @schema: the schema being built
3334 * @node: a subtree containing XML Schema informations
3335 *
3336 * parse a XML schema Extension definition
3337 * *WARNING* this interface is highly subject to change
3338 *
3339 * Returns the type definition or NULL in case of error
3340 */
3341static xmlSchemaTypePtr
3342xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003343 xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003344{
3345 xmlSchemaTypePtr type, subtype;
3346 xmlNodePtr child = NULL;
3347 xmlChar name[30];
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003348 const xmlChar *oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003349
3350 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3351 return (NULL);
3352
3353 oldcontainer = ctxt->container;
3354
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003355 snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003356 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003357 if (type == NULL)
3358 return (NULL);
3359 type->node = node;
3360 type->type = XML_SCHEMA_TYPE_EXTENSION;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003361 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003362 ctxt->container = name;
3363
3364 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs));
3365 if (type->base == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003366 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_EXTENSION_NO_BASE,
3367 "Extension %s has no base\n", type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003368 }
3369 child = node->children;
3370 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003371 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3372 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003373 }
3374 subtype = NULL;
3375
3376 if (IS_SCHEMA(child, "all")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003377 subtype = xmlSchemaParseAll(ctxt, schema, child);
3378 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003379 } else if (IS_SCHEMA(child, "choice")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003380 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3381 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003382 } else if (IS_SCHEMA(child, "sequence")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003383 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3384 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003385 } else if (IS_SCHEMA(child, "group")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003386 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3387 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003388 }
3389 if (subtype != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003390 type->subtypes = subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00003391 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
3392 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003393 xmlSchemaPErr2(ctxt, node, child,
3394 XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD,
3395 "Extension %s has unexpected content\n", type->name,
3396 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003397 }
3398 ctxt->container = oldcontainer;
3399 return (type);
3400}
3401
3402/**
3403 * xmlSchemaParseSimpleContent:
3404 * @ctxt: a schema validation context
3405 * @schema: the schema being built
3406 * @node: a subtree containing XML Schema informations
3407 *
3408 * parse a XML schema SimpleContent definition
3409 * *WARNING* this interface is highly subject to change
3410 *
3411 * Returns the type definition or NULL in case of error
3412 */
3413static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003414xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt,
3415 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003416{
3417 xmlSchemaTypePtr type, subtype;
3418 xmlNodePtr child = NULL;
3419 xmlChar name[30];
3420
3421 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3422 return (NULL);
3423
3424
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003425 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003426 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003427 if (type == NULL)
3428 return (NULL);
3429 type->node = node;
3430 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003431 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003432
3433 child = node->children;
3434 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003435 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3436 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003437 }
3438 subtype = NULL;
3439 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003440 subtype = (xmlSchemaTypePtr)
3441 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3442 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003443 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003444 subtype = (xmlSchemaTypePtr)
3445 xmlSchemaParseExtension(ctxt, schema, child);
3446 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003447 }
3448 type->subtypes = subtype;
3449 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003450 xmlSchemaPErr2(ctxt, node, child,
3451 XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD,
3452 "SimpleContent %s has unexpected content\n",
3453 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003454 }
3455 return (type);
3456}
3457
3458/**
3459 * xmlSchemaParseComplexContent:
3460 * @ctxt: a schema validation context
3461 * @schema: the schema being built
3462 * @node: a subtree containing XML Schema informations
3463 *
3464 * parse a XML schema ComplexContent definition
3465 * *WARNING* this interface is highly subject to change
3466 *
3467 * Returns the type definition or NULL in case of error
3468 */
3469static xmlSchemaTypePtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003470xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt,
3471 xmlSchemaPtr schema, xmlNodePtr node)
Daniel Veillard4255d502002-04-16 15:50:10 +00003472{
3473 xmlSchemaTypePtr type, subtype;
3474 xmlNodePtr child = NULL;
3475 xmlChar name[30];
3476
3477 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3478 return (NULL);
3479
3480
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003481 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003482 type = xmlSchemaAddType(ctxt, schema, name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003483 if (type == NULL)
3484 return (NULL);
3485 type->node = node;
3486 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003487 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003488
3489 child = node->children;
3490 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003491 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3492 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003493 }
3494 subtype = NULL;
3495 if (IS_SCHEMA(child, "restriction")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003496 subtype = (xmlSchemaTypePtr)
3497 xmlSchemaParseRestriction(ctxt, schema, child, 0);
3498 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003499 } else if (IS_SCHEMA(child, "extension")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003500 subtype = (xmlSchemaTypePtr)
3501 xmlSchemaParseExtension(ctxt, schema, child);
3502 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003503 }
3504 type->subtypes = subtype;
3505 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003506 xmlSchemaPErr2(ctxt, node, child,
3507 XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD,
3508 "ComplexContent %s has unexpected content\n",
3509 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003510 }
3511 return (type);
3512}
3513
3514/**
3515 * xmlSchemaParseComplexType:
3516 * @ctxt: a schema validation context
3517 * @schema: the schema being built
3518 * @node: a subtree containing XML Schema informations
3519 *
3520 * parse a XML schema Complex Type definition
3521 * *WARNING* this interface is highly subject to change
3522 *
3523 * Returns the type definition or NULL in case of error
3524 */
3525static xmlSchemaTypePtr
3526xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
3527 xmlNodePtr node)
3528{
3529 xmlSchemaTypePtr type, subtype;
3530 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003531 const xmlChar *name;
3532 const xmlChar *oldcontainer;
3533 char buf[100];
Daniel Veillard4255d502002-04-16 15:50:10 +00003534
3535 if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
3536 return (NULL);
3537
3538 oldcontainer = ctxt->container;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003539 name = xmlSchemaGetProp(ctxt, node, "name");
Daniel Veillard4255d502002-04-16 15:50:10 +00003540 if (name == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003541
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003542 snprintf(buf, 99, "anontype %d", ctxt->counter++ + 1);
3543 name = (const xmlChar *)buf;
3544 type = xmlSchemaAddType(ctxt, schema, name, NULL);
3545 } else {
3546 const xmlChar *local, *ns;
3547
3548 local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns);
3549 type = xmlSchemaAddType(ctxt, schema, local, ns);
Daniel Veillard4255d502002-04-16 15:50:10 +00003550 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003551 if (type == NULL) {
Daniel Veillard4255d502002-04-16 15:50:10 +00003552 return (NULL);
3553 }
3554 type->node = node;
3555 type->type = XML_SCHEMA_TYPE_COMPLEX;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003556 type->id = xmlSchemaGetProp(ctxt, node, "id");
Daniel Veillard4255d502002-04-16 15:50:10 +00003557 ctxt->container = name;
3558
3559 child = node->children;
3560 if (IS_SCHEMA(child, "annotation")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003561 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child);
3562 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003563 }
3564 if (IS_SCHEMA(child, "simpleContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003565 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child);
3566 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003567 } else if (IS_SCHEMA(child, "complexContent")) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003568 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child);
3569 child = child->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00003570 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003571 subtype = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003572
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003573 if (IS_SCHEMA(child, "all")) {
3574 subtype = xmlSchemaParseAll(ctxt, schema, child);
3575 child = child->next;
3576 } else if (IS_SCHEMA(child, "choice")) {
3577 subtype = xmlSchemaParseChoice(ctxt, schema, child);
3578 child = child->next;
3579 } else if (IS_SCHEMA(child, "sequence")) {
3580 subtype = xmlSchemaParseSequence(ctxt, schema, child);
3581 child = child->next;
3582 } else if (IS_SCHEMA(child, "group")) {
3583 subtype = xmlSchemaParseGroup(ctxt, schema, child);
3584 child = child->next;
3585 }
3586 if (subtype != NULL)
3587 type->subtypes = subtype;
3588 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type);
Daniel Veillard4255d502002-04-16 15:50:10 +00003589 }
3590 if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003591 xmlSchemaPErr2(ctxt, node, child,
3592 XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD,
3593 "ComplexType %s has unexpected content\n",
3594 type->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003595 }
3596 ctxt->container = oldcontainer;
Daniel Veillard4255d502002-04-16 15:50:10 +00003597 return (type);
3598}
3599
Daniel Veillard4255d502002-04-16 15:50:10 +00003600/**
3601 * xmlSchemaParseSchema:
3602 * @ctxt: a schema validation context
3603 * @node: a subtree containing XML Schema informations
3604 *
3605 * parse a XML schema definition from a node set
3606 * *WARNING* this interface is highly subject to change
3607 *
3608 * Returns the internal XML Schema structure built from the resource or
3609 * NULL in case of error
3610 */
3611static xmlSchemaPtr
3612xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
3613{
3614 xmlSchemaPtr schema = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00003615 xmlNodePtr child = NULL;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003616 const xmlChar *val;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003617 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003618
3619 if ((ctxt == NULL) || (node == NULL))
3620 return (NULL);
3621
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003622 nberrors = ctxt->nberrors;
3623 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00003624 if (IS_SCHEMA(node, "schema")) {
3625 schema = xmlSchemaNewSchema(ctxt);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003626 if (schema == NULL)
3627 return (NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003628 val = xmlSchemaGetProp(ctxt, node, "targetNamespace");
3629 if (val != NULL) {
3630 schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1);
3631 } else {
3632 schema->targetNamespace = NULL;
3633 }
3634 schema->id = xmlSchemaGetProp(ctxt, node, "id");
3635 schema->version = xmlSchemaGetProp(ctxt, node, "version");
3636 val = xmlSchemaGetProp(ctxt, node, "elementFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003637 if (val != NULL) {
3638 if (xmlStrEqual(val, BAD_CAST "qualified"))
3639 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3640 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3641 xmlSchemaPErr2(ctxt, node, child,
3642 XML_SCHEMAP_ELEMFORMDEFAULT_VALUE,
3643 "Invalid value %s for elementFormDefault\n",
3644 val, NULL);
3645 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003646 } else {
3647 schema->flags |= XML_SCHEMAS_QUALIF_ELEM;
3648 }
3649 val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003650 if (val != NULL) {
3651 if (xmlStrEqual(val, BAD_CAST "qualified"))
3652 schema->flags |= XML_SCHEMAS_QUALIF_ATTR;
3653 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) {
3654 xmlSchemaPErr2(ctxt, node, child,
3655 XML_SCHEMAP_ATTRFORMDEFAULT_VALUE,
3656 "Invalid value %s for attributeFormDefault\n",
3657 val, NULL);
3658 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003659 }
Daniel Veillard4255d502002-04-16 15:50:10 +00003660
Daniel Veillardbd2904b2003-11-25 15:38:59 +00003661 xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children);
3662 } else {
3663 xmlDocPtr doc;
3664
3665 doc = node->doc;
3666
3667 if ((doc != NULL) && (doc->URL != NULL)) {
3668 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3669 XML_SCHEMAP_NOT_SCHEMA,
3670 "File %s is not a schemas", doc->URL, NULL);
3671 } else {
3672 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
3673 XML_SCHEMAP_NOT_SCHEMA,
3674 "File is not a schemas", NULL, NULL);
3675 }
3676 return(NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003677 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003678 if (ctxt->nberrors != 0) {
3679 if (schema != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003680 xmlSchemaFree(schema);
3681 schema = NULL;
3682 }
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00003683 }
3684 ctxt->nberrors = nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00003685#ifdef DEBUG
3686 if (schema == NULL)
3687 xmlGenericError(xmlGenericErrorContext,
3688 "xmlSchemaParse() failed\n");
3689#endif
3690
3691 return (schema);
3692}
3693
3694/************************************************************************
3695 * *
3696 * Validating using Schemas *
3697 * *
3698 ************************************************************************/
3699
3700/************************************************************************
3701 * *
3702 * Reading/Writing Schemas *
3703 * *
3704 ************************************************************************/
3705
3706/**
3707 * xmlSchemaNewParserCtxt:
3708 * @URL: the location of the schema
3709 *
3710 * Create an XML Schemas parse context for that file/resource expected
3711 * to contain an XML Schemas file.
3712 *
3713 * Returns the parser context or NULL in case of error
3714 */
3715xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003716xmlSchemaNewParserCtxt(const char *URL)
3717{
Daniel Veillard4255d502002-04-16 15:50:10 +00003718 xmlSchemaParserCtxtPtr ret;
3719
3720 if (URL == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003721 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003722
3723 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3724 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003725 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3726 NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00003727 return (NULL);
3728 }
3729 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003730 ret->dict = xmlDictCreate();
3731 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003732 return (ret);
3733}
3734
3735/**
Daniel Veillard6045c902002-10-09 21:13:59 +00003736 * xmlSchemaNewMemParserCtxt:
3737 * @buffer: a pointer to a char array containing the schemas
3738 * @size: the size of the array
3739 *
3740 * Create an XML Schemas parse context for that memory buffer expected
3741 * to contain an XML Schemas file.
3742 *
3743 * Returns the parser context or NULL in case of error
3744 */
3745xmlSchemaParserCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003746xmlSchemaNewMemParserCtxt(const char *buffer, int size)
3747{
Daniel Veillard6045c902002-10-09 21:13:59 +00003748 xmlSchemaParserCtxtPtr ret;
3749
3750 if ((buffer == NULL) || (size <= 0))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003751 return (NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003752
3753 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3754 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003755 xmlSchemaPErrMemory(NULL, "allocating schama parser context",
3756 NULL);
Daniel Veillard6045c902002-10-09 21:13:59 +00003757 return (NULL);
3758 }
3759 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3760 ret->buffer = buffer;
3761 ret->size = size;
3762 return (ret);
3763}
3764
3765/**
Daniel Veillard9d751502003-10-29 13:21:47 +00003766 * xmlSchemaNewDocParserCtxt:
3767 * @doc: a preparsed document tree
3768 *
3769 * Create an XML Schemas parse context for that document.
3770 * NB. The document may be modified during the parsing process.
3771 *
3772 * Returns the parser context or NULL in case of error
3773 */
3774xmlSchemaParserCtxtPtr
3775xmlSchemaNewDocParserCtxt(xmlDocPtr doc)
3776{
3777 xmlSchemaParserCtxtPtr ret;
3778
3779 if (doc == NULL)
3780 return (NULL);
3781
3782 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
3783 if (ret == NULL) {
3784 xmlSchemaPErrMemory(NULL, "allocating schema parser context",
3785 NULL);
3786 return (NULL);
3787 }
3788 memset(ret, 0, sizeof(xmlSchemaParserCtxt));
3789 ret->doc = doc;
3790
3791 return (ret);
3792}
3793
3794/**
Daniel Veillard4255d502002-04-16 15:50:10 +00003795 * xmlSchemaFreeParserCtxt:
3796 * @ctxt: the schema parser context
3797 *
3798 * Free the resources associated to the schema parser context
3799 */
3800void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003801xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt)
3802{
Daniel Veillard4255d502002-04-16 15:50:10 +00003803 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003804 return;
Daniel Veillard6045c902002-10-09 21:13:59 +00003805 if (ctxt->doc != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003806 xmlFreeDoc(ctxt->doc);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00003807 xmlDictFree(ctxt->dict);
Daniel Veillard4255d502002-04-16 15:50:10 +00003808 xmlFree(ctxt);
3809}
3810
3811/************************************************************************
3812 * *
3813 * Building the content models *
3814 * *
3815 ************************************************************************/
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003816
Daniel Veillard4255d502002-04-16 15:50:10 +00003817/**
3818 * xmlSchemaBuildAContentModel:
3819 * @type: the schema type definition
3820 * @ctxt: the schema parser context
3821 * @name: the element name whose content is being built
3822 *
3823 * Generate the automata sequence needed for that type
3824 */
3825static void
3826xmlSchemaBuildAContentModel(xmlSchemaTypePtr type,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003827 xmlSchemaParserCtxtPtr ctxt,
3828 const xmlChar * name)
3829{
Daniel Veillard4255d502002-04-16 15:50:10 +00003830 if (type == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003831 xmlGenericError(xmlGenericErrorContext,
3832 "Found unexpected type = NULL in %s content model\n",
3833 name);
3834 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00003835 }
3836 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003837 case XML_SCHEMA_TYPE_ANY:
3838 /* TODO : handle the namespace too */
3839 /* TODO : make that a specific transition type */
3840 TODO ctxt->state =
3841 xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL,
3842 BAD_CAST "*", NULL);
3843 break;
3844 case XML_SCHEMA_TYPE_ELEMENT:{
3845 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
Daniel Veillard32370232002-10-16 14:08:14 +00003846
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003847 /* TODO : handle the namespace too */
3848 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003849
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003850 if (elem->maxOccurs >= UNBOUNDED) {
3851 if (elem->minOccurs > 1) {
3852 xmlAutomataStatePtr tmp;
3853 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003854
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003855 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3856 oldstate,
3857 NULL);
3858 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003859
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003860 counter = xmlAutomataNewCounter(ctxt->am,
3861 elem->minOccurs -
3862 1, UNBOUNDED);
Daniel Veillard32370232002-10-16 14:08:14 +00003863
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003864 if (elem->refDecl != NULL) {
3865 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3866 elem->refDecl,
3867 ctxt,
3868 elem->refDecl->
3869 name);
3870 } else {
3871 ctxt->state =
3872 xmlAutomataNewTransition(ctxt->am,
3873 ctxt->state, NULL,
3874 elem->name, type);
3875 }
3876 tmp = ctxt->state;
3877 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3878 counter);
3879 ctxt->state =
3880 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
3881 counter);
Daniel Veillard32370232002-10-16 14:08:14 +00003882
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003883 } else {
3884 if (elem->refDecl != NULL) {
3885 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3886 elem->refDecl,
3887 ctxt,
3888 elem->refDecl->
3889 name);
3890 } else {
3891 ctxt->state =
3892 xmlAutomataNewTransition(ctxt->am,
3893 ctxt->state, NULL,
3894 elem->name, type);
3895 }
3896 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3897 oldstate);
3898 if (elem->minOccurs == 0) {
3899 /* basically an elem* */
3900 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3901 ctxt->state);
3902 }
3903 }
3904 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) {
3905 xmlAutomataStatePtr tmp;
3906 int counter;
Daniel Veillard32370232002-10-16 14:08:14 +00003907
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003908 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3909 oldstate, NULL);
3910 oldstate = ctxt->state;
Daniel Veillard32370232002-10-16 14:08:14 +00003911
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003912 counter = xmlAutomataNewCounter(ctxt->am,
3913 elem->minOccurs - 1,
3914 elem->maxOccurs - 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00003915
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003916 if (elem->refDecl != NULL) {
3917 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3918 elem->refDecl, ctxt,
3919 elem->refDecl->name);
3920 } else {
3921 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3922 ctxt->state,
3923 NULL,
3924 elem->name,
3925 type);
3926 }
3927 tmp = ctxt->state;
3928 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
3929 counter);
3930 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp,
3931 NULL,
3932 counter);
3933 if (elem->minOccurs == 0) {
3934 /* basically an elem? */
3935 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3936 ctxt->state);
3937 }
Daniel Veillardb39bc392002-10-26 19:29:51 +00003938
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003939 } else {
3940 if (elem->refDecl != NULL) {
3941 xmlSchemaBuildAContentModel((xmlSchemaTypePtr)
3942 elem->refDecl, ctxt,
3943 elem->refDecl->name);
3944 } else {
3945 ctxt->state = xmlAutomataNewTransition(ctxt->am,
3946 ctxt->state,
3947 NULL,
3948 elem->name,
3949 type);
3950 }
3951 if (elem->minOccurs == 0) {
3952 /* basically an elem? */
3953 xmlAutomataNewEpsilon(ctxt->am, oldstate,
3954 ctxt->state);
3955 }
3956 }
3957 break;
3958 }
3959 case XML_SCHEMA_TYPE_SEQUENCE:{
3960 xmlSchemaTypePtr subtypes;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003961
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003962 /*
3963 * If max and min occurances are default (1) then
3964 * simply iterate over the subtypes
3965 */
3966 if ((type->minOccurs == 1) && (type->maxOccurs == 1)) {
3967 subtypes = type->subtypes;
3968 while (subtypes != NULL) {
3969 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
3970 subtypes = subtypes->next;
3971 }
3972 } else {
3973 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003974
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003975 if (type->maxOccurs >= UNBOUNDED) {
3976 if (type->minOccurs > 1) {
3977 xmlAutomataStatePtr tmp;
3978 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003979
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003980 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
3981 oldstate,
3982 NULL);
3983 oldstate = ctxt->state;
Daniel Veillardb39bc392002-10-26 19:29:51 +00003984
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003985 counter = xmlAutomataNewCounter(ctxt->am,
3986 type->
3987 minOccurs - 1,
3988 UNBOUNDED);
Daniel Veillardb39bc392002-10-26 19:29:51 +00003989
Daniel Veillardd0c9c322003-10-10 00:49:42 +00003990 subtypes = type->subtypes;
3991 while (subtypes != NULL) {
3992 xmlSchemaBuildAContentModel(subtypes, ctxt,
3993 name);
3994 subtypes = subtypes->next;
3995 }
3996 tmp = ctxt->state;
3997 xmlAutomataNewCountedTrans(ctxt->am, tmp,
3998 oldstate, counter);
3999 ctxt->state =
4000 xmlAutomataNewCounterTrans(ctxt->am, tmp,
4001 NULL, counter);
Daniel Veillardb39bc392002-10-26 19:29:51 +00004002
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004003 } else {
4004 subtypes = type->subtypes;
4005 while (subtypes != NULL) {
4006 xmlSchemaBuildAContentModel(subtypes, ctxt,
4007 name);
4008 subtypes = subtypes->next;
4009 }
4010 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
4011 oldstate);
4012 if (type->minOccurs == 0) {
4013 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4014 ctxt->state);
4015 }
4016 }
4017 } else if ((type->maxOccurs > 1)
4018 || (type->minOccurs > 1)) {
4019 xmlAutomataStatePtr tmp;
4020 int counter;
Daniel Veillardb39bc392002-10-26 19:29:51 +00004021
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004022 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
4023 oldstate,
4024 NULL);
4025 oldstate = ctxt->state;
Daniel Veillard4255d502002-04-16 15:50:10 +00004026
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004027 counter = xmlAutomataNewCounter(ctxt->am,
4028 type->minOccurs -
4029 1,
4030 type->maxOccurs -
4031 1);
Daniel Veillard4255d502002-04-16 15:50:10 +00004032
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004033 subtypes = type->subtypes;
4034 while (subtypes != NULL) {
4035 xmlSchemaBuildAContentModel(subtypes, ctxt,
4036 name);
4037 subtypes = subtypes->next;
4038 }
4039 tmp = ctxt->state;
4040 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate,
4041 counter);
4042 ctxt->state =
4043 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL,
4044 counter);
4045 if (type->minOccurs == 0) {
4046 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4047 ctxt->state);
4048 }
Daniel Veillardb509f152002-04-17 16:28:10 +00004049
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004050 } else {
4051 subtypes = type->subtypes;
4052 while (subtypes != NULL) {
4053 xmlSchemaBuildAContentModel(subtypes, ctxt,
4054 name);
4055 subtypes = subtypes->next;
4056 }
4057 if (type->minOccurs == 0) {
4058 xmlAutomataNewEpsilon(ctxt->am, oldstate,
4059 ctxt->state);
4060 }
4061 }
4062 }
4063 break;
4064 }
4065 case XML_SCHEMA_TYPE_CHOICE:{
4066 xmlSchemaTypePtr subtypes;
4067 xmlAutomataStatePtr start, end;
Daniel Veillardb509f152002-04-17 16:28:10 +00004068
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004069 start = ctxt->state;
4070 end = xmlAutomataNewState(ctxt->am);
Daniel Veillard7646b182002-04-20 06:41:40 +00004071
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004072 /*
4073 * iterate over the subtypes and remerge the end with an
4074 * epsilon transition
4075 */
4076 if (type->maxOccurs == 1) {
4077 subtypes = type->subtypes;
4078 while (subtypes != NULL) {
4079 ctxt->state = start;
4080 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4081 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end);
4082 subtypes = subtypes->next;
4083 }
4084 } else {
4085 int counter;
4086 xmlAutomataStatePtr hop;
4087 int maxOccurs = type->maxOccurs == UNBOUNDED ?
4088 UNBOUNDED : type->maxOccurs - 1;
4089 int minOccurs =
4090 type->minOccurs < 1 ? 0 : type->minOccurs - 1;
Daniel Veillard7646b182002-04-20 06:41:40 +00004091
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004092 /*
4093 * use a counter to keep track of the number of transtions
4094 * which went through the choice.
4095 */
4096 counter =
4097 xmlAutomataNewCounter(ctxt->am, minOccurs,
4098 maxOccurs);
4099 hop = xmlAutomataNewState(ctxt->am);
Daniel Veillard6231e842002-04-18 11:54:04 +00004100
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004101 subtypes = type->subtypes;
4102 while (subtypes != NULL) {
4103 ctxt->state = start;
4104 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4105 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop);
4106 subtypes = subtypes->next;
4107 }
4108 xmlAutomataNewCountedTrans(ctxt->am, hop, start,
4109 counter);
4110 xmlAutomataNewCounterTrans(ctxt->am, hop, end,
4111 counter);
4112 }
4113 if (type->minOccurs == 0) {
4114 xmlAutomataNewEpsilon(ctxt->am, start, end);
4115 }
4116 ctxt->state = end;
4117 break;
4118 }
4119 case XML_SCHEMA_TYPE_ALL:{
4120 xmlAutomataStatePtr start;
4121 xmlSchemaTypePtr subtypes;
4122 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type;
4123 int lax;
4124
4125 subtypes = type->subtypes;
4126 if (subtypes == NULL)
4127 break;
4128 start = ctxt->state;
4129 while (subtypes != NULL) {
4130 ctxt->state = start;
4131 elem = (xmlSchemaElementPtr) subtypes;
4132
4133 /* TODO : handle the namespace too */
4134 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) {
4135 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state,
4136 ctxt->state, elem->name, 1,
4137 1, subtypes);
4138 } else {
4139 xmlAutomataNewCountTrans(ctxt->am, ctxt->state,
4140 ctxt->state, elem->name,
4141 elem->minOccurs,
4142 elem->maxOccurs,
4143 subtypes);
4144 }
4145 subtypes = subtypes->next;
4146 }
4147 lax = type->minOccurs == 0;
4148 ctxt->state =
4149 xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL,
4150 lax);
4151 break;
4152 }
4153 case XML_SCHEMA_TYPE_RESTRICTION:
4154 if (type->subtypes != NULL)
4155 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4156 break;
4157 case XML_SCHEMA_TYPE_EXTENSION:
4158 if (type->baseType != NULL) {
4159 xmlSchemaTypePtr subtypes;
4160
4161 xmlSchemaBuildAContentModel(type->baseType, ctxt, name);
4162 subtypes = type->subtypes;
4163 while (subtypes != NULL) {
4164 xmlSchemaBuildAContentModel(subtypes, ctxt, name);
4165 subtypes = subtypes->next;
4166 }
4167 } else if (type->subtypes != NULL)
4168 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4169 break;
4170 case XML_SCHEMA_TYPE_GROUP:
4171 if (type->subtypes == NULL) {
4172 }
4173 case XML_SCHEMA_TYPE_COMPLEX:
4174 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
4175 if (type->subtypes != NULL)
4176 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name);
4177 break;
4178 default:
4179 xmlGenericError(xmlGenericErrorContext,
4180 "Found unexpected type %d in %s content model\n",
4181 type->type, name);
4182 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004183 }
4184}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004185
Daniel Veillard4255d502002-04-16 15:50:10 +00004186/**
4187 * xmlSchemaBuildContentModel:
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004188 * @elem: the element
Daniel Veillard4255d502002-04-16 15:50:10 +00004189 * @ctxt: the schema parser context
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004190 * @name: the element name
Daniel Veillard4255d502002-04-16 15:50:10 +00004191 *
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004192 * Builds the content model of the element.
Daniel Veillard4255d502002-04-16 15:50:10 +00004193 */
4194static void
4195xmlSchemaBuildContentModel(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004196 xmlSchemaParserCtxtPtr ctxt,
4197 const xmlChar * name)
4198{
Daniel Veillard4255d502002-04-16 15:50:10 +00004199 xmlAutomataStatePtr start;
4200
Daniel Veillard4255d502002-04-16 15:50:10 +00004201 if (elem->contModel != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004202 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004203 if (elem->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004204 elem->contentType = XML_SCHEMA_CONTENT_ANY;
4205 return;
Daniel Veillard88c58912002-04-23 07:12:20 +00004206 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004207 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004208 return;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004209 if ((elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC) ||
4210 (elem->subtypes->contentType == XML_SCHEMA_CONTENT_SIMPLE))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004211 return;
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004212
4213#ifdef DEBUG_CONTENT
4214 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004215 "Building content model for %s\n", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004216#endif
4217
Daniel Veillard4255d502002-04-16 15:50:10 +00004218 ctxt->am = xmlNewAutomata();
4219 if (ctxt->am == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004220 xmlGenericError(xmlGenericErrorContext,
4221 "Cannot create automata for elem %s\n", name);
4222 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004223 }
4224 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
4225 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name);
4226 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard4402ab42002-09-12 16:02:56 +00004227 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004228 if (elem->contModel == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004229 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_INTERNAL,
4230 "failed to compile %s content model\n", name, NULL);
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004231 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004232 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_NOTDETERMINIST,
4233 "Content model of %s is not determinist:\n", name,
4234 NULL);
Daniel Veillarde19fc232002-04-22 16:01:24 +00004235 } else {
Daniel Veillard118aed72002-09-24 14:13:13 +00004236#ifdef DEBUG_CONTENT_REGEXP
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004237 xmlGenericError(xmlGenericErrorContext,
4238 "Content model of %s:\n", name);
4239 xmlRegexpPrint(stderr, elem->contModel);
Daniel Veillard4255d502002-04-16 15:50:10 +00004240#endif
Daniel Veillarde19fc232002-04-22 16:01:24 +00004241 }
Daniel Veillarda84c0b32003-06-02 16:58:46 +00004242 ctxt->state = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00004243 xmlFreeAutomata(ctxt->am);
4244 ctxt->am = NULL;
4245}
4246
4247/**
4248 * xmlSchemaRefFixupCallback:
4249 * @elem: the schema element context
4250 * @ctxt: the schema parser context
4251 *
4252 * Free the resources associated to the schema parser context
4253 */
4254static void
4255xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004256 xmlSchemaParserCtxtPtr ctxt,
4257 const xmlChar * name,
4258 const xmlChar * context ATTRIBUTE_UNUSED,
4259 const xmlChar * namespace ATTRIBUTE_UNUSED)
Daniel Veillard4255d502002-04-16 15:50:10 +00004260{
4261 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004262 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004263 if (elem->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004264 xmlSchemaElementPtr elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004265
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004266 if (elem->subtypes != NULL) {
4267 xmlSchemaPErr(ctxt, elem->node,
4268 XML_SCHEMAP_INVALID_REF_AND_SUBTYPE,
4269 "Schemas: element %s have both ref and subtype\n",
4270 name, NULL);
4271 return;
4272 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004273 elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00004274
4275 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004276 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF,
4277 "Schemas: element %s ref to %s not found\n",
4278 name, elem->ref);
4279 return;
4280 }
4281 elem->refDecl = elemDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004282 } else if (elem->namedType != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004283 xmlSchemaTypePtr typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004284
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004285 if (elem->subtypes != NULL) {
4286 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE,
4287 "Schemas: element %s have both type and subtype\n",
4288 name, NULL);
4289 return;
4290 }
4291 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType,
4292 elem->namedTypeNs);
Daniel Veillard4255d502002-04-16 15:50:10 +00004293
4294 if (typeDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004295 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE,
4296 "Schemas: element %s type %s not found\n", name,
4297 elem->namedType);
4298 return;
4299 }
4300 elem->subtypes = typeDecl;
Daniel Veillard4255d502002-04-16 15:50:10 +00004301 }
4302}
4303
4304/**
4305 * xmlSchemaTypeFixup:
4306 * @typeDecl: the schema type definition
4307 * @ctxt: the schema parser context
4308 *
4309 * Fixes the content model of the type.
4310 */
4311static void
4312xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004313 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004314{
Daniel Veillard82bbbd42003-05-11 20:16:09 +00004315 if (typeDecl == NULL)
4316 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004317 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004318 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004319 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004320 switch (typeDecl->type) {
4321 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{
4322 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
4323 if (typeDecl->subtypes != NULL)
4324 typeDecl->contentType =
4325 typeDecl->subtypes->contentType;
4326 break;
4327 }
4328 case XML_SCHEMA_TYPE_RESTRICTION:{
4329 if (typeDecl->subtypes != NULL)
4330 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004331
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004332 if (typeDecl->base != NULL) {
4333 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004334
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004335 baseType =
4336 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4337 typeDecl->baseNs);
4338 if (baseType == NULL) {
4339 xmlSchemaPErr(ctxt, typeDecl->node,
4340 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004341 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004342 name, typeDecl->base);
4343 }
4344 typeDecl->baseType = baseType;
4345 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004346 if (typeDecl->subtypes == NULL)
4347 if (typeDecl->baseType != NULL)
4348 typeDecl->contentType =
4349 typeDecl->baseType->contentType;
4350 else
4351 /* 1.1.1 */
4352 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004353 else if ((typeDecl->subtypes->subtypes == NULL) &&
4354 ((typeDecl->subtypes->type ==
4355 XML_SCHEMA_TYPE_ALL)
4356 || (typeDecl->subtypes->type ==
4357 XML_SCHEMA_TYPE_SEQUENCE)))
4358 /* 1.1.2 */
4359 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4360 else if ((typeDecl->subtypes->type ==
4361 XML_SCHEMA_TYPE_CHOICE)
4362 && (typeDecl->subtypes->subtypes == NULL))
4363 /* 1.1.3 */
4364 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4365 else {
4366 /* 1.2 and 2.X are applied at the other layer */
4367 typeDecl->contentType =
4368 XML_SCHEMA_CONTENT_ELEMENTS;
4369 }
4370 break;
4371 }
4372 case XML_SCHEMA_TYPE_EXTENSION:{
4373 xmlSchemaContentType explicitContentType;
4374 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00004375
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004376 if (typeDecl->base != NULL) {
4377 xmlSchemaTypePtr baseType;
Daniel Veillard4255d502002-04-16 15:50:10 +00004378
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004379 baseType =
4380 xmlSchemaGetType(ctxt->schema, typeDecl->base,
4381 typeDecl->baseNs);
4382 if (baseType == NULL) {
4383 xmlSchemaPErr(ctxt, typeDecl->node,
4384 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
Daniel Veillard4255d502002-04-16 15:50:10 +00004385 "Schemas: type %s base type %s not found\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004386 name, typeDecl->base);
4387 }
4388 typeDecl->baseType = baseType;
4389 }
4390 if (typeDecl->subtypes != NULL)
4391 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004392
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004393 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS;
4394 if (typeDecl->subtypes == NULL)
4395 /* 1.1.1 */
4396 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4397 else if ((typeDecl->subtypes->subtypes == NULL) &&
4398 ((typeDecl->subtypes->type ==
4399 XML_SCHEMA_TYPE_ALL)
4400 || (typeDecl->subtypes->type ==
4401 XML_SCHEMA_TYPE_SEQUENCE)))
4402 /* 1.1.2 */
4403 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
4404 else if ((typeDecl->subtypes->type ==
4405 XML_SCHEMA_TYPE_CHOICE)
4406 && (typeDecl->subtypes->subtypes == NULL))
4407 /* 1.1.3 */
4408 explicitContentType = XML_SCHEMA_CONTENT_EMPTY;
Daniel Veillard4255d502002-04-16 15:50:10 +00004409
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004410 base = xmlSchemaGetType(ctxt->schema, typeDecl->base,
4411 typeDecl->baseNs);
4412 if (base == NULL) {
4413 xmlSchemaPErr(ctxt, typeDecl->node,
4414 XML_SCHEMAP_UNKNOWN_BASE_TYPE,
4415 "Schemas: base type %s of type %s not found\n",
4416 typeDecl->base, name);
4417 return;
4418 }
4419 xmlSchemaTypeFixup(base, ctxt, NULL);
4420 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
4421 /* 2.1 */
4422 typeDecl->contentType = base->contentType;
4423 } else if (base->contentType ==
4424 XML_SCHEMA_CONTENT_EMPTY) {
4425 /* 2.2 imbitable ! */
4426 typeDecl->contentType =
4427 XML_SCHEMA_CONTENT_ELEMENTS;
4428 } else {
4429 /* 2.3 imbitable pareil ! */
4430 typeDecl->contentType =
4431 XML_SCHEMA_CONTENT_ELEMENTS;
4432 }
4433 break;
4434 }
4435 case XML_SCHEMA_TYPE_COMPLEX:{
4436 if (typeDecl->subtypes == NULL) {
4437 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4438 } else {
4439 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4440 typeDecl->contentType =
4441 XML_SCHEMA_CONTENT_MIXED;
4442 else {
4443 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4444 NULL);
4445 if (typeDecl->subtypes != NULL)
4446 typeDecl->contentType =
4447 typeDecl->subtypes->contentType;
4448 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004449 if (typeDecl->attributes == NULL)
4450 typeDecl->attributes =
4451 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004452 }
4453 break;
4454 }
4455 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{
4456 if (typeDecl->subtypes == NULL) {
4457 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY;
4458 } else {
4459 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED)
4460 typeDecl->contentType =
4461 XML_SCHEMA_CONTENT_MIXED;
4462 else {
4463 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt,
4464 NULL);
4465 if (typeDecl->subtypes != NULL)
4466 typeDecl->contentType =
4467 typeDecl->subtypes->contentType;
4468 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00004469 if (typeDecl->attributes == NULL)
4470 typeDecl->attributes =
4471 typeDecl->subtypes->attributes;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004472 }
4473 break;
4474 }
4475 case XML_SCHEMA_TYPE_SEQUENCE:
4476 case XML_SCHEMA_TYPE_GROUP:
4477 case XML_SCHEMA_TYPE_ALL:
4478 case XML_SCHEMA_TYPE_CHOICE:
4479 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
4480 break;
4481 case XML_SCHEMA_TYPE_BASIC:
4482 case XML_SCHEMA_TYPE_ANY:
4483 case XML_SCHEMA_TYPE_FACET:
4484 case XML_SCHEMA_TYPE_SIMPLE:
4485 case XML_SCHEMA_TYPE_UR:
4486 case XML_SCHEMA_TYPE_ELEMENT:
4487 case XML_SCHEMA_TYPE_ATTRIBUTE:
4488 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
4489 case XML_SCHEMA_TYPE_NOTATION:
4490 case XML_SCHEMA_TYPE_LIST:
4491 case XML_SCHEMA_TYPE_UNION:
4492 case XML_SCHEMA_FACET_MININCLUSIVE:
4493 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4494 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4495 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
4496 case XML_SCHEMA_FACET_TOTALDIGITS:
4497 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4498 case XML_SCHEMA_FACET_PATTERN:
4499 case XML_SCHEMA_FACET_ENUMERATION:
4500 case XML_SCHEMA_FACET_WHITESPACE:
4501 case XML_SCHEMA_FACET_LENGTH:
4502 case XML_SCHEMA_FACET_MAXLENGTH:
4503 case XML_SCHEMA_FACET_MINLENGTH:
4504 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00004505 if (typeDecl->subtypes != NULL)
4506 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004507 break;
4508 }
4509 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004510#ifdef DEBUG_TYPE
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004511 if (typeDecl->node != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004512 xmlGenericError(xmlGenericErrorContext,
4513 "Type of %s : %s:%d :", name,
4514 typeDecl->node->doc->URL,
4515 xmlGetLineNo(typeDecl->node));
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004516 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004517 xmlGenericError(xmlGenericErrorContext, "Type of %s :", name);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00004518 }
Daniel Veillard8651f532002-04-17 09:06:27 +00004519 switch (typeDecl->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004520 case XML_SCHEMA_CONTENT_SIMPLE:
4521 xmlGenericError(xmlGenericErrorContext, "simple\n");
4522 break;
4523 case XML_SCHEMA_CONTENT_ELEMENTS:
4524 xmlGenericError(xmlGenericErrorContext, "elements\n");
4525 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004526 case XML_SCHEMA_CONTENT_UNKNOWN:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004527 xmlGenericError(xmlGenericErrorContext, "unknown !!!\n");
4528 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004529 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004530 xmlGenericError(xmlGenericErrorContext, "empty\n");
4531 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004532 case XML_SCHEMA_CONTENT_MIXED:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004533 xmlGenericError(xmlGenericErrorContext, "mixed\n");
4534 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004535 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004536 xmlGenericError(xmlGenericErrorContext, "mixed or elems\n");
4537 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004538 case XML_SCHEMA_CONTENT_BASIC:
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004539 xmlGenericError(xmlGenericErrorContext, "basic\n");
4540 break;
4541 default:
4542 xmlGenericError(xmlGenericErrorContext,
4543 "not registered !!!\n");
4544 break;
Daniel Veillard8651f532002-04-17 09:06:27 +00004545 }
4546#endif
Daniel Veillard4255d502002-04-16 15:50:10 +00004547}
4548
4549/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004550 * xmlSchemaCheckFacet:
4551 * @facet: the facet
4552 * @typeDecl: the schema type definition
4553 * @ctxt: the schema parser context or NULL
4554 * @name: name of the type
4555 *
4556 * Checks the default values types, especially for facets
4557 *
4558 * Returns 0 if okay or -1 in cae of error
4559 */
4560int
4561xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004562 xmlSchemaTypePtr typeDecl,
4563 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004564{
4565 static xmlSchemaTypePtr nonNegativeIntegerType = NULL;
4566 int ret = 0;
4567
4568 if (nonNegativeIntegerType == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004569 nonNegativeIntegerType =
4570 xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger",
4571 xmlSchemaNs);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004572 }
4573 switch (facet->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004574 case XML_SCHEMA_FACET_MININCLUSIVE:
4575 case XML_SCHEMA_FACET_MINEXCLUSIVE:
4576 case XML_SCHEMA_FACET_MAXINCLUSIVE:
4577 case XML_SCHEMA_FACET_MAXEXCLUSIVE:{
4578 /*
4579 * Okay we need to validate the value
4580 * at that point.
4581 */
4582 xmlSchemaValidCtxtPtr vctxt;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004583
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004584 vctxt = xmlSchemaNewValidCtxt(NULL);
4585 if (vctxt == NULL)
4586 break;
4587 xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4588 facet->value);
4589 facet->val = vctxt->value;
4590 vctxt->value = NULL;
4591 if (facet->val == NULL) {
4592 /* error code */
4593 if (ctxt != NULL) {
4594 xmlSchemaPErr(ctxt, facet->node,
4595 XML_SCHEMAP_INVALID_FACET,
4596 "Schemas: type %s facet value %s invalid\n",
4597 name, facet->value);
4598 }
4599 ret = -1;
4600 }
4601 xmlSchemaFreeValidCtxt(vctxt);
4602 break;
4603 }
4604 case XML_SCHEMA_FACET_ENUMERATION:{
4605 /*
4606 * Okay we need to validate the value
4607 * at that point.
4608 */
4609 xmlSchemaValidCtxtPtr vctxt;
4610 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004611
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004612 vctxt = xmlSchemaNewValidCtxt(NULL);
4613 if (vctxt == NULL)
4614 break;
4615 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl,
4616 facet->value);
4617 if (tmp != 0) {
4618 if (ctxt != NULL) {
4619 xmlSchemaPErr(ctxt, facet->node,
4620 XML_SCHEMAP_INVALID_ENUM,
4621 "Schemas: type %s enumeration value %s invalid\n",
4622 name, facet->value);
4623 }
4624 ret = -1;
4625 }
4626 xmlSchemaFreeValidCtxt(vctxt);
4627 break;
4628 }
4629 case XML_SCHEMA_FACET_PATTERN:
4630 facet->regexp = xmlRegexpCompile(facet->value);
4631 if (facet->regexp == NULL) {
4632 xmlSchemaPErr(ctxt, typeDecl->node,
4633 XML_SCHEMAP_REGEXP_INVALID,
4634 "Schemas: type %s facet regexp %s invalid\n",
4635 name, facet->value);
4636 ret = -1;
4637 }
4638 break;
4639 case XML_SCHEMA_FACET_TOTALDIGITS:
4640 case XML_SCHEMA_FACET_FRACTIONDIGITS:
4641 case XML_SCHEMA_FACET_LENGTH:
4642 case XML_SCHEMA_FACET_MAXLENGTH:
4643 case XML_SCHEMA_FACET_MINLENGTH:{
4644 int tmp;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004645
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004646 tmp =
4647 xmlSchemaValidatePredefinedType(nonNegativeIntegerType,
4648 facet->value,
4649 &facet->val);
4650 if (tmp != 0) {
4651 /* error code */
4652 if (ctxt != NULL) {
4653 xmlSchemaPErr(ctxt, facet->node,
4654 XML_SCHEMAP_INVALID_FACET_VALUE,
4655 "Schemas: type %s facet value %s invalid\n",
4656 name, facet->value);
4657 }
4658 ret = -1;
4659 }
4660 break;
4661 }
4662 case XML_SCHEMA_FACET_WHITESPACE:{
4663 if (xmlStrEqual(facet->value, BAD_CAST "preserve")) {
4664 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
4665 } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) {
4666 facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
4667 } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) {
4668 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
4669 } else {
4670 if (ctxt != NULL) {
4671 xmlSchemaPErr(ctxt, facet->node,
4672 XML_SCHEMAP_INVALID_WHITE_SPACE,
4673 "Schemas: type %s whiteSpace value %s invalid\n",
4674 name, facet->value);
4675 }
4676 ret = -1;
4677 }
4678 }
4679 default:
4680 break;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004681 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004682 return (ret);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00004683}
4684
4685/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004686 * xmlSchemaCheckDefaults:
4687 * @typeDecl: the schema type definition
4688 * @ctxt: the schema parser context
4689 *
4690 * Checks the default values types, especially for facets
4691 */
4692static void
4693xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004694 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004695{
Daniel Veillard4255d502002-04-16 15:50:10 +00004696 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004697 name = typeDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004698 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004699 if (typeDecl->facets != NULL) {
4700 xmlSchemaFacetPtr facet = typeDecl->facets;
4701
4702 while (facet != NULL) {
4703 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name);
4704 facet = facet->next;
4705 }
4706 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004707 }
4708}
4709
4710/**
Daniel Veillard13e04c62002-04-23 17:51:29 +00004711 * xmlSchemaAttrGrpFixup:
4712 * @attrgrpDecl: the schema attribute definition
4713 * @ctxt: the schema parser context
4714 * @name: the attribute name
4715 *
4716 * Fixes finish doing the computations on the attributes definitions
4717 */
4718static void
4719xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004720 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard13e04c62002-04-23 17:51:29 +00004721{
4722 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004723 name = attrgrpDecl->name;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004724 if (attrgrpDecl->attributes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004725 return;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004726 if (attrgrpDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004727 xmlSchemaAttributeGroupPtr ref;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004728
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004729 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref,
4730 attrgrpDecl->refNs);
4731 if (ref == NULL) {
4732 xmlSchemaPErr(ctxt, attrgrpDecl->node,
4733 XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP,
4734 "Schemas: attribute group %s reference %s not found\n",
4735 name, attrgrpDecl->ref);
4736 return;
4737 }
4738 xmlSchemaAttrGrpFixup(ref, ctxt, NULL);
4739 attrgrpDecl->attributes = ref->attributes;
Daniel Veillard13e04c62002-04-23 17:51:29 +00004740 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004741 xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF,
4742 "Schemas: attribute %s has no attributes nor reference\n",
4743 name, NULL);
Daniel Veillard13e04c62002-04-23 17:51:29 +00004744 }
4745}
4746
4747/**
Daniel Veillard4255d502002-04-16 15:50:10 +00004748 * xmlSchemaAttrFixup:
4749 * @attrDecl: the schema attribute definition
4750 * @ctxt: the schema parser context
4751 * @name: the attribute name
4752 *
4753 * Fixes finish doing the computations on the attributes definitions
4754 */
4755static void
4756xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004757 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name)
Daniel Veillard4255d502002-04-16 15:50:10 +00004758{
4759 if (name == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004760 name = attrDecl->name;
Daniel Veillard4255d502002-04-16 15:50:10 +00004761 if (attrDecl->subtypes != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004762 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004763 if (attrDecl->typeName != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004764 xmlSchemaTypePtr type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004765
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004766 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName,
4767 attrDecl->typeNs);
4768 if (type == NULL) {
4769 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE,
4770 "Schemas: attribute %s type %s not found\n",
4771 name, attrDecl->typeName);
4772 }
4773 attrDecl->subtypes = type;
Daniel Veillard4255d502002-04-16 15:50:10 +00004774 } else if (attrDecl->ref != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004775 xmlSchemaAttributePtr ref;
Daniel Veillard4255d502002-04-16 15:50:10 +00004776
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004777 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref,
4778 attrDecl->refNs);
4779 if (ref == NULL) {
4780 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF,
4781 "Schemas: attribute %s reference %s not found\n",
4782 name, attrDecl->ref);
4783 return;
4784 }
4785 xmlSchemaAttrFixup(ref, ctxt, NULL);
4786 attrDecl->subtypes = ref->subtypes;
Daniel Veillard4255d502002-04-16 15:50:10 +00004787 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004788 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF,
4789 "Schemas: attribute %s has no type nor reference\n",
4790 name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004791 }
4792}
4793
4794/**
4795 * xmlSchemaParse:
4796 * @ctxt: a schema validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004797 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004798 * parse a schema definition resource and build an internal
Daniel Veillard4255d502002-04-16 15:50:10 +00004799 * XML Shema struture which can be used to validate instances.
4800 * *WARNING* this interface is highly subject to change
4801 *
4802 * Returns the internal XML Schema structure built from the resource or
4803 * NULL in case of error
4804 */
4805xmlSchemaPtr
4806xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
4807{
4808 xmlSchemaPtr ret = NULL;
4809 xmlDocPtr doc;
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004810 xmlNodePtr root;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004811 int nberrors;
Daniel Veillard4255d502002-04-16 15:50:10 +00004812
4813 xmlSchemaInitTypes();
4814
Daniel Veillard6045c902002-10-09 21:13:59 +00004815 if (ctxt == NULL)
Daniel Veillard4255d502002-04-16 15:50:10 +00004816 return (NULL);
4817
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004818 nberrors = ctxt->nberrors;
4819 ctxt->nberrors = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00004820 ctxt->counter = 0;
4821 ctxt->container = NULL;
4822
4823 /*
4824 * First step is to parse the input document into an DOM/Infoset
4825 */
Daniel Veillard6045c902002-10-09 21:13:59 +00004826 if (ctxt->URL != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004827 doc = xmlReadFile((const char *) ctxt->URL, NULL,
4828 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004829 if (doc == NULL) {
4830 xmlSchemaPErr(ctxt, NULL,
4831 XML_SCHEMAP_FAILED_LOAD,
4832 "xmlSchemaParse: could not load %s\n",
4833 ctxt->URL, NULL);
4834 return (NULL);
4835 }
Daniel Veillard6045c902002-10-09 21:13:59 +00004836 } else if (ctxt->buffer != NULL) {
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004837 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL,
4838 SCHEMAS_PARSE_OPTIONS);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004839 if (doc == NULL) {
4840 xmlSchemaPErr(ctxt, NULL,
4841 XML_SCHEMAP_FAILED_PARSE,
4842 "xmlSchemaParse: could not parse\n",
4843 NULL, NULL);
4844 return (NULL);
4845 }
4846 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
4847 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard9d751502003-10-29 13:21:47 +00004848 } else if (ctxt->doc != NULL) {
4849 doc = ctxt->doc;
Daniel Veillard6045c902002-10-09 21:13:59 +00004850 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004851 xmlSchemaPErr(ctxt, NULL,
4852 XML_SCHEMAP_NOTHING_TO_PARSE,
4853 "xmlSchemaParse: could not parse\n",
4854 NULL, NULL);
4855 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00004856 }
4857
4858 /*
4859 * Then extract the root and Schema parse it
4860 */
4861 root = xmlDocGetRootElement(doc);
4862 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004863 xmlSchemaPErr(ctxt, (xmlNodePtr) doc,
4864 XML_SCHEMAP_NOROOT,
4865 "schemas has no root", NULL, NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00004866 xmlFreeDoc(doc);
Daniel Veillard4255d502002-04-16 15:50:10 +00004867 return (NULL);
4868 }
4869
4870 /*
4871 * Remove all the blank text nodes
4872 */
Daniel Veillardbd2904b2003-11-25 15:38:59 +00004873 xmlSchemaCleanupDoc(ctxt, root);
Daniel Veillard4255d502002-04-16 15:50:10 +00004874
4875 /*
4876 * Then do the parsing for good
4877 */
4878 ret = xmlSchemaParseSchema(ctxt, root);
Daniel Veillard1d913862003-11-21 00:28:39 +00004879 if (ret == NULL) {
4880 xmlFreeDoc(doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004881 return (NULL);
Daniel Veillard1d913862003-11-21 00:28:39 +00004882 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004883 ret->doc = doc;
4884
4885 /*
4886 * Then fix all the references.
4887 */
4888 ctxt->schema = ret;
4889 xmlHashScanFull(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004890 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004891
4892 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00004893 * Then fixup all attributes declarations
4894 */
4895 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt);
4896
4897 /*
4898 * Then fixup all attributes group declarations
4899 */
4900 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup,
4901 ctxt);
4902
4903 /*
Daniel Veillard4255d502002-04-16 15:50:10 +00004904 * Then fixup all types properties
4905 */
4906 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt);
4907
4908 /*
4909 * Then build the content model for all elements
4910 */
4911 xmlHashScan(ret->elemDecl,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004912 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004913
4914 /*
4915 * Then check the defaults part of the type like facets values
4916 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004917 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults,
4918 ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00004919
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004920 if (ctxt->nberrors != 0) {
4921 xmlSchemaFree(ret);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004922 ret = NULL;
Daniel Veillard75bb3bb2003-05-12 15:25:56 +00004923 }
Daniel Veillard4255d502002-04-16 15:50:10 +00004924 return (ret);
4925}
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004926
Daniel Veillard4255d502002-04-16 15:50:10 +00004927/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004928 * xmlSchemaSetParserErrors:
Daniel Veillard4255d502002-04-16 15:50:10 +00004929 * @ctxt: a schema validation context
Daniel Veillard01c13b52002-12-10 15:19:08 +00004930 * @err: the error callback
4931 * @warn: the warning callback
4932 * @ctx: contextual data for the callbacks
Daniel Veillard4255d502002-04-16 15:50:10 +00004933 *
Daniel Veillard01c13b52002-12-10 15:19:08 +00004934 * Set the callback functions used to handle errors for a validation context
Daniel Veillard4255d502002-04-16 15:50:10 +00004935 */
4936void
4937xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004938 xmlSchemaValidityErrorFunc err,
4939 xmlSchemaValidityWarningFunc warn, void *ctx)
4940{
Daniel Veillard4255d502002-04-16 15:50:10 +00004941 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004942 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00004943 ctxt->error = err;
4944 ctxt->warning = warn;
4945 ctxt->userData = ctx;
4946}
4947
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004948/**
4949 * xmlSchemaFacetTypeToString:
4950 * @type: the facet type
4951 *
4952 * Convert the xmlSchemaTypeType to a char string.
4953 *
4954 * Returns the char string representation of the facet type if the
4955 * type is a facet and an "Internal Error" string otherwise.
4956 */
4957static const char *
4958xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
4959{
4960 switch (type) {
4961 case XML_SCHEMA_FACET_PATTERN:
4962 return ("pattern");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004963 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004964 return ("maxExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004965 case XML_SCHEMA_FACET_MAXINCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004966 return ("maxInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004967 case XML_SCHEMA_FACET_MINEXCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004968 return ("minExclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004969 case XML_SCHEMA_FACET_MININCLUSIVE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004970 return ("minInclusive");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004971 case XML_SCHEMA_FACET_WHITESPACE:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004972 return ("whiteSpace");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004973 case XML_SCHEMA_FACET_ENUMERATION:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004974 return ("enumeration");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004975 case XML_SCHEMA_FACET_LENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004976 return ("length");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004977 case XML_SCHEMA_FACET_MAXLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004978 return ("maxLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004979 case XML_SCHEMA_FACET_MINLENGTH:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004980 return ("minLength");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004981 case XML_SCHEMA_FACET_TOTALDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004982 return ("totalDigits");
Daniel Veillardd0c9c322003-10-10 00:49:42 +00004983 case XML_SCHEMA_FACET_FRACTIONDIGITS:
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00004984 return ("fractionDigits");
4985 default:
4986 break;
4987 }
4988 return ("Internal Error");
4989}
4990
4991/**
4992 * xmlSchemaValidateFacets:
4993 * @ctxt: a schema validation context
4994 * @base: the base type
4995 * @facets: the list of facets to check
4996 * @value: the lexical repr of the value to validate
4997 * @val: the precomputed value
4998 *
4999 * Check a value against all facet conditions
5000 *
5001 * Returns 0 if the element is schemas valid, a positive error code
5002 * number otherwise and -1 in case of internal or API error.
5003 */
5004static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005005xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
5006 xmlSchemaTypePtr base,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005007 xmlSchemaFacetPtr facets, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005008{
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005009 int ret = 0;
5010 int tmp = 0;
5011 xmlSchemaTypeType type;
5012 xmlSchemaFacetPtr facet = facets;
5013
5014 while (facet != NULL) {
5015 type = facet->type;
5016 if (type == XML_SCHEMA_FACET_ENUMERATION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005017 tmp = 1;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005018
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005019 while (facet != NULL) {
5020 tmp =
5021 xmlSchemaValidateFacet(base, facet, value,
5022 ctxt->value);
5023 if (tmp == 0) {
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005024 return 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005025 }
5026 facet = facet->next;
5027 }
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005028 } else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005029 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005030
5031 if (tmp != 0) {
5032 ret = tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005033 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 +00005034 }
5035 if (facet != NULL)
5036 facet = facet->next;
5037 }
5038 return (ret);
5039}
5040
Daniel Veillard4255d502002-04-16 15:50:10 +00005041/************************************************************************
5042 * *
5043 * Simple type validation *
5044 * *
5045 ************************************************************************/
5046
5047/**
5048 * xmlSchemaValidateSimpleValue:
5049 * @ctxt: a schema validation context
5050 * @type: the type declaration
5051 * @value: the value to validate
5052 *
5053 * Validate a value against a simple type
5054 *
5055 * Returns 0 if the value is valid, a positive error code
5056 * number otherwise and -1 in case of internal or API error.
5057 */
5058static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005059xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005060 xmlSchemaTypePtr type, const xmlChar * value)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005061{
Daniel Veillard4255d502002-04-16 15:50:10 +00005062 int ret = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005063
Daniel Veillard4255d502002-04-16 15:50:10 +00005064 /*
5065 * First normalize the value accordingly to Schema Datatype
5066 * 4.3.6 whiteSpace definition of the whiteSpace facet of type
5067 */
5068 /*
5069 * Then check the normalized value against the lexical space of the
5070 * type.
5071 */
5072 if (type->type == XML_SCHEMA_TYPE_BASIC) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005073 if (ctxt->value != NULL) {
5074 xmlSchemaFreeValue(ctxt->value);
5075 ctxt->value = NULL;
5076 }
5077 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
5078 ctxt->cur);
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005079 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005080 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 +00005081 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005082 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005083 xmlSchemaTypePtr base;
5084 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005085
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005086 base = type->baseType;
5087 if (base != NULL) {
5088 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5089 } else if (type->subtypes != NULL) {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005090 TODO
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005091 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005092
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005093 /*
Daniel Veillardf2a12832003-11-24 13:04:35 +00005094 * Do not validate facets or attributes when working on
5095 * building the Schemas
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005096 */
5097 if (ctxt->schema != NULL) {
5098 if (ret == 0) {
5099 facet = type->facets;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005100 ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005101 }
5102 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005103 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005104 xmlSchemaTypePtr base;
Daniel Veillard4255d502002-04-16 15:50:10 +00005105
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005106 base = type->subtypes;
5107 if (base != NULL) {
5108 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5109 } else {
5110 TODO}
Daniel Veillard4255d502002-04-16 15:50:10 +00005111 } else if (type->type == XML_SCHEMA_TYPE_LIST) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005112 xmlSchemaTypePtr base;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005113 const xmlChar *cur, *end;
5114 xmlChar *tmp;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005115 int ret2;
Daniel Veillard4255d502002-04-16 15:50:10 +00005116
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005117 base = type->subtypes;
5118 if (base == NULL) {
5119 xmlSchemaVErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL,
5120 "Internal: List type %s has no base type\n",
5121 type->name, NULL);
5122 return (-1);
5123 }
5124 cur = value;
5125 do {
William M. Brack76e95df2003-10-18 16:20:14 +00005126 while (IS_BLANK_CH(*cur))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005127 cur++;
5128 end = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00005129 while ((*end != 0) && (!(IS_BLANK_CH(*end))))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005130 end++;
5131 if (end == cur)
5132 break;
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005133 tmp = xmlStrndup(cur, end - cur);
5134 ret2 = xmlSchemaValidateSimpleValue(ctxt, base, tmp);
5135 xmlFree(tmp);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005136 if (ret2 != 0)
5137 ret = 1;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005138 cur = end;
5139 } while (*cur != 0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005140 } else {
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005141 TODO
5142 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005143 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005144}
5145
5146/************************************************************************
5147 * *
5148 * DOM Validation code *
5149 * *
5150 ************************************************************************/
5151
5152static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005153 xmlNodePtr node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005154static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005155 xmlNodePtr elem,
5156 xmlSchemaAttributePtr attributes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005157static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005158 xmlNodePtr elem,
5159 xmlSchemaElementPtr elemDecl,
5160 xmlSchemaTypePtr type);
Daniel Veillard4255d502002-04-16 15:50:10 +00005161
5162/**
5163 * xmlSchemaRegisterAttributes:
5164 * @ctxt: a schema validation context
5165 * @attrs: a list of attributes
5166 *
5167 * Register the list of attributes as the set to be validated on that element
5168 *
5169 * Returns -1 in case of error, 0 otherwise
5170 */
5171static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005172xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs)
5173{
Daniel Veillard4255d502002-04-16 15:50:10 +00005174 while (attrs != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005175 if ((attrs->ns != NULL) &&
5176 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) {
5177 attrs = attrs->next;
5178 continue;
5179 }
5180 if (ctxt->attrNr >= ctxt->attrMax) {
5181 xmlSchemaAttrStatePtr tmp;
Daniel Veillard4255d502002-04-16 15:50:10 +00005182
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005183 ctxt->attrMax *= 2;
5184 tmp = (xmlSchemaAttrStatePtr)
5185 xmlRealloc(ctxt->attr, ctxt->attrMax *
5186 sizeof(xmlSchemaAttrState));
5187 if (tmp == NULL) {
5188 xmlSchemaVErrMemory(ctxt, "registering attributes", NULL);
5189 ctxt->attrMax /= 2;
5190 return (-1);
5191 }
5192 ctxt->attr = tmp;
5193 }
5194 ctxt->attr[ctxt->attrNr].attr = attrs;
5195 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN;
5196 ctxt->attrNr++;
5197 attrs = attrs->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005198 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005199 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005200}
5201
5202/**
5203 * xmlSchemaCheckAttributes:
5204 * @ctxt: a schema validation context
5205 * @node: the node carrying it.
5206 *
5207 * Check that the registered set of attributes on the current node
5208 * has been properly validated.
5209 *
5210 * Returns 0 if validity constraints are met, 1 otherwise.
5211 */
5212static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005213xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5214{
Daniel Veillard4255d502002-04-16 15:50:10 +00005215 int ret = 0;
5216 int i;
5217
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005218 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
5219 if (ctxt->attr[i].attr == NULL)
5220 break;
5221 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) {
5222 ret = 1;
5223 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, "Attribute %s on %s is unknown\n", ctxt->attr[i].attr->name, node->name);
5224 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005225 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005226 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005227}
5228
5229/**
5230 * xmlSchemaValidateSimpleContent:
5231 * @ctxt: a schema validation context
5232 * @elem: an element
5233 * @type: the type declaration
5234 *
5235 * Validate the content of an element expected to be a simple type
5236 *
5237 * Returns 0 if the element is schemas valid, a positive error code
5238 * number otherwise and -1 in case of internal or API error.
5239 */
5240static int
5241xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005242 xmlNodePtr node ATTRIBUTE_UNUSED)
5243{
Daniel Veillard4255d502002-04-16 15:50:10 +00005244 xmlNodePtr child;
5245 xmlSchemaTypePtr type, base;
5246 xmlChar *value;
Daniel Veillardd3b9cd82003-04-09 11:24:17 +00005247 int ret = 0;
Daniel Veillard4255d502002-04-16 15:50:10 +00005248
5249 child = ctxt->node;
5250 type = ctxt->type;
5251
5252 /*
5253 * Validation Rule: Element Locally Valid (Type): 3.1.3
5254 */
5255 value = xmlNodeGetContent(child);
5256 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */
5257 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005258 case XML_SCHEMA_TYPE_RESTRICTION:{
5259 xmlSchemaFacetPtr facet;
Daniel Veillard4255d502002-04-16 15:50:10 +00005260
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005261 base = type->baseType;
5262 if (base != NULL) {
5263 ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
5264 } else {
5265 TODO}
5266 if (ret == 0) {
5267 facet = type->facets;
5268 ret =
5269 xmlSchemaValidateFacets(ctxt, base, facet, value);
5270 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005271 if ((ret == 0) && (type->attributes != NULL)) {
5272 ret = xmlSchemaValidateAttributes(ctxt, node,
5273 type->attributes);
5274 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005275 break;
5276 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005277 case XML_SCHEMA_TYPE_EXTENSION:{
5278 TODO
5279 break;
5280 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005281 default:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005282 TODO
5283 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005284 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005285 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005286
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005287 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005288}
5289
5290/**
5291 * xmlSchemaValidateCheckNodeList
5292 * @nodelist: the list of nodes
5293 *
5294 * Check the node list is only made of text nodes and entities pointing
5295 * to text nodes
5296 *
5297 * Returns 1 if true, 0 if false and -1 in case of error
5298 */
5299static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005300xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist)
5301{
Daniel Veillard4255d502002-04-16 15:50:10 +00005302 while (nodelist != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005303 if (nodelist->type == XML_ENTITY_REF_NODE) {
5304 TODO /* implement recursion in the entity content */
5305 }
5306 if ((nodelist->type != XML_TEXT_NODE) &&
5307 (nodelist->type != XML_COMMENT_NODE) &&
5308 (nodelist->type != XML_PI_NODE) &&
5309 (nodelist->type != XML_PI_NODE)) {
5310 return (0);
5311 }
5312 nodelist = nodelist->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005313 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005314 return (1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005315}
5316
5317/**
5318 * xmlSchemaSkipIgnored:
5319 * @ctxt: a schema validation context
5320 * @type: the current type context
5321 * @node: the top node.
5322 *
5323 * Skip ignorable nodes in that context
5324 *
5325 * Returns the new sibling
5326 * number otherwise and -1 in case of internal or API error.
5327 */
5328static xmlNodePtr
Daniel Veillarddda8f1b2002-09-26 09:47:36 +00005329xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005330 xmlSchemaTypePtr type, xmlNodePtr node)
5331{
Daniel Veillard4255d502002-04-16 15:50:10 +00005332 int mixed = 0;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005333
Daniel Veillard4255d502002-04-16 15:50:10 +00005334 /*
5335 * TODO complete and handle entities
5336 */
5337 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) ||
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005338 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS));
Daniel Veillard4255d502002-04-16 15:50:10 +00005339 while ((node != NULL) &&
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005340 ((node->type == XML_COMMENT_NODE) ||
5341 ((mixed == 1) && (node->type == XML_TEXT_NODE)) ||
5342 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) &&
5343 (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) {
5344 node = node->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005345 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005346 return (node);
Daniel Veillard4255d502002-04-16 15:50:10 +00005347}
5348
5349/**
5350 * xmlSchemaValidateCallback:
5351 * @ctxt: a schema validation context
5352 * @name: the name of the element detected (might be NULL)
5353 * @type: the type
5354 *
5355 * A transition has been made in the automata associated to an element
5356 * content model
5357 */
5358static void
5359xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005360 const xmlChar * name ATTRIBUTE_UNUSED,
5361 xmlSchemaTypePtr type, xmlNodePtr node)
5362{
Daniel Veillard4255d502002-04-16 15:50:10 +00005363 xmlSchemaTypePtr oldtype = ctxt->type;
5364 xmlNodePtr oldnode = ctxt->node;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005365
Daniel Veillard4255d502002-04-16 15:50:10 +00005366#ifdef DEBUG_CONTENT
Daniel Veillard8651f532002-04-17 09:06:27 +00005367 xmlGenericError(xmlGenericErrorContext,
5368 "xmlSchemaValidateCallback: %s, %s, %s\n",
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005369 name, type->name, node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005370#endif
5371 ctxt->type = type;
5372 ctxt->node = node;
5373 xmlSchemaValidateContent(ctxt, node);
5374 ctxt->type = oldtype;
5375 ctxt->node = oldnode;
5376}
5377
5378
5379#if 0
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005380
Daniel Veillard4255d502002-04-16 15:50:10 +00005381/**
5382 * xmlSchemaValidateSimpleRestrictionType:
5383 * @ctxt: a schema validation context
5384 * @node: the top node.
5385 *
5386 * Validate the content of a restriction type.
5387 *
5388 * Returns 0 if the element is schemas valid, a positive error code
5389 * number otherwise and -1 in case of internal or API error.
5390 */
5391static int
5392xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt,
5393 xmlNodePtr node)
5394{
5395 xmlNodePtr child;
5396 xmlSchemaTypePtr type;
5397 int ret;
5398
5399 child = ctxt->node;
5400 type = ctxt->type;
5401
5402 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005403 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005404 return (-1);
5405 }
5406 /*
5407 * Only text and text based entities references shall be found there
5408 */
5409 ret = xmlSchemaValidateCheckNodeList(child);
5410 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005411 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005412 return (-1);
5413 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005414 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 +00005415 return (-1);
5416 }
5417 ctxt->type = type->subtypes;
5418 xmlSchemaValidateContent(ctxt, node);
5419 ctxt->type = type;
5420 return (ret);
5421}
5422#endif
5423
5424/**
5425 * xmlSchemaValidateSimpleType:
5426 * @ctxt: a schema validation context
5427 * @node: the top node.
5428 *
5429 * Validate the content of an simple type.
5430 *
5431 * Returns 0 if the element is schemas valid, a positive error code
5432 * number otherwise and -1 in case of internal or API error.
5433 */
5434static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005435xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5436{
Daniel Veillard4255d502002-04-16 15:50:10 +00005437 xmlNodePtr child;
5438 xmlSchemaTypePtr type;
5439 xmlAttrPtr attr;
5440 int ret;
5441
5442 child = ctxt->node;
5443 type = ctxt->type;
5444
5445 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005446 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s\n", node->name, NULL);
5447 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005448 }
5449 /*
5450 * Only text and text based entities references shall be found there
5451 */
5452 ret = xmlSchemaValidateCheckNodeList(child);
5453 if (ret < 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005454 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateSimpleType %s content\n", node->name, NULL);
5455 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005456 } else if (ret == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005457 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, "Element %s content is not a simple type\n", node->name, NULL);
5458 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005459 }
5460 /*
5461 * Validation Rule: Element Locally Valid (Type): 3.1.1
5462 */
5463 attr = node->properties;
5464 while (attr != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005465 if ((attr->ns == NULL) ||
5466 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) ||
5467 ((!xmlStrEqual(attr->name, BAD_CAST "type")) &&
5468 (!xmlStrEqual(attr->name, BAD_CAST "nil")) &&
5469 (!xmlStrEqual(attr->name, BAD_CAST "schemasLocation")) &&
5470 (!xmlStrEqual
5471 (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) {
5472 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDATTR, "Element %s: attribute %s should not be present\n", node->name, attr->name);
5473 return (ctxt->err);
5474 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005475 }
5476
5477 ctxt->type = type->subtypes;
5478 ret = xmlSchemaValidateSimpleContent(ctxt, node);
5479 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005480 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005481}
5482
5483/**
5484 * xmlSchemaValidateElementType:
5485 * @ctxt: a schema validation context
5486 * @node: the top node.
5487 *
5488 * Validate the content of an element type.
5489 * Validation Rule: Element Locally Valid (Complex Type)
5490 *
5491 * Returns 0 if the element is schemas valid, a positive error code
5492 * number otherwise and -1 in case of internal or API error.
5493 */
5494static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005495xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5496{
Daniel Veillard4255d502002-04-16 15:50:10 +00005497 xmlNodePtr child;
5498 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005499 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */
Daniel Veillard4255d502002-04-16 15:50:10 +00005500 xmlSchemaElementPtr decl;
5501 int ret, attrBase;
5502
5503 oldregexp = ctxt->regexp;
5504
5505 child = ctxt->node;
5506 type = ctxt->type;
5507
5508 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005509 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateElementType\n", node->name, NULL);
5510 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005511 }
5512 if (child == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005513 if (type->minOccurs > 0) {
5514 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, "Element %s: missing child %s\n", node->name, type->name);
5515 }
5516 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005517 }
5518
5519 /*
5520 * Verify the element matches
5521 */
5522 if (!xmlStrEqual(child->name, type->name)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005523 xmlSchemaVErr3(ctxt, node, XML_SCHEMAS_ERR_WRONGELEM, "Element %s: missing child %s found %s\n", node->name, type->name, child->name);
5524 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005525 }
5526 /*
5527 * Verify the attributes
5528 */
5529 attrBase = ctxt->attrBase;
5530 ctxt->attrBase = ctxt->attrNr;
5531 xmlSchemaRegisterAttributes(ctxt, child->properties);
5532 xmlSchemaValidateAttributes(ctxt, child, type->attributes);
5533 /*
5534 * Verify the element content recursively
5535 */
5536 decl = (xmlSchemaElementPtr) type;
5537 oldregexp = ctxt->regexp;
5538 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005539 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel,
5540 (xmlRegExecCallbacks)
5541 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00005542#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005543 xmlGenericError(xmlGenericErrorContext, "====> %s\n", node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005544#endif
5545 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005546 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr) type,
5547 type->subtypes);
Daniel Veillard4255d502002-04-16 15:50:10 +00005548
5549 if (decl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005550 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005551#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005552 xmlGenericError(xmlGenericErrorContext,
5553 "====> %s : %d\n", node->name, ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005554#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005555 if (ret == 0) {
5556 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", node->name, NULL);
5557 } else if (ret < 0) {
5558 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failure\n", node->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00005559#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005560 } else {
5561 xmlGenericError(xmlGenericErrorContext,
5562 "Element %s content check succeeded\n",
5563 node->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005564
5565#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005566 }
5567 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00005568 }
5569 /*
5570 * Verify that all attributes were Schemas-validated
5571 */
5572 xmlSchemaCheckAttributes(ctxt, node);
5573 ctxt->attrNr = ctxt->attrBase;
5574 ctxt->attrBase = attrBase;
5575
5576 ctxt->regexp = oldregexp;
5577
5578 ctxt->node = child;
5579 ctxt->type = type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005580 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005581}
5582
5583/**
5584 * xmlSchemaValidateBasicType:
5585 * @ctxt: a schema validation context
5586 * @node: the top node.
5587 *
5588 * Validate the content of an element expected to be a basic type type
5589 *
5590 * Returns 0 if the element is schemas valid, a positive error code
5591 * number otherwise and -1 in case of internal or API error.
5592 */
5593static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005594xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5595{
Daniel Veillard4255d502002-04-16 15:50:10 +00005596 int ret;
5597 xmlNodePtr child, cur;
5598 xmlSchemaTypePtr type;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005599 xmlChar *value; /* lexical representation */
Daniel Veillard4255d502002-04-16 15:50:10 +00005600
5601 child = ctxt->node;
5602 type = ctxt->type;
5603
5604 if ((ctxt == NULL) || (type == NULL)) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005605 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: xmlSchemaValidateBasicType\n", node->name, NULL);
5606 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00005607 }
5608 /*
5609 * First check the content model of the node.
5610 */
5611 cur = child;
5612 while (cur != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005613 switch (cur->type) {
5614 case XML_TEXT_NODE:
5615 case XML_CDATA_SECTION_NODE:
5616 case XML_PI_NODE:
5617 case XML_COMMENT_NODE:
5618 case XML_XINCLUDE_START:
5619 case XML_XINCLUDE_END:
5620 break;
5621 case XML_ENTITY_REF_NODE:
5622 case XML_ENTITY_NODE:
5623 TODO break;
5624 case XML_ELEMENT_NODE:
5625 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: child %s should not be present\n", node->name, cur->name);
5626 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005627 case XML_ATTRIBUTE_NODE:
5628 case XML_DOCUMENT_NODE:
5629 case XML_DOCUMENT_TYPE_NODE:
5630 case XML_DOCUMENT_FRAG_NODE:
5631 case XML_NOTATION_NODE:
5632 case XML_HTML_DOCUMENT_NODE:
5633 case XML_DTD_NODE:
5634 case XML_ELEMENT_DECL:
5635 case XML_ATTRIBUTE_DECL:
5636 case XML_ENTITY_DECL:
5637 case XML_NAMESPACE_DECL:
5638#ifdef LIBXML_DOCB_ENABLED
5639 case XML_DOCB_DOCUMENT_NODE:
5640#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005641 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, "Element %s: node type of node unexpected here\n", node->name, NULL);
5642 return (ctxt->err);
5643 }
5644 cur = cur->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00005645 }
5646 if (child == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005647 value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005648 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005649 value = xmlNodeGetContent(child->parent);
Daniel Veillard4255d502002-04-16 15:50:10 +00005650
5651 if (ctxt->value != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005652 xmlSchemaFreeValue(ctxt->value);
5653 ctxt->value = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005654 }
5655 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value));
5656 if (value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005657 xmlFree(value);
Daniel Veillard4255d502002-04-16 15:50:10 +00005658 if (ret != 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005659 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 +00005660 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005661 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00005662}
5663
5664/**
5665 * xmlSchemaValidateComplexType:
5666 * @ctxt: a schema validation context
5667 * @node: the top node.
5668 *
5669 * Validate the content of an element expected to be a complex type type
5670 * xmlschema-1.html#cvc-complex-type
5671 * Validation Rule: Element Locally Valid (Complex Type)
5672 *
5673 * Returns 0 if the element is schemas valid, a positive error code
5674 * number otherwise and -1 in case of internal or API error.
5675 */
5676static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005677xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5678{
Daniel Veillard4255d502002-04-16 15:50:10 +00005679 xmlNodePtr child;
Daniel Veillard8651f532002-04-17 09:06:27 +00005680 xmlSchemaTypePtr type, subtype;
Daniel Veillard4255d502002-04-16 15:50:10 +00005681 int ret;
5682
5683 child = ctxt->node;
5684 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005685 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005686
Daniel Veillard4255d502002-04-16 15:50:10 +00005687 switch (type->contentType) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005688 case XML_SCHEMA_CONTENT_EMPTY:
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005689 if (type->baseType != NULL) {
5690 } else if (child != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005691 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is supposed to be empty\n", node->name, NULL);
5692 }
5693 if (type->attributes != NULL) {
5694 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5695 }
5696 subtype = type->subtypes;
5697 while (subtype != NULL) {
5698 ctxt->type = subtype;
5699 xmlSchemaValidateComplexType(ctxt, node);
5700 subtype = subtype->next;
5701 }
5702 break;
5703 case XML_SCHEMA_CONTENT_ELEMENTS:
5704 case XML_SCHEMA_CONTENT_MIXED:
5705 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
5706 /*
5707 * Skip ignorable nodes in that context
5708 */
5709 child = xmlSchemaSkipIgnored(ctxt, type, child);
5710 while (child != NULL) {
5711 if (child->type == XML_ELEMENT_NODE) {
5712 ret = xmlRegExecPushString(ctxt->regexp,
5713 child->name, child);
Daniel Veillard4255d502002-04-16 15:50:10 +00005714#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005715 if (ret < 0)
5716 xmlGenericError(xmlGenericErrorContext,
5717 " --> %s Error\n", child->name);
5718 else
5719 xmlGenericError(xmlGenericErrorContext,
5720 " --> %s\n", child->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00005721#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005722 }
5723 child = child->next;
5724 /*
5725 * Skip ignorable nodes in that context
5726 */
5727 child = xmlSchemaSkipIgnored(ctxt, type, child);
5728 }
Daniel Veillardf2a12832003-11-24 13:04:35 +00005729 if (type->attributes != NULL) {
5730 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5731 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005732 break;
5733 case XML_SCHEMA_CONTENT_BASIC:{
5734 if (type->subtypes != NULL) {
5735 ctxt->type = type->subtypes;
5736 xmlSchemaValidateComplexType(ctxt, node);
5737 }
5738 if (type->baseType != NULL) {
5739 ctxt->type = type->baseType;
5740 xmlSchemaValidateBasicType(ctxt, node);
5741 }
5742 if (type->attributes != NULL) {
5743 xmlSchemaValidateAttributes(ctxt, node,
5744 type->attributes);
5745 }
5746 ctxt->type = type;
5747 break;
5748 }
Daniel Veillardbe9c6322003-11-22 20:37:51 +00005749 case XML_SCHEMA_CONTENT_SIMPLE:{
5750 if (type->subtypes != NULL) {
5751 ctxt->type = type->subtypes;
5752 xmlSchemaValidateComplexType(ctxt, node);
5753 }
5754 if (type->baseType != NULL) {
5755 ctxt->type = type->baseType;
5756 xmlSchemaValidateComplexType(ctxt, node);
5757 }
5758 if (type->attributes != NULL) {
5759 xmlSchemaValidateAttributes(ctxt, node,
5760 type->attributes);
5761 }
5762 ctxt->type = type;
5763 break;
5764 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005765 default:
5766 TODO xmlGenericError(xmlGenericErrorContext,
5767 "unimplemented content type %d\n",
5768 type->contentType);
Daniel Veillard4255d502002-04-16 15:50:10 +00005769 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005770 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005771}
5772
5773/**
5774 * xmlSchemaValidateContent:
5775 * @ctxt: a schema validation context
5776 * @elem: an element
5777 * @type: the type declaration
5778 *
5779 * Validate the content of an element against the type.
5780 *
5781 * Returns 0 if the element is schemas valid, a positive error code
5782 * number otherwise and -1 in case of internal or API error.
5783 */
5784static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005785xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node)
5786{
Daniel Veillard4255d502002-04-16 15:50:10 +00005787 xmlNodePtr child;
5788 xmlSchemaTypePtr type;
5789
5790 child = ctxt->node;
5791 type = ctxt->type;
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005792 ctxt->cur = node;
Daniel Veillard4255d502002-04-16 15:50:10 +00005793
Daniel Veillarde19fc232002-04-22 16:01:24 +00005794 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
Daniel Veillard82bbbd42003-05-11 20:16:09 +00005795 ctxt->cur = node;
Daniel Veillarde19fc232002-04-22 16:01:24 +00005796
Daniel Veillard4255d502002-04-16 15:50:10 +00005797 switch (type->type) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005798 case XML_SCHEMA_TYPE_ANY:
5799 /* Any type will do it, fine */
5800 TODO /* handle recursivity */
5801 break;
5802 case XML_SCHEMA_TYPE_COMPLEX:
5803 xmlSchemaValidateComplexType(ctxt, node);
5804 break;
5805 case XML_SCHEMA_TYPE_ELEMENT:{
5806 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type;
5807
5808 /*
5809 * Handle element reference here
5810 */
5811 if (decl->ref != NULL) {
5812 if (decl->refDecl == NULL) {
5813 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, "Internal error: element reference %s not resolved\n", decl->ref, NULL);
5814 return (-1);
5815 }
5816 ctxt->type = (xmlSchemaTypePtr) decl->refDecl;
5817 decl = decl->refDecl;
5818 }
5819 xmlSchemaValidateElementType(ctxt, node);
5820 ctxt->type = type;
5821 break;
5822 }
5823 case XML_SCHEMA_TYPE_BASIC:
5824 xmlSchemaValidateBasicType(ctxt, node);
5825 break;
5826 case XML_SCHEMA_TYPE_FACET:
5827 TODO break;
5828 case XML_SCHEMA_TYPE_SIMPLE:
5829 xmlSchemaValidateSimpleType(ctxt, node);
5830 break;
5831 case XML_SCHEMA_TYPE_SEQUENCE:
5832 TODO break;
5833 case XML_SCHEMA_TYPE_CHOICE:
5834 TODO break;
5835 case XML_SCHEMA_TYPE_ALL:
5836 TODO break;
5837 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:
5838 TODO break;
5839 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:
5840 TODO break;
5841 case XML_SCHEMA_TYPE_UR:
5842 TODO break;
5843 case XML_SCHEMA_TYPE_RESTRICTION:
5844 /*xmlSchemaValidateRestrictionType(ctxt, node); */
5845 TODO break;
5846 case XML_SCHEMA_TYPE_EXTENSION:
5847 TODO break;
5848 case XML_SCHEMA_TYPE_ATTRIBUTE:
5849 TODO break;
5850 case XML_SCHEMA_TYPE_GROUP:
5851 TODO break;
5852 case XML_SCHEMA_TYPE_NOTATION:
5853 TODO break;
5854 case XML_SCHEMA_TYPE_LIST:
5855 TODO break;
5856 case XML_SCHEMA_TYPE_UNION:
5857 TODO break;
5858 case XML_SCHEMA_FACET_MININCLUSIVE:
5859 TODO break;
5860 case XML_SCHEMA_FACET_MINEXCLUSIVE:
5861 TODO break;
5862 case XML_SCHEMA_FACET_MAXINCLUSIVE:
5863 TODO break;
5864 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
5865 TODO break;
5866 case XML_SCHEMA_FACET_TOTALDIGITS:
5867 TODO break;
5868 case XML_SCHEMA_FACET_FRACTIONDIGITS:
5869 TODO break;
5870 case XML_SCHEMA_FACET_PATTERN:
5871 TODO break;
5872 case XML_SCHEMA_FACET_ENUMERATION:
5873 TODO break;
5874 case XML_SCHEMA_FACET_WHITESPACE:
5875 TODO break;
5876 case XML_SCHEMA_FACET_LENGTH:
5877 TODO break;
5878 case XML_SCHEMA_FACET_MAXLENGTH:
5879 TODO break;
5880 case XML_SCHEMA_FACET_MINLENGTH:
5881 TODO break;
5882 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
5883 TODO break;
Daniel Veillard4255d502002-04-16 15:50:10 +00005884 }
5885 xmlSchemaValidateAttributes(ctxt, node, type->attributes);
5886
5887 if (ctxt->node == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005888 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005889 ctxt->node = ctxt->node->next;
5890 ctxt->type = type->next;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005891 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005892}
5893
5894/**
5895 * xmlSchemaValidateType:
5896 * @ctxt: a schema validation context
5897 * @elem: an element
5898 * @type: the list of type declarations
5899 *
5900 * Validate the content of an element against the types.
5901 *
5902 * Returns 0 if the element is schemas valid, a positive error code
5903 * number otherwise and -1 in case of internal or API error.
5904 */
5905static int
5906xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005907 xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type)
5908{
Daniel Veillard4255d502002-04-16 15:50:10 +00005909 xmlChar *nil;
5910
Daniel Veillard2db8c122003-07-08 12:16:59 +00005911 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005912 return (0);
Daniel Veillard2db8c122003-07-08 12:16:59 +00005913
Daniel Veillard4255d502002-04-16 15:50:10 +00005914 /*
5915 * 3.3.4 : 2
5916 */
5917 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005918 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, "Element %s is abstract\n", elem->name, NULL);
5919 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005920 }
5921 /*
5922 * 3.3.4: 3
5923 */
5924 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs);
5925 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005926 /* 3.3.4: 3.2 */
5927 if (xmlStrEqual(nil, BAD_CAST "true")) {
5928 if (elem->children != NULL) {
5929 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTEMPTY, "Element %s is not empty\n", elem->name, NULL);
5930 return (ctxt->err);
5931 }
5932 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
5933 (elemDecl->value != NULL)) {
5934 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_HAVEDEFAULT, "Empty element %s cannot get a fixed value\n", elem->name, NULL);
5935 return (ctxt->err);
5936 }
5937 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005938 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005939 /* 3.3.4: 3.1 */
5940 if (nil != NULL) {
5941 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTNILLABLE, "Element %s with xs:nil but not nillable\n", elem->name, NULL);
5942 xmlFree(nil);
5943 return (ctxt->err);
5944 }
Daniel Veillard4255d502002-04-16 15:50:10 +00005945 }
5946
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005947 /* TODO 3.3.4: 4 if the element carries xs:type */
Daniel Veillard4255d502002-04-16 15:50:10 +00005948
5949 ctxt->type = elemDecl->subtypes;
5950 ctxt->node = elem->children;
5951 xmlSchemaValidateContent(ctxt, elem);
5952 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005953
5954 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00005955}
5956
5957
5958/**
5959 * xmlSchemaValidateAttributes:
5960 * @ctxt: a schema validation context
5961 * @elem: an element
5962 * @attributes: the list of attribute declarations
5963 *
5964 * Validate the attributes of an element.
5965 *
5966 * Returns 0 if the element is schemas valid, a positive error code
5967 * number otherwise and -1 in case of internal or API error.
5968 */
5969static int
5970xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005971 xmlSchemaAttributePtr attributes)
5972{
Daniel Veillard4255d502002-04-16 15:50:10 +00005973 int i, ret;
5974 xmlAttrPtr attr;
5975 xmlChar *value;
Daniel Veillard13e04c62002-04-23 17:51:29 +00005976 xmlSchemaAttributeGroupPtr group = NULL;
Daniel Veillard4255d502002-04-16 15:50:10 +00005977
5978 if (attributes == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005979 return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00005980 while (attributes != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00005981 /*
5982 * Handle attribute groups
5983 */
5984 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
5985 group = (xmlSchemaAttributeGroupPtr) attributes;
5986 xmlSchemaValidateAttributes(ctxt, elem, group->attributes);
5987 attributes = group->next;
5988 continue;
5989 }
5990 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) {
5991 attr = ctxt->attr[i].attr;
5992 if (attr == NULL)
5993 continue;
5994 if (attributes->ref != NULL) {
5995 if (!xmlStrEqual(attr->name, attributes->ref))
5996 continue;
5997 if (attr->ns != NULL) {
5998 if ((attributes->refNs == NULL) ||
5999 (!xmlStrEqual(attr->ns->href, attributes->refNs)))
6000 continue;
6001 } else if (attributes->refNs != NULL) {
6002 continue;
6003 }
6004 } else {
6005 if (!xmlStrEqual(attr->name, attributes->name))
6006 continue;
6007 /*
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006008 * handle the namespaces checks here
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006009 */
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006010 if (attr->ns == NULL) {
6011 /*
6012 * accept an unqualified attribute only if the declaration
6013 * is unqualified or if the schemas allowed it.
6014 */
6015 if ((attributes->targetNamespace != NULL) &&
6016 ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0))
6017 continue;
6018 } else {
6019 if (attributes->targetNamespace == NULL)
6020 continue;
6021 if (!xmlStrEqual(attributes->targetNamespace,
6022 attr->ns->href))
6023 continue;
6024 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006025 }
6026 ctxt->cur = (xmlNodePtr) attributes;
6027 if (attributes->subtypes == NULL) {
6028 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL);
6029 continue;
6030 }
6031 value = xmlNodeListGetString(elem->doc, attr->children, 1);
6032 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
6033 value);
6034 if (ret != 0) {
6035 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_ATTRINVALID, "attribute %s on %s does not match type\n", attr->name, elem->name);
6036 } else {
6037 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
6038 }
6039 if (value != NULL) {
6040 xmlFree(value);
6041 }
6042 }
6043 attributes = attributes->next;
Daniel Veillard4255d502002-04-16 15:50:10 +00006044 }
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006045 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006046}
6047
6048/**
6049 * xmlSchemaValidateElement:
6050 * @ctxt: a schema validation context
6051 * @elem: an element
6052 *
6053 * Validate an element in a tree
6054 *
6055 * Returns 0 if the element is schemas valid, a positive error code
6056 * number otherwise and -1 in case of internal or API error.
6057 */
6058static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006059xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem)
6060{
Daniel Veillard4255d502002-04-16 15:50:10 +00006061 xmlSchemaElementPtr elemDecl;
6062 int ret, attrBase;
6063
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006064 if (elem->ns != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006065 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6066 elem->name, elem->ns->href, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006067 } else {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006068 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6069 elem->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006070 }
6071 /*
6072 * special case whe elementFormDefault is unqualified for top-level elem.
6073 */
6074 if ((elemDecl == NULL) && (elem->ns != NULL) &&
6075 (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) &&
6076 (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) &&
6077 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6078 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6079 elem->name, NULL, NULL);
6080 }
6081
Daniel Veillard4255d502002-04-16 15:50:10 +00006082 /*
6083 * 3.3.4 : 1
6084 */
6085 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006086 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", elem->name, NULL);
6087 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006088 }
6089 if (elemDecl->subtypes == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006090 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTYPE, "Element %s has no type\n", elem->name, NULL);
6091 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006092 }
6093 /*
6094 * Verify the attributes
6095 */
6096 attrBase = ctxt->attrBase;
6097 ctxt->attrBase = ctxt->attrNr;
6098 xmlSchemaRegisterAttributes(ctxt, elem->properties);
6099 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes);
6100 /*
6101 * Verify the element content recursively
6102 */
6103 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006104 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel,
6105 (xmlRegExecCallbacks)
6106 xmlSchemaValidateCallback, ctxt);
Daniel Veillard4255d502002-04-16 15:50:10 +00006107#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006108 xmlGenericError(xmlGenericErrorContext, "====> %s\n", elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006109#endif
6110 }
6111 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006112 if (elemDecl->contModel != NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006113 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006114#ifdef DEBUG_AUTOMATA
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006115 xmlGenericError(xmlGenericErrorContext,
6116 "====> %s : %d\n", elem->name, ret);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006117#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006118 if (ret == 0) {
6119 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
6120 } else if (ret < 0) {
6121 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, "Element %s content check failed\n", elem->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006122#ifdef DEBUG_CONTENT
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006123 } else {
6124 xmlGenericError(xmlGenericErrorContext,
6125 "Element %s content check succeeded\n",
6126 elem->name);
Daniel Veillard4255d502002-04-16 15:50:10 +00006127
6128#endif
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006129 }
6130 xmlRegFreeExecCtxt(ctxt->regexp);
Daniel Veillard4255d502002-04-16 15:50:10 +00006131 }
6132 /*
6133 * Verify that all attributes were Schemas-validated
6134 */
6135 xmlSchemaCheckAttributes(ctxt, elem);
6136 ctxt->attrNr = ctxt->attrBase;
6137 ctxt->attrBase = attrBase;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006138
6139 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006140}
6141
6142/**
6143 * xmlSchemaValidateDocument:
6144 * @ctxt: a schema validation context
6145 * @doc: a parsed document tree
6146 *
6147 * Validate a document tree in memory.
6148 *
6149 * Returns 0 if the document is schemas valid, a positive error code
6150 * number otherwise and -1 in case of internal or API error.
6151 */
6152static int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006153xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6154{
Daniel Veillard4255d502002-04-16 15:50:10 +00006155 xmlNodePtr root;
6156 xmlSchemaElementPtr elemDecl;
6157
6158 root = xmlDocGetRootElement(doc);
6159 if (root == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006160 xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, "document has no root\n", NULL, NULL);
6161 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006162 }
6163 if (root->ns != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006164 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6165 root->name, root->ns->href, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006166 else
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006167 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6168 root->name, NULL, NULL);
Daniel Veillardbe9c6322003-11-22 20:37:51 +00006169 /*
6170 * special case whe elementFormDefault is unqualified for top-level elem.
6171 */
6172 if ((elemDecl == NULL) && (root->ns != NULL) &&
6173 (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) &&
6174 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) {
6175 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl,
6176 root->name, NULL, NULL);
6177 }
6178
Daniel Veillard4255d502002-04-16 15:50:10 +00006179 if (elemDecl == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006180 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", root->name, NULL);
Daniel Veillarddecd64d2002-04-18 14:41:51 +00006181 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006182 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, "Root element %s not toplevel\n", root->name, NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006183 }
6184 /*
6185 * Okay, start the recursive validation
6186 */
6187 xmlSchemaValidateElement(ctxt, root);
6188
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006189 return (ctxt->err);
Daniel Veillard4255d502002-04-16 15:50:10 +00006190}
6191
6192/************************************************************************
6193 * *
6194 * SAX Validation code *
6195 * *
6196 ************************************************************************/
6197
6198/************************************************************************
6199 * *
6200 * Validation interfaces *
6201 * *
6202 ************************************************************************/
6203
6204/**
6205 * xmlSchemaNewValidCtxt:
6206 * @schema: a precompiled XML Schemas
6207 *
6208 * Create an XML Schemas validation context based on the given schema
6209 *
6210 * Returns the validation context or NULL in case of error
6211 */
6212xmlSchemaValidCtxtPtr
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006213xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
6214{
Daniel Veillard4255d502002-04-16 15:50:10 +00006215 xmlSchemaValidCtxtPtr ret;
6216
6217 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
6218 if (ret == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006219 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006220 return (NULL);
6221 }
6222 memset(ret, 0, sizeof(xmlSchemaValidCtxt));
6223 ret->schema = schema;
6224 ret->attrNr = 0;
6225 ret->attrMax = 10;
6226 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax *
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006227 sizeof
6228 (xmlSchemaAttrState));
Daniel Veillard4255d502002-04-16 15:50:10 +00006229 if (ret->attr == NULL) {
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006230 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
6231 free(ret);
6232 return (NULL);
Daniel Veillard4255d502002-04-16 15:50:10 +00006233 }
6234 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState));
6235 return (ret);
6236}
6237
6238/**
6239 * xmlSchemaFreeValidCtxt:
6240 * @ctxt: the schema validation context
6241 *
6242 * Free the resources associated to the schema validation context
6243 */
6244void
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006245xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
6246{
Daniel Veillard4255d502002-04-16 15:50:10 +00006247 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006248 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006249 if (ctxt->attr != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006250 xmlFree(ctxt->attr);
Daniel Veillard88c58912002-04-23 07:12:20 +00006251 if (ctxt->value != NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006252 xmlSchemaFreeValue(ctxt->value);
Daniel Veillard4255d502002-04-16 15:50:10 +00006253 xmlFree(ctxt);
6254}
6255
6256/**
6257 * xmlSchemaSetValidErrors:
6258 * @ctxt: a schema validation context
6259 * @err: the error function
6260 * @warn: the warning function
Daniel Veillarda9b66d02002-12-11 14:23:49 +00006261 * @ctx: the functions context
Daniel Veillard4255d502002-04-16 15:50:10 +00006262 *
6263 * Set the error and warning callback informations
6264 */
6265void
6266xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006267 xmlSchemaValidityErrorFunc err,
6268 xmlSchemaValidityWarningFunc warn, void *ctx)
6269{
Daniel Veillard4255d502002-04-16 15:50:10 +00006270 if (ctxt == NULL)
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006271 return;
Daniel Veillard4255d502002-04-16 15:50:10 +00006272 ctxt->error = err;
6273 ctxt->warning = warn;
6274 ctxt->userData = ctx;
6275}
6276
6277/**
6278 * xmlSchemaValidateDoc:
6279 * @ctxt: a schema validation context
6280 * @doc: a parsed document tree
6281 *
6282 * Validate a document tree in memory.
6283 *
6284 * Returns 0 if the document is schemas valid, a positive error code
6285 * number otherwise and -1 in case of internal or API error.
6286 */
6287int
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006288xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
6289{
Daniel Veillard4255d502002-04-16 15:50:10 +00006290 int ret;
6291
6292 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006293 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006294
6295 ctxt->doc = doc;
6296 ret = xmlSchemaValidateDocument(ctxt, doc);
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006297 return (ret);
Daniel Veillard4255d502002-04-16 15:50:10 +00006298}
6299
6300/**
6301 * xmlSchemaValidateStream:
6302 * @ctxt: a schema validation context
6303 * @input: the input to use for reading the data
6304 * @enc: an optional encoding information
6305 * @sax: a SAX handler for the resulting events
6306 * @user_data: the context to provide to the SAX handler.
6307 *
6308 * Validate a document tree in memory.
6309 *
6310 * Returns 0 if the document is schemas valid, a positive error code
6311 * number otherwise and -1 in case of internal or API error.
6312 */
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006313int
Daniel Veillard4255d502002-04-16 15:50:10 +00006314xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006315 xmlParserInputBufferPtr input, xmlCharEncoding enc,
6316 xmlSAXHandlerPtr sax, void *user_data)
6317{
Daniel Veillard4255d502002-04-16 15:50:10 +00006318 if ((ctxt == NULL) || (input == NULL))
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006319 return (-1);
Daniel Veillard4255d502002-04-16 15:50:10 +00006320 ctxt->input = input;
6321 ctxt->enc = enc;
6322 ctxt->sax = sax;
6323 ctxt->user_data = user_data;
Daniel Veillardd0c9c322003-10-10 00:49:42 +00006324 TODO return (0);
Daniel Veillard4255d502002-04-16 15:50:10 +00006325}
6326
6327#endif /* LIBXML_SCHEMAS_ENABLED */