|
1 /* |
|
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 /* |
|
11 * TODO: |
|
12 * - when types are redefined in includes, check that all |
|
13 * types in the redef list are equal |
|
14 * -> need a type equality operation. |
|
15 */ |
|
16 #define IN_LIBXML |
|
17 #include "XmlEnglibxml.h" |
|
18 |
|
19 #if defined(LIBXML_SCHEMAS_ENABLED) || defined(XMLENGINE_XMLSCHEMA_DATATYPES) |
|
20 |
|
21 |
|
22 #include <string.h> |
|
23 #include "Libxml2_xmlmemory.h" |
|
24 #include "Libxml2_parser.h" |
|
25 #include "Libxml2_parserInternals.h" |
|
26 #include "Libxml2_hash.h" |
|
27 #include "Libxml2_uri.h" |
|
28 |
|
29 #include "Libxml2_xmlschemas.h" |
|
30 #include "Libxml2_schemasInternals.h" |
|
31 #include "Libxml2_xmlschemastypes.h" |
|
32 |
|
33 #ifdef LIBXML_AUTOMATA_ENABLED |
|
34 #include <xmlautomata.h> |
|
35 #endif |
|
36 |
|
37 #ifdef LIBXML_REGEXP_ENABLED |
|
38 #include <xmlregexp.h> |
|
39 #endif |
|
40 |
|
41 #include "Libxml2_dict.h" |
|
42 |
|
43 /* #define DEBUG 1 */ |
|
44 |
|
45 /* #define DEBUG_CONTENT 1 */ |
|
46 |
|
47 /* #define DEBUG_TYPE 1 */ |
|
48 |
|
49 /* #define DEBUG_CONTENT_REGEXP 1 */ |
|
50 |
|
51 /* #define DEBUG_AUTOMATA 1 */ |
|
52 |
|
53 #define UNBOUNDED (1 << 30) |
|
54 #define TODO \ |
|
55 xmlGenericError(xmlGenericErrorContext, \ |
|
56 "Unimplemented block at %s:%d\n", \ |
|
57 __FILE__, __LINE__); |
|
58 |
|
59 #define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar*)"the default namespace" |
|
60 |
|
61 /* |
|
62 * The XML Schemas namespaces |
|
63 */ //TODO: define exported functions that return these Or export these |
|
64 static const xmlChar* const xmlSchemaNs = (const xmlChar*) |
|
65 "http://www.w3.org/2001/XMLSchema"; |
|
66 |
|
67 static const xmlChar* const xmlSchemaInstanceNs = (const xmlChar*) |
|
68 "http://www.w3.org/2001/XMLSchema-instance"; |
|
69 |
|
70 /** |
|
71 * xmlSchemaFreeAnnot: |
|
72 * @annot: a schema type structure |
|
73 * |
|
74 * Deallocate a annotation structure |
|
75 */ |
|
76 static void |
|
77 xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot) |
|
78 { |
|
79 if (annot == NULL) |
|
80 return; |
|
81 xmlFree(annot); |
|
82 } |
|
83 |
|
84 /** |
|
85 * xmlSchemaFreeType: |
|
86 * @type: a schema type structure |
|
87 * |
|
88 * Deallocate a Schema Type structure. |
|
89 */ |
|
90 void |
|
91 xmlSchemaFreeType(xmlSchemaTypePtr type) |
|
92 { |
|
93 if (type == NULL) |
|
94 return; |
|
95 if (type->annot != NULL) |
|
96 xmlSchemaFreeAnnot(type->annot); |
|
97 if (type->facets != NULL) { |
|
98 xmlSchemaFacetPtr facet, next; |
|
99 |
|
100 facet = type->facets; |
|
101 while (facet != NULL) { |
|
102 next = facet->next; |
|
103 xmlSchemaFreeFacet(facet); |
|
104 facet = next; |
|
105 } |
|
106 } |
|
107 xmlFree(type); |
|
108 } |
|
109 |
|
110 |
|
111 /** |
|
112 * xmlSchemaFreeFacet: |
|
113 * @facet: a schema facet structure |
|
114 * |
|
115 * Deallocate a Schema Facet structure. |
|
116 */ |
|
117 void |
|
118 xmlSchemaFreeFacet(xmlSchemaFacetPtr facet) |
|
119 { |
|
120 if (facet == NULL) |
|
121 return; |
|
122 if (facet->val != NULL) |
|
123 xmlSchemaFreeValue(facet->val); |
|
124 #ifdef LIBXML_REGEXP_ENABLED |
|
125 if (facet->regexp != NULL) |
|
126 xmlRegFreeRegexp(facet->regexp); |
|
127 #endif |
|
128 if (facet->annot != NULL) |
|
129 xmlSchemaFreeAnnot(facet->annot); |
|
130 xmlFree(facet); |
|
131 } |
|
132 |
|
133 #endif /* defined(LIBXML_SCHEMAS_ENABLED) || defined(XMLENGINE_XMLSCHEMA_DATATYPES) */ |
|
134 |
|
135 #ifdef LIBXML_SCHEMAS_ENABLED |
|
136 |
|
137 #define IS_SCHEMA(node, type) \ |
|
138 ((node != NULL) && (node->ns != NULL) && \ |
|
139 (xmlStrEqual(node->name, (const xmlChar *) type)) && \ |
|
140 (xmlStrEqual(node->ns->href, xmlSchemaNs))) |
|
141 |
|
142 #define XML_SCHEMAS_PARSE_ERROR 1 |
|
143 |
|
144 #define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT |
|
145 |
|
146 struct _xmlSchemaParserCtxt { |
|
147 void *userData; /* user specific data block */ |
|
148 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */ |
|
149 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */ |
|
150 xmlSchemaValidError err; |
|
151 int nberrors; |
|
152 xmlStructuredErrorFunc serror; |
|
153 |
|
154 xmlSchemaPtr topschema; /* The main schema */ |
|
155 xmlHashTablePtr namespaces; /* Hash table of namespaces to schemas */ |
|
156 |
|
157 xmlSchemaPtr schema; /* The schema in use */ |
|
158 const xmlChar *container; /* the current element, group, ... */ |
|
159 int counter; |
|
160 |
|
161 const xmlChar *URL; |
|
162 xmlDocPtr doc; |
|
163 int preserve; /* Whether the doc should be freed */ |
|
164 |
|
165 const char *buffer; |
|
166 int size; |
|
167 |
|
168 /* |
|
169 * Used to build complex element content models |
|
170 */ |
|
171 xmlAutomataPtr am; |
|
172 xmlAutomataStatePtr start; |
|
173 xmlAutomataStatePtr end; |
|
174 xmlAutomataStatePtr state; |
|
175 |
|
176 xmlDictPtr dict; /* dictionnary for interned string names */ |
|
177 int includes; /* the inclusion level, 0 for root or imports */ |
|
178 }; |
|
179 |
|
180 |
|
181 #define XML_SCHEMAS_ATTR_UNKNOWN 1 |
|
182 #define XML_SCHEMAS_ATTR_CHECKED 2 |
|
183 |
|
184 typedef struct _xmlSchemaAttrState xmlSchemaAttrState; |
|
185 typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr; |
|
186 struct _xmlSchemaAttrState { |
|
187 xmlAttrPtr attr; |
|
188 int state; |
|
189 }; |
|
190 |
|
191 /** |
|
192 * xmlSchemaValidCtxt: |
|
193 * |
|
194 * A Schemas validation context |
|
195 */ |
|
196 |
|
197 struct _xmlSchemaValidCtxt { |
|
198 void *userData; /* user specific data block */ |
|
199 xmlSchemaValidityErrorFunc error; /* the callback in case of errors */ |
|
200 xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */ |
|
201 xmlStructuredErrorFunc serror; |
|
202 |
|
203 xmlSchemaPtr schema; /* The schema in use */ |
|
204 xmlDocPtr doc; |
|
205 xmlParserInputBufferPtr input; |
|
206 xmlCharEncoding enc; |
|
207 xmlSAXHandlerPtr sax; |
|
208 void *user_data; |
|
209 |
|
210 xmlDocPtr myDoc; |
|
211 int err; |
|
212 int nberrors; |
|
213 |
|
214 xmlNodePtr node; |
|
215 xmlNodePtr cur; |
|
216 xmlSchemaTypePtr type; |
|
217 |
|
218 xmlRegExecCtxtPtr regexp; |
|
219 xmlSchemaValPtr value; |
|
220 |
|
221 int attrNr; |
|
222 int attrBase; |
|
223 int attrMax; |
|
224 xmlSchemaAttrStatePtr attr; |
|
225 }; |
|
226 |
|
227 /* |
|
228 * These are the entries in the schemas importSchemas hash table |
|
229 */ |
|
230 typedef struct _xmlSchemaImport xmlSchemaImport; |
|
231 typedef xmlSchemaImport *xmlSchemaImportPtr; |
|
232 struct _xmlSchemaImport { |
|
233 const xmlChar *schemaLocation; |
|
234 xmlSchemaPtr schema; |
|
235 }; |
|
236 |
|
237 /* |
|
238 * These are the entries associated to includes in a schemas |
|
239 */ |
|
240 typedef struct _xmlSchemaInclude xmlSchemaInclude; |
|
241 typedef xmlSchemaInclude *xmlSchemaIncludePtr; |
|
242 struct _xmlSchemaInclude { |
|
243 xmlSchemaIncludePtr next; |
|
244 |
|
245 const xmlChar *schemaLocation; |
|
246 xmlDocPtr doc; |
|
247 }; |
|
248 |
|
249 |
|
250 |
|
251 /************************************************************************ |
|
252 * * |
|
253 * Some predeclarations * |
|
254 * * |
|
255 ************************************************************************/ |
|
256 static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt, |
|
257 xmlSchemaTypePtr type, |
|
258 const xmlChar * value); |
|
259 |
|
260 static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, |
|
261 xmlSchemaPtr schema, |
|
262 xmlNodePtr node); |
|
263 static int |
|
264 xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, |
|
265 xmlSchemaTypePtr type, |
|
266 const xmlChar * value, |
|
267 int fireErrors); |
|
268 |
|
269 /************************************************************************ |
|
270 * * |
|
271 * Datatype error handlers * |
|
272 * * |
|
273 ************************************************************************/ |
|
274 |
|
275 /** |
|
276 * xmlSchemaPErrMemory: |
|
277 * @node: a context node |
|
278 * @extra: extra informations |
|
279 * |
|
280 * Handle an out of memory condition |
|
281 */ |
|
282 static void |
|
283 xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, |
|
284 const char *extra, xmlNodePtr node) |
|
285 { |
|
286 if (ctxt != NULL) |
|
287 ctxt->nberrors++; |
|
288 __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, |
|
289 extra); |
|
290 } |
|
291 |
|
292 /** |
|
293 * xmlSchemaPErr: |
|
294 * @ctxt: the parsing context |
|
295 * @node: the context node |
|
296 * @error: the error code |
|
297 * @msg: the error message |
|
298 * @str1: extra data |
|
299 * @str2: extra data |
|
300 * |
|
301 * Handle a parser error |
|
302 */ |
|
303 static void |
|
304 xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, |
|
305 const char *msg, const xmlChar * str1, const xmlChar * str2) |
|
306 { |
|
307 xmlGenericErrorFunc channel = NULL; |
|
308 xmlStructuredErrorFunc schannel = NULL; |
|
309 void *data = NULL; |
|
310 |
|
311 if (ctxt != NULL) { |
|
312 ctxt->nberrors++; |
|
313 channel = ctxt->error; |
|
314 data = ctxt->userData; |
|
315 schannel = ctxt->serror; |
|
316 } |
|
317 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, |
|
318 error, XML_ERR_ERROR, NULL, 0, |
|
319 (const char *) str1, (const char *) str2, NULL, 0, 0, |
|
320 msg, str1, str2); |
|
321 } |
|
322 |
|
323 /** |
|
324 * xmlSchemaPErr2: |
|
325 * @ctxt: the parsing context |
|
326 * @node: the context node |
|
327 * @node: the current child |
|
328 * @error: the error code |
|
329 * @msg: the error message |
|
330 * @str1: extra data |
|
331 * @str2: extra data |
|
332 * |
|
333 * Handle a parser error |
|
334 */ |
|
335 static void |
|
336 xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, |
|
337 xmlNodePtr child, int error, |
|
338 const char *msg, const xmlChar * str1, const xmlChar * str2) |
|
339 { |
|
340 if (child != NULL) |
|
341 xmlSchemaPErr(ctxt, child, error, msg, str1, str2); |
|
342 else |
|
343 xmlSchemaPErr(ctxt, node, error, msg, str1, str2); |
|
344 } |
|
345 |
|
346 /** |
|
347 * xmlSchemaVTypeErrMemory: |
|
348 * @node: a context node |
|
349 * @extra: extra informations |
|
350 * |
|
351 * Handle an out of memory condition |
|
352 */ |
|
353 static void |
|
354 xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt, |
|
355 const char *extra, xmlNodePtr node) |
|
356 { |
|
357 if (ctxt != NULL) { |
|
358 ctxt->nberrors++; |
|
359 ctxt->err = XML_SCHEMAS_ERR_INTERNAL; |
|
360 } |
|
361 __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, |
|
362 extra); |
|
363 } |
|
364 |
|
365 /** |
|
366 * xmlSchemaVErr3: |
|
367 * @ctxt: the validation context |
|
368 * @node: the context node |
|
369 * @error: the error code |
|
370 * @msg: the error message |
|
371 * @str1: extra data |
|
372 * @str2: extra data |
|
373 * @str3: extra data |
|
374 * |
|
375 * Handle a validation error |
|
376 */ |
|
377 static void |
|
378 xmlSchemaVErr3(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error, |
|
379 const char *msg, const xmlChar *str1, const xmlChar *str2, |
|
380 const xmlChar *str3) |
|
381 { |
|
382 xmlStructuredErrorFunc schannel = NULL; |
|
383 xmlGenericErrorFunc channel = NULL; |
|
384 void *data = NULL; |
|
385 |
|
386 if (ctxt != NULL) { |
|
387 ctxt->nberrors++; |
|
388 ctxt->err = error; |
|
389 channel = ctxt->error; |
|
390 schannel = ctxt->serror; |
|
391 data = ctxt->userData; |
|
392 } |
|
393 /* reajust to global error numbers */ |
|
394 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT; |
|
395 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV, |
|
396 error, XML_ERR_ERROR, NULL, 0, |
|
397 (const char *) str1, (const char *) str2, |
|
398 (const char *) str3, 0, 0, |
|
399 msg, str1, str2, str3); |
|
400 } |
|
401 /** |
|
402 * xmlSchemaVErr: |
|
403 * @ctxt: the validation context |
|
404 * @node: the context node |
|
405 * @error: the error code |
|
406 * @msg: the error message |
|
407 * @str1: extra data |
|
408 * @str2: extra data |
|
409 * |
|
410 * Handle a validation error |
|
411 */ |
|
412 static void |
|
413 xmlSchemaVErr(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error, |
|
414 const char *msg, const xmlChar * str1, const xmlChar * str2) |
|
415 { |
|
416 xmlStructuredErrorFunc schannel = NULL; |
|
417 xmlGenericErrorFunc channel = NULL; |
|
418 void *data = NULL; |
|
419 |
|
420 if (ctxt != NULL) { |
|
421 ctxt->nberrors++; |
|
422 ctxt->err = error; |
|
423 channel = ctxt->error; |
|
424 data = ctxt->userData; |
|
425 schannel = ctxt->serror; |
|
426 } |
|
427 /* reajust to global error numbers */ |
|
428 error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT; |
|
429 __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV, |
|
430 error, XML_ERR_ERROR, NULL, 0, |
|
431 (const char *) str1, (const char *) str2, NULL, 0, 0, |
|
432 msg, str1, str2); |
|
433 } |
|
434 |
|
435 /************************************************************************ |
|
436 * * |
|
437 * Allocation functions * |
|
438 * * |
|
439 ************************************************************************/ |
|
440 |
|
441 /** |
|
442 * xmlSchemaNewSchema: |
|
443 * @ctxt: a schema validation context |
|
444 * |
|
445 * Allocate a new Schema structure. |
|
446 * |
|
447 * Returns the newly allocated structure or NULL in case or error |
|
448 */ |
|
449 static xmlSchemaPtr |
|
450 xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt) |
|
451 { |
|
452 xmlSchemaPtr ret; |
|
453 |
|
454 ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema)); |
|
455 if (ret == NULL) { |
|
456 xmlSchemaPErrMemory(ctxt, "allocating schema", NULL); |
|
457 return (NULL); |
|
458 } |
|
459 memset(ret, 0, sizeof(xmlSchema)); |
|
460 ret->dict = ctxt->dict; |
|
461 xmlDictReference(ret->dict); |
|
462 |
|
463 return (ret); |
|
464 } |
|
465 |
|
466 /** |
|
467 * xmlSchemaNewFacet: |
|
468 * |
|
469 * Allocate a new Facet structure. |
|
470 * |
|
471 * Returns the newly allocated structure or NULL in case or error |
|
472 */ |
|
473 xmlSchemaFacetPtr |
|
474 xmlSchemaNewFacet(void) |
|
475 { |
|
476 xmlSchemaFacetPtr ret; |
|
477 |
|
478 ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet)); |
|
479 if (ret == NULL) { |
|
480 return (NULL); |
|
481 } |
|
482 memset(ret, 0, sizeof(xmlSchemaFacet)); |
|
483 |
|
484 return (ret); |
|
485 } |
|
486 |
|
487 /** |
|
488 * xmlSchemaNewAnnot: |
|
489 * @ctxt: a schema validation context |
|
490 * @node: a node |
|
491 * |
|
492 * Allocate a new annotation structure. |
|
493 * |
|
494 * Returns the newly allocated structure or NULL in case or error |
|
495 */ |
|
496 static xmlSchemaAnnotPtr |
|
497 xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) |
|
498 { |
|
499 xmlSchemaAnnotPtr ret; |
|
500 |
|
501 ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot)); |
|
502 if (ret == NULL) { |
|
503 xmlSchemaPErrMemory(ctxt, "allocating annotation", node); |
|
504 return (NULL); |
|
505 } |
|
506 memset(ret, 0, sizeof(xmlSchemaAnnot)); |
|
507 ret->content = node; |
|
508 return (ret); |
|
509 } |
|
510 |
|
511 |
|
512 |
|
513 /** |
|
514 * xmlSchemaFreeImport: |
|
515 * @import: a schema import structure |
|
516 * |
|
517 * Deallocate an import structure |
|
518 */ |
|
519 static void |
|
520 xmlSchemaFreeImport(xmlSchemaImportPtr import) |
|
521 { |
|
522 if (import == NULL) |
|
523 return; |
|
524 |
|
525 xmlSchemaFree(import->schema); |
|
526 xmlFree(import); |
|
527 } |
|
528 |
|
529 /** |
|
530 * xmlSchemaFreeInclude: |
|
531 * @include: a schema include structure |
|
532 * |
|
533 * Deallocate an include structure |
|
534 */ |
|
535 static void |
|
536 xmlSchemaFreeInclude(xmlSchemaIncludePtr include) |
|
537 { |
|
538 if (include == NULL) |
|
539 return; |
|
540 |
|
541 xmlFreeDoc(include->doc); |
|
542 xmlFree(include); |
|
543 } |
|
544 |
|
545 /** |
|
546 * xmlSchemaFreeIncludeList: |
|
547 * @includes: a schema include list |
|
548 * |
|
549 * Deallocate an include structure |
|
550 */ |
|
551 static void |
|
552 xmlSchemaFreeIncludeList(xmlSchemaIncludePtr includes) |
|
553 { |
|
554 xmlSchemaIncludePtr next; |
|
555 |
|
556 while (includes != NULL) { |
|
557 next = includes->next; |
|
558 xmlSchemaFreeInclude(includes); |
|
559 includes = next; |
|
560 } |
|
561 } |
|
562 |
|
563 /** |
|
564 * xmlSchemaFreeNotation: |
|
565 * @schema: a schema notation structure |
|
566 * |
|
567 * Deallocate a Schema Notation structure. |
|
568 */ |
|
569 static void |
|
570 xmlSchemaFreeNotation(xmlSchemaNotationPtr nota) |
|
571 { |
|
572 if (nota == NULL) |
|
573 return; |
|
574 xmlFree(nota); |
|
575 } |
|
576 |
|
577 /** |
|
578 * xmlSchemaFreeAttribute: |
|
579 * @schema: a schema attribute structure |
|
580 * |
|
581 * Deallocate a Schema Attribute structure. |
|
582 */ |
|
583 static void |
|
584 xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr) |
|
585 { |
|
586 if (attr == NULL) |
|
587 return; |
|
588 xmlFree(attr); |
|
589 } |
|
590 |
|
591 /** |
|
592 * xmlSchemaFreeAttributeGroup: |
|
593 * @schema: a schema attribute group structure |
|
594 * |
|
595 * Deallocate a Schema Attribute Group structure. |
|
596 */ |
|
597 static void |
|
598 xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr) |
|
599 { |
|
600 if (attr == NULL) |
|
601 return; |
|
602 xmlFree(attr); |
|
603 } |
|
604 |
|
605 /** |
|
606 * xmlSchemaFreeElement: |
|
607 * @schema: a schema element structure |
|
608 * |
|
609 * Deallocate a Schema Element structure. |
|
610 */ |
|
611 static void |
|
612 xmlSchemaFreeElement(xmlSchemaElementPtr elem) |
|
613 { |
|
614 if (elem == NULL) |
|
615 return; |
|
616 if (elem->annot != NULL) |
|
617 xmlSchemaFreeAnnot(elem->annot); |
|
618 if (elem->contModel != NULL) |
|
619 xmlRegFreeRegexp(elem->contModel); |
|
620 xmlFree(elem); |
|
621 } |
|
622 |
|
623 /** |
|
624 * xmlSchemaFreeTypeList: |
|
625 * @type: a schema type structure |
|
626 * |
|
627 * Deallocate a Schema Type structure. |
|
628 */ |
|
629 static void |
|
630 xmlSchemaFreeTypeList(xmlSchemaTypePtr type) |
|
631 { |
|
632 xmlSchemaTypePtr next; |
|
633 |
|
634 while (type != NULL) { |
|
635 next = type->redef; |
|
636 xmlSchemaFreeType(type); |
|
637 type = next; |
|
638 } |
|
639 } |
|
640 |
|
641 /** |
|
642 * xmlSchemaFree: |
|
643 * @schema: a schema structure |
|
644 * |
|
645 * Deallocate a Schema structure. |
|
646 */ |
|
647 void |
|
648 xmlSchemaFree(xmlSchemaPtr schema) |
|
649 { |
|
650 if (schema == NULL) |
|
651 return; |
|
652 |
|
653 if (schema->notaDecl != NULL) |
|
654 xmlHashFree(schema->notaDecl, |
|
655 (xmlHashDeallocator) xmlSchemaFreeNotation); |
|
656 if (schema->attrDecl != NULL) |
|
657 xmlHashFree(schema->attrDecl, |
|
658 (xmlHashDeallocator) xmlSchemaFreeAttribute); |
|
659 if (schema->attrgrpDecl != NULL) |
|
660 xmlHashFree(schema->attrgrpDecl, |
|
661 (xmlHashDeallocator) xmlSchemaFreeAttributeGroup); |
|
662 if (schema->elemDecl != NULL) |
|
663 xmlHashFree(schema->elemDecl, |
|
664 (xmlHashDeallocator) xmlSchemaFreeElement); |
|
665 if (schema->typeDecl != NULL) |
|
666 xmlHashFree(schema->typeDecl, |
|
667 (xmlHashDeallocator) xmlSchemaFreeTypeList); |
|
668 if (schema->groupDecl != NULL) |
|
669 xmlHashFree(schema->groupDecl, |
|
670 (xmlHashDeallocator) xmlSchemaFreeType); |
|
671 if (schema->schemasImports != NULL) |
|
672 xmlHashFree(schema->schemasImports, |
|
673 (xmlHashDeallocator) xmlSchemaFreeImport); |
|
674 if (schema->includes != NULL) { |
|
675 xmlSchemaFreeIncludeList((xmlSchemaIncludePtr) schema->includes); |
|
676 } |
|
677 if (schema->annot != NULL) |
|
678 xmlSchemaFreeAnnot(schema->annot); |
|
679 if (schema->doc != NULL && !schema->preserve) |
|
680 xmlFreeDoc(schema->doc); |
|
681 xmlDictFree(schema->dict); |
|
682 |
|
683 xmlFree(schema); |
|
684 } |
|
685 |
|
686 /************************************************************************ |
|
687 * * |
|
688 * Debug functions * |
|
689 * * |
|
690 ************************************************************************/ |
|
691 |
|
692 #ifdef LIBXML_OUTPUT_ENABLED |
|
693 |
|
694 /** |
|
695 * xmlSchemaElementDump: |
|
696 * @elem: an element |
|
697 * @output: the file output |
|
698 * |
|
699 * Dump the element |
|
700 */ |
|
701 static void |
|
702 xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output, |
|
703 const xmlChar * name ATTRIBUTE_UNUSED, |
|
704 const xmlChar * context ATTRIBUTE_UNUSED, |
|
705 const xmlChar * namespace ATTRIBUTE_UNUSED) |
|
706 { |
|
707 if (elem == NULL) |
|
708 return; |
|
709 |
|
710 fprintf(output, "Element "); |
|
711 if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL) |
|
712 fprintf(output, "toplevel "); |
|
713 fprintf(output, ": %s ", elem->name); |
|
714 if (namespace != NULL) |
|
715 fprintf(output, "namespace '%s' ", namespace); |
|
716 |
|
717 if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE) |
|
718 fprintf(output, "nillable "); |
|
719 if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL) |
|
720 fprintf(output, "global "); |
|
721 if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT) |
|
722 fprintf(output, "default "); |
|
723 if (elem->flags & XML_SCHEMAS_ELEM_FIXED) |
|
724 fprintf(output, "fixed "); |
|
725 if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT) |
|
726 fprintf(output, "abstract "); |
|
727 if (elem->flags & XML_SCHEMAS_ELEM_REF) |
|
728 fprintf(output, "ref '%s' ", elem->ref); |
|
729 if (elem->id != NULL) |
|
730 fprintf(output, "id '%s' ", elem->id); |
|
731 fprintf(output, "\n"); |
|
732 if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) { |
|
733 fprintf(output, " "); |
|
734 if (elem->minOccurs != 1) |
|
735 fprintf(output, "min: %d ", elem->minOccurs); |
|
736 if (elem->maxOccurs >= UNBOUNDED) |
|
737 fprintf(output, "max: unbounded\n"); |
|
738 else if (elem->maxOccurs != 1) |
|
739 fprintf(output, "max: %d\n", elem->maxOccurs); |
|
740 else |
|
741 fprintf(output, "\n"); |
|
742 } |
|
743 if (elem->namedType != NULL) { |
|
744 fprintf(output, " type: %s", elem->namedType); |
|
745 if (elem->namedTypeNs != NULL) |
|
746 fprintf(output, " ns %s\n", elem->namedTypeNs); |
|
747 else |
|
748 fprintf(output, "\n"); |
|
749 } |
|
750 if (elem->substGroup != NULL) { |
|
751 fprintf(output, " substitutionGroup: %s", elem->substGroup); |
|
752 if (elem->substGroupNs != NULL) |
|
753 fprintf(output, " ns %s\n", elem->substGroupNs); |
|
754 else |
|
755 fprintf(output, "\n"); |
|
756 } |
|
757 if (elem->value != NULL) |
|
758 fprintf(output, " default: %s", elem->value); |
|
759 } |
|
760 |
|
761 /** |
|
762 * xmlSchemaAnnotDump: |
|
763 * @output: the file output |
|
764 * @annot: a annotation |
|
765 * |
|
766 * Dump the annotation |
|
767 */ |
|
768 static void |
|
769 xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot) |
|
770 { |
|
771 xmlChar *content; |
|
772 |
|
773 if (annot == NULL) |
|
774 return; |
|
775 |
|
776 content = xmlNodeGetContent(annot->content); |
|
777 if (content != NULL) { |
|
778 fprintf(output, " Annot: %s\n", content); |
|
779 xmlFree(content); |
|
780 } else |
|
781 fprintf(output, " Annot: empty\n"); |
|
782 } |
|
783 |
|
784 /** |
|
785 * xmlSchemaTypeDump: |
|
786 * @output: the file output |
|
787 * @type: a type structure |
|
788 * |
|
789 * Dump a SchemaType structure |
|
790 */ |
|
791 static void |
|
792 xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output) |
|
793 { |
|
794 if (type == NULL) { |
|
795 fprintf(output, "Type: NULL\n"); |
|
796 return; |
|
797 } |
|
798 fprintf(output, "Type: "); |
|
799 if (type->name != NULL) |
|
800 fprintf(output, "%s, ", type->name); |
|
801 else |
|
802 fprintf(output, "no name"); |
|
803 switch (type->type) { |
|
804 case XML_SCHEMA_TYPE_BASIC: |
|
805 fprintf(output, "basic "); |
|
806 break; |
|
807 case XML_SCHEMA_TYPE_SIMPLE: |
|
808 fprintf(output, "simple "); |
|
809 break; |
|
810 case XML_SCHEMA_TYPE_COMPLEX: |
|
811 fprintf(output, "complex "); |
|
812 break; |
|
813 case XML_SCHEMA_TYPE_SEQUENCE: |
|
814 fprintf(output, "sequence "); |
|
815 break; |
|
816 case XML_SCHEMA_TYPE_CHOICE: |
|
817 fprintf(output, "choice "); |
|
818 break; |
|
819 case XML_SCHEMA_TYPE_ALL: |
|
820 fprintf(output, "all "); |
|
821 break; |
|
822 case XML_SCHEMA_TYPE_UR: |
|
823 fprintf(output, "ur "); |
|
824 break; |
|
825 case XML_SCHEMA_TYPE_RESTRICTION: |
|
826 fprintf(output, "restriction "); |
|
827 break; |
|
828 case XML_SCHEMA_TYPE_EXTENSION: |
|
829 fprintf(output, "extension "); |
|
830 break; |
|
831 default: |
|
832 fprintf(output, "unknowntype%d ", type->type); |
|
833 break; |
|
834 } |
|
835 if (type->base != NULL) { |
|
836 fprintf(output, "base %s, ", type->base); |
|
837 } |
|
838 switch (type->contentType) { |
|
839 case XML_SCHEMA_CONTENT_UNKNOWN: |
|
840 fprintf(output, "unknown "); |
|
841 break; |
|
842 case XML_SCHEMA_CONTENT_EMPTY: |
|
843 fprintf(output, "empty "); |
|
844 break; |
|
845 case XML_SCHEMA_CONTENT_ELEMENTS: |
|
846 fprintf(output, "element "); |
|
847 break; |
|
848 case XML_SCHEMA_CONTENT_MIXED: |
|
849 fprintf(output, "mixed "); |
|
850 break; |
|
851 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: |
|
852 fprintf(output, "mixed_or_elems "); |
|
853 break; |
|
854 case XML_SCHEMA_CONTENT_BASIC: |
|
855 fprintf(output, "basic "); |
|
856 break; |
|
857 case XML_SCHEMA_CONTENT_SIMPLE: |
|
858 fprintf(output, "simple "); |
|
859 break; |
|
860 case XML_SCHEMA_CONTENT_ANY: |
|
861 fprintf(output, "any "); |
|
862 break; |
|
863 } |
|
864 fprintf(output, "\n"); |
|
865 if ((type->minOccurs != 1) || (type->maxOccurs != 1)) { |
|
866 fprintf(output, " "); |
|
867 if (type->minOccurs != 1) |
|
868 fprintf(output, "min: %d ", type->minOccurs); |
|
869 if (type->maxOccurs >= UNBOUNDED) |
|
870 fprintf(output, "max: unbounded\n"); |
|
871 else if (type->maxOccurs != 1) |
|
872 fprintf(output, "max: %d\n", type->maxOccurs); |
|
873 else |
|
874 fprintf(output, "\n"); |
|
875 } |
|
876 if (type->annot != NULL) |
|
877 xmlSchemaAnnotDump(output, type->annot); |
|
878 if (type->subtypes != NULL) { |
|
879 xmlSchemaTypePtr sub = type->subtypes; |
|
880 |
|
881 fprintf(output, " subtypes: "); |
|
882 while (sub != NULL) { |
|
883 fprintf(output, "%s ", sub->name); |
|
884 sub = sub->next; |
|
885 } |
|
886 fprintf(output, "\n"); |
|
887 } |
|
888 |
|
889 } |
|
890 |
|
891 /** |
|
892 * xmlSchemaDump: |
|
893 * @output: the file output |
|
894 * @schema: a schema structure |
|
895 * |
|
896 * Dump a Schema structure. |
|
897 */ |
|
898 void |
|
899 xmlSchemaDump(FILE * output, xmlSchemaPtr schema) |
|
900 { |
|
901 if (schema == NULL) { |
|
902 fprintf(output, "Schemas: NULL\n"); |
|
903 return; |
|
904 } |
|
905 fprintf(output, "Schemas: "); |
|
906 if (schema->name != NULL) |
|
907 fprintf(output, "%s, ", schema->name); |
|
908 else |
|
909 fprintf(output, "no name, "); |
|
910 if (schema->targetNamespace != NULL) |
|
911 fprintf(output, "%s", (const char *) schema->targetNamespace); |
|
912 else |
|
913 fprintf(output, "no target namespace"); |
|
914 fprintf(output, "\n"); |
|
915 if (schema->annot != NULL) |
|
916 xmlSchemaAnnotDump(output, schema->annot); |
|
917 |
|
918 xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump, |
|
919 output); |
|
920 xmlHashScanFull(schema->elemDecl, |
|
921 (xmlHashScannerFull) xmlSchemaElementDump, output); |
|
922 } |
|
923 #endif /* LIBXML_OUTPUT_ENABLED */ |
|
924 |
|
925 /************************************************************************ |
|
926 * * |
|
927 * Utilities * |
|
928 * * |
|
929 ************************************************************************/ |
|
930 |
|
931 /** |
|
932 * xmlSchemaGetProp: |
|
933 * @ctxt: the parser context |
|
934 * @node: the node |
|
935 * @name: the property name |
|
936 * |
|
937 * Read a attribute value and internalize the string |
|
938 * |
|
939 * Returns the string or NULL if not present. |
|
940 */ |
|
941 static const xmlChar * |
|
942 xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, |
|
943 const char *name) |
|
944 { |
|
945 xmlChar *val; |
|
946 const xmlChar *ret; |
|
947 |
|
948 val = xmlGetProp(node, BAD_CAST name); |
|
949 if (val == NULL) |
|
950 return(NULL); |
|
951 ret = xmlDictLookup(ctxt->dict, val, -1); |
|
952 xmlFree(val); |
|
953 return(ret); |
|
954 } |
|
955 |
|
956 #if 0 |
|
957 /** |
|
958 * xmlSchemaGetNamespace: |
|
959 * @ctxt: the parser context |
|
960 * @schema: the schemas containing the declaration |
|
961 * @node: the node |
|
962 * @qname: the QName to analyze |
|
963 * |
|
964 * Find the namespace name for the given declaration. |
|
965 * |
|
966 * Returns the local name for that declaration, as well as the namespace name |
|
967 * NOTE: This function is no longer used (Buchcik, May '04) |
|
968 */ |
|
969 static const xmlChar * |
|
970 xmlSchemaGetNamespace(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
971 xmlNodePtr node, const xmlChar *qname, |
|
972 const xmlChar **namespace) { |
|
973 int len; |
|
974 const xmlChar *name, *prefix, *def = NULL; |
|
975 xmlNsPtr ns; |
|
976 |
|
977 *namespace = NULL; |
|
978 |
|
979 /* TODO: The following seems to be not correct here: |
|
980 * 1. The name of a declaration is a NCName, not a QName. |
|
981 * 2. The attribute "targetNamespace" is allowed for the |
|
982 * <schema> Element Information Item only. |
|
983 * 3. One cannot evaluate the target namespace, by the type |
|
984 * of declaration, since it is dependant on the xxxFormDefault |
|
985 * of <schema> and the form attribute of an <element> or <attribute>. |
|
986 */ |
|
987 |
|
988 if (xmlStrEqual(node->name, BAD_CAST "element") || |
|
989 xmlStrEqual(node->name, BAD_CAST "attribute") || |
|
990 xmlStrEqual(node->name, BAD_CAST "simpleType") || |
|
991 xmlStrEqual(node->name, BAD_CAST "complexType")) { |
|
992 def = xmlSchemaGetProp(ctxt, node, "targetNamespace"); |
|
993 } |
|
994 |
|
995 |
|
996 qname = xmlDictLookup(ctxt->dict, qname, -1); /* intern the string */ |
|
997 name = xmlSplitQName3(qname, &len); |
|
998 if (name == NULL) { |
|
999 if (def == NULL) { |
|
1000 if (xmlStrEqual(node->name, BAD_CAST "element")) { |
|
1001 if (schema->flags & XML_SCHEMAS_QUALIF_ELEM) |
|
1002 *namespace = schema->targetNamespace; |
|
1003 } else if (xmlStrEqual(node->name, BAD_CAST "attribute")) { |
|
1004 if (schema->flags & XML_SCHEMAS_QUALIF_ATTR) |
|
1005 *namespace = schema->targetNamespace; |
|
1006 } else if ((xmlStrEqual(node->name, BAD_CAST "simpleType")) || |
|
1007 (xmlStrEqual(node->name, BAD_CAST "complexType"))) { |
|
1008 *namespace = schema->targetNamespace; |
|
1009 } |
|
1010 } else { |
|
1011 *namespace = def; |
|
1012 } |
|
1013 return(qname); |
|
1014 } |
|
1015 |
|
1016 name = xmlDictLookup(ctxt->dict, name, -1); |
|
1017 prefix = xmlDictLookup(ctxt->dict, qname, len); |
|
1018 if (def != NULL) { |
|
1019 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_DEF_AND_PREFIX, |
|
1020 "%s: presence of both prefix %s and targetNamespace\n", |
|
1021 node->name, prefix); |
|
1022 } |
|
1023 ns = xmlSearchNs(node->doc, node, prefix); |
|
1024 if (ns == NULL) { |
|
1025 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED, |
|
1026 "%s: the QName prefix %s is undefined\n", |
|
1027 node->name, prefix); |
|
1028 return(name); |
|
1029 } |
|
1030 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
|
1031 return(name); |
|
1032 } |
|
1033 #endif |
|
1034 |
|
1035 /************************************************************************ |
|
1036 * * |
|
1037 * Parsing functions * |
|
1038 * * |
|
1039 ************************************************************************/ |
|
1040 |
|
1041 /** |
|
1042 * xmlSchemaGetElem: |
|
1043 * @schema: the schemas context |
|
1044 * @name: the element name |
|
1045 * @ns: the element namespace |
|
1046 * @level: how deep is the request |
|
1047 * |
|
1048 * Lookup a an element in the schemas or the accessible schemas |
|
1049 * |
|
1050 * Returns the element definition or NULL if not found. |
|
1051 */ |
|
1052 static xmlSchemaElementPtr |
|
1053 xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, |
|
1054 const xmlChar * namespace, int level) |
|
1055 { |
|
1056 xmlSchemaElementPtr ret; |
|
1057 xmlSchemaImportPtr import = NULL; |
|
1058 |
|
1059 if ((name == NULL) || (schema == NULL)) |
|
1060 return (NULL); |
|
1061 |
|
1062 if (namespace == NULL) { |
|
1063 ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
|
1064 if ((ret != NULL) && |
|
1065 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
|
1066 return (ret); |
|
1067 } |
|
1068 /* |
|
1069 * This one was removed, since top level element declarations have |
|
1070 * the target namespace specified in targetNamespace of the <schema> |
|
1071 * information element, even if elementFormDefault is "unqualified". |
|
1072 */ |
|
1073 |
|
1074 /* else if ((schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0) { |
|
1075 if (xmlStrEqual(namespace, schema->targetNamespace)) |
|
1076 ret = xmlHashLookup2(schema->elemDecl, name, NULL); |
|
1077 else |
|
1078 ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
|
1079 if ((ret != NULL) && |
|
1080 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
|
1081 return (ret); |
|
1082 } |
|
1083 */ |
|
1084 } else { |
|
1085 ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
|
1086 if ((ret != NULL) && |
|
1087 ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
|
1088 return (ret); |
|
1089 } |
|
1090 } |
|
1091 if (level > 0) |
|
1092 import = xmlHashLookup(schema->schemasImports, namespace); |
|
1093 if (import != NULL) |
|
1094 ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1); |
|
1095 #ifdef DEBUG |
|
1096 if (ret == NULL) { |
|
1097 if (namespace == NULL) |
|
1098 fprintf(stderr, "Unable to lookup type %s", name); |
|
1099 else |
|
1100 fprintf(stderr, "Unable to lookup type %s:%s", name, |
|
1101 namespace); |
|
1102 } |
|
1103 #endif |
|
1104 return (ret); |
|
1105 } |
|
1106 |
|
1107 /** |
|
1108 * xmlSchemaGetType: |
|
1109 * @schema: the schemas context |
|
1110 * @name: the type name |
|
1111 * @ns: the type namespace |
|
1112 * |
|
1113 * Lookup a type in the schemas or the predefined types |
|
1114 * |
|
1115 * Returns the group definition or NULL if not found. |
|
1116 */ |
|
1117 static xmlSchemaTypePtr |
|
1118 xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name, |
|
1119 const xmlChar * namespace) |
|
1120 { |
|
1121 xmlSchemaTypePtr ret; |
|
1122 xmlSchemaImportPtr import; |
|
1123 |
|
1124 if (name == NULL) |
|
1125 return (NULL); |
|
1126 if (schema != NULL) { |
|
1127 ret = xmlHashLookup2(schema->typeDecl, name, namespace); |
|
1128 if (ret != NULL) |
|
1129 return (ret); |
|
1130 } |
|
1131 ret = xmlSchemaGetPredefinedType(name, namespace); |
|
1132 if (ret != NULL) |
|
1133 return (ret); |
|
1134 import = xmlHashLookup(schema->schemasImports, namespace); |
|
1135 if (import != NULL) |
|
1136 ret = xmlSchemaGetType(import->schema, name, namespace); |
|
1137 #ifdef DEBUG |
|
1138 if (ret == NULL) { |
|
1139 if (namespace == NULL) |
|
1140 fprintf(stderr, "Unable to lookup type %s", name); |
|
1141 else |
|
1142 fprintf(stderr, "Unable to lookup type %s:%s", name, |
|
1143 namespace); |
|
1144 } |
|
1145 #endif |
|
1146 return (ret); |
|
1147 } |
|
1148 |
|
1149 /************************************************************************ |
|
1150 * * |
|
1151 * Parsing functions * |
|
1152 * * |
|
1153 ************************************************************************/ |
|
1154 |
|
1155 #define IS_BLANK_NODE(n) \ |
|
1156 (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content))) |
|
1157 |
|
1158 /** |
|
1159 * xmlSchemaIsBlank: |
|
1160 * @str: a string |
|
1161 * |
|
1162 * Check if a string is ignorable |
|
1163 * |
|
1164 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise |
|
1165 */ |
|
1166 static int |
|
1167 xmlSchemaIsBlank(xmlChar * str) |
|
1168 { |
|
1169 if (str == NULL) |
|
1170 return (1); |
|
1171 while (*str != 0) { |
|
1172 if (!(IS_BLANK_CH(*str))) |
|
1173 return (0); |
|
1174 str++; |
|
1175 } |
|
1176 return (1); |
|
1177 } |
|
1178 |
|
1179 /** |
|
1180 * xmlSchemaAddNotation: |
|
1181 * @ctxt: a schema validation context |
|
1182 * @schema: the schema being built |
|
1183 * @name: the item name |
|
1184 * |
|
1185 * Add an XML schema Attrribute declaration |
|
1186 * *WARNING* this interface is highly subject to change |
|
1187 * |
|
1188 * Returns the new struture or NULL in case of error |
|
1189 */ |
|
1190 static xmlSchemaNotationPtr |
|
1191 xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1192 const xmlChar * name) |
|
1193 { |
|
1194 xmlSchemaNotationPtr ret = NULL; |
|
1195 int val; |
|
1196 |
|
1197 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1198 return (NULL); |
|
1199 |
|
1200 if (schema->notaDecl == NULL) |
|
1201 schema->notaDecl = xmlHashCreate(10); |
|
1202 if (schema->notaDecl == NULL) |
|
1203 return (NULL); |
|
1204 |
|
1205 ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation)); |
|
1206 if (ret == NULL) { |
|
1207 xmlSchemaPErrMemory(ctxt, "add annotation", NULL); |
|
1208 return (NULL); |
|
1209 } |
|
1210 memset(ret, 0, sizeof(xmlSchemaNotation)); |
|
1211 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1212 val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace, |
|
1213 ret); |
|
1214 if (val != 0) { |
|
1215 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1216 XML_SCHEMAP_REDEFINED_NOTATION, |
|
1217 "Notation %s already defined\n", |
|
1218 name, NULL); |
|
1219 xmlFree(ret); |
|
1220 return (NULL); |
|
1221 } |
|
1222 return (ret); |
|
1223 } |
|
1224 |
|
1225 |
|
1226 /** |
|
1227 * xmlSchemaAddAttribute: |
|
1228 * @ctxt: a schema validation context |
|
1229 * @schema: the schema being built |
|
1230 * @name: the item name |
|
1231 * @namespace: the namespace |
|
1232 * |
|
1233 * Add an XML schema Attrribute declaration |
|
1234 * *WARNING* this interface is highly subject to change |
|
1235 * |
|
1236 * Returns the new struture or NULL in case of error |
|
1237 */ |
|
1238 static xmlSchemaAttributePtr |
|
1239 xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1240 const xmlChar * name, const xmlChar * namespace) |
|
1241 { |
|
1242 xmlSchemaAttributePtr ret = NULL; |
|
1243 int val; |
|
1244 |
|
1245 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1246 return (NULL); |
|
1247 |
|
1248 #ifdef DEBUG |
|
1249 fprintf(stderr, "Adding attribute %s\n", name); |
|
1250 if (namespace != NULL) |
|
1251 fprintf(stderr, " target namespace %s\n", namespace); |
|
1252 #endif |
|
1253 |
|
1254 if (schema->attrDecl == NULL) |
|
1255 schema->attrDecl = xmlHashCreate(10); |
|
1256 if (schema->attrDecl == NULL) |
|
1257 return (NULL); |
|
1258 |
|
1259 ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); |
|
1260 if (ret == NULL) { |
|
1261 xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL); |
|
1262 return (NULL); |
|
1263 } |
|
1264 memset(ret, 0, sizeof(xmlSchemaAttribute)); |
|
1265 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1266 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1); |
|
1267 val = xmlHashAddEntry3(schema->attrDecl, name, |
|
1268 schema->targetNamespace, ctxt->container, ret); |
|
1269 if (val != 0) { |
|
1270 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1271 XML_SCHEMAP_REDEFINED_ATTR, |
|
1272 "Attribute %s already defined\n", |
|
1273 name, NULL); |
|
1274 xmlFree(ret); |
|
1275 return (NULL); |
|
1276 } |
|
1277 return (ret); |
|
1278 } |
|
1279 |
|
1280 /** |
|
1281 * xmlSchemaAddAttributeGroup: |
|
1282 * @ctxt: a schema validation context |
|
1283 * @schema: the schema being built |
|
1284 * @name: the item name |
|
1285 * |
|
1286 * Add an XML schema Attrribute Group declaration |
|
1287 * |
|
1288 * Returns the new struture or NULL in case of error |
|
1289 */ |
|
1290 static xmlSchemaAttributeGroupPtr |
|
1291 xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
|
1292 xmlSchemaPtr schema, const xmlChar * name) |
|
1293 { |
|
1294 xmlSchemaAttributeGroupPtr ret = NULL; |
|
1295 int val; |
|
1296 |
|
1297 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1298 return (NULL); |
|
1299 |
|
1300 if (schema->attrgrpDecl == NULL) |
|
1301 schema->attrgrpDecl = xmlHashCreate(10); |
|
1302 if (schema->attrgrpDecl == NULL) |
|
1303 return (NULL); |
|
1304 |
|
1305 ret = |
|
1306 (xmlSchemaAttributeGroupPtr) |
|
1307 xmlMalloc(sizeof(xmlSchemaAttributeGroup)); |
|
1308 if (ret == NULL) { |
|
1309 xmlSchemaPErrMemory(ctxt, "allocating attribute group", NULL); |
|
1310 return (NULL); |
|
1311 } |
|
1312 memset(ret, 0, sizeof(xmlSchemaAttributeGroup)); |
|
1313 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1314 val = xmlHashAddEntry3(schema->attrgrpDecl, name, |
|
1315 schema->targetNamespace, ctxt->container, ret); |
|
1316 if (val != 0) { |
|
1317 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1318 XML_SCHEMAP_REDEFINED_ATTRGROUP, |
|
1319 "Attribute group %s already defined\n", |
|
1320 name, NULL); |
|
1321 xmlFree(ret); |
|
1322 return (NULL); |
|
1323 } |
|
1324 return (ret); |
|
1325 } |
|
1326 |
|
1327 /** |
|
1328 * xmlSchemaAddElement: |
|
1329 * @ctxt: a schema validation context |
|
1330 * @schema: the schema being built |
|
1331 * @name: the type name |
|
1332 * @namespace: the type namespace |
|
1333 * |
|
1334 * Add an XML schema Element declaration |
|
1335 * *WARNING* this interface is highly subject to change |
|
1336 * |
|
1337 * Returns the new struture or NULL in case of error |
|
1338 */ |
|
1339 static xmlSchemaElementPtr |
|
1340 xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1341 const xmlChar * name, const xmlChar * namespace) |
|
1342 { |
|
1343 xmlSchemaElementPtr ret = NULL; |
|
1344 int val; |
|
1345 |
|
1346 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1347 return (NULL); |
|
1348 |
|
1349 #ifdef DEBUG |
|
1350 fprintf(stderr, "Adding element %s\n", name); |
|
1351 if (namespace != NULL) |
|
1352 fprintf(stderr, " target namespace %s\n", namespace); |
|
1353 #endif |
|
1354 |
|
1355 if (schema->elemDecl == NULL) |
|
1356 schema->elemDecl = xmlHashCreate(10); |
|
1357 if (schema->elemDecl == NULL) |
|
1358 return (NULL); |
|
1359 |
|
1360 ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); |
|
1361 if (ret == NULL) { |
|
1362 xmlSchemaPErrMemory(ctxt, "allocating element", NULL); |
|
1363 return (NULL); |
|
1364 } |
|
1365 memset(ret, 0, sizeof(xmlSchemaElement)); |
|
1366 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1367 ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1); |
|
1368 val = xmlHashAddEntry3(schema->elemDecl, name, |
|
1369 namespace, ctxt->container, ret); |
|
1370 if (val != 0) { |
|
1371 char buf[100]; |
|
1372 |
|
1373 snprintf(buf, 99, "privatieelem %d", ctxt->counter++ + 1); |
|
1374 val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf, |
|
1375 namespace, ret); |
|
1376 if (val != 0) { |
|
1377 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1378 XML_SCHEMAP_REDEFINED_ELEMENT, |
|
1379 "Element %s already defined\n", |
|
1380 name, NULL); |
|
1381 xmlFree(ret); |
|
1382 return (NULL); |
|
1383 } |
|
1384 } |
|
1385 return (ret); |
|
1386 } |
|
1387 |
|
1388 /** |
|
1389 * xmlSchemaAddType: |
|
1390 * @ctxt: a schema validation context |
|
1391 * @schema: the schema being built |
|
1392 * @name: the item name |
|
1393 * @namespace: the namespace |
|
1394 * |
|
1395 * Add an XML schema Simple Type definition |
|
1396 * *WARNING* this interface is highly subject to change |
|
1397 * |
|
1398 * Returns the new struture or NULL in case of error |
|
1399 */ |
|
1400 static xmlSchemaTypePtr |
|
1401 xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1402 const xmlChar * name, const xmlChar * namespace) |
|
1403 { |
|
1404 xmlSchemaTypePtr ret = NULL; |
|
1405 int val; |
|
1406 |
|
1407 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1408 return (NULL); |
|
1409 |
|
1410 #ifdef DEBUG |
|
1411 fprintf(stderr, "Adding type %s\n", name); |
|
1412 if (namespace != NULL) |
|
1413 fprintf(stderr, " target namespace %s\n", namespace); |
|
1414 #endif |
|
1415 |
|
1416 if (schema->typeDecl == NULL) |
|
1417 schema->typeDecl = xmlHashCreate(10); |
|
1418 if (schema->typeDecl == NULL) |
|
1419 return (NULL); |
|
1420 |
|
1421 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); |
|
1422 if (ret == NULL) { |
|
1423 xmlSchemaPErrMemory(ctxt, "allocating type", NULL); |
|
1424 return (NULL); |
|
1425 } |
|
1426 memset(ret, 0, sizeof(xmlSchemaType)); |
|
1427 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1428 ret->redef = NULL; |
|
1429 val = xmlHashAddEntry2(schema->typeDecl, name, namespace, ret); |
|
1430 if (val != 0) { |
|
1431 if (ctxt->includes == 0) { |
|
1432 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1433 XML_SCHEMAP_REDEFINED_TYPE, |
|
1434 "Type %s already defined\n", |
|
1435 name, NULL); |
|
1436 xmlFree(ret); |
|
1437 return (NULL); |
|
1438 } else { |
|
1439 xmlSchemaTypePtr prev; |
|
1440 |
|
1441 prev = xmlHashLookup2(schema->typeDecl, name, namespace); |
|
1442 if (prev == NULL) { |
|
1443 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1444 XML_ERR_INTERNAL_ERROR, |
|
1445 "Internal error on type %s definition\n", |
|
1446 name, NULL); |
|
1447 xmlFree(ret); |
|
1448 return (NULL); |
|
1449 } |
|
1450 ret->redef = prev->redef; |
|
1451 prev->redef = ret; |
|
1452 } |
|
1453 } |
|
1454 ret->minOccurs = 1; |
|
1455 ret->maxOccurs = 1; |
|
1456 |
|
1457 return (ret); |
|
1458 } |
|
1459 |
|
1460 /** |
|
1461 * xmlSchemaAddGroup: |
|
1462 * @ctxt: a schema validation context |
|
1463 * @schema: the schema being built |
|
1464 * @name: the group name |
|
1465 * |
|
1466 * Add an XML schema Group definition |
|
1467 * |
|
1468 * Returns the new struture or NULL in case of error |
|
1469 */ |
|
1470 static xmlSchemaTypePtr |
|
1471 xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1472 const xmlChar * name) |
|
1473 { |
|
1474 xmlSchemaTypePtr ret = NULL; |
|
1475 int val; |
|
1476 |
|
1477 if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
|
1478 return (NULL); |
|
1479 |
|
1480 if (schema->groupDecl == NULL) |
|
1481 schema->groupDecl = xmlHashCreate(10); |
|
1482 if (schema->groupDecl == NULL) |
|
1483 return (NULL); |
|
1484 |
|
1485 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); |
|
1486 if (ret == NULL) { |
|
1487 xmlSchemaPErrMemory(ctxt, "adding group", NULL); |
|
1488 return (NULL); |
|
1489 } |
|
1490 memset(ret, 0, sizeof(xmlSchemaType)); |
|
1491 ret->name = xmlDictLookup(ctxt->dict, name, -1); |
|
1492 val = |
|
1493 xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace, |
|
1494 ret); |
|
1495 if (val != 0) { |
|
1496 xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
|
1497 XML_SCHEMAP_REDEFINED_GROUP, |
|
1498 "Group %s already defined\n", |
|
1499 name, NULL); |
|
1500 xmlFree(ret); |
|
1501 return (NULL); |
|
1502 } |
|
1503 ret->minOccurs = 1; |
|
1504 ret->maxOccurs = 1; |
|
1505 |
|
1506 return (ret); |
|
1507 } |
|
1508 |
|
1509 /************************************************************************ |
|
1510 * * |
|
1511 * Utilities for parsing * |
|
1512 * * |
|
1513 ************************************************************************/ |
|
1514 |
|
1515 /** |
|
1516 * xmlGetQNameProp: |
|
1517 * @ctxt: a schema validation context |
|
1518 * @node: a subtree containing XML Schema informations |
|
1519 * @name: the attribute name |
|
1520 * @namespace: the result namespace if any |
|
1521 * |
|
1522 * Extract a QName Attribute value |
|
1523 * |
|
1524 * Returns the NCName or NULL if not found, and also update @namespace |
|
1525 * with the namespace URI |
|
1526 */ |
|
1527 static const xmlChar * |
|
1528 xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, |
|
1529 const char *name, const xmlChar ** namespace) |
|
1530 { |
|
1531 const xmlChar *val; |
|
1532 xmlNsPtr ns; |
|
1533 const xmlChar *ret, *prefix; |
|
1534 int len; |
|
1535 |
|
1536 *namespace = NULL; |
|
1537 val = xmlSchemaGetProp(ctxt, node, name); |
|
1538 if (val == NULL) |
|
1539 return (NULL); |
|
1540 |
|
1541 if (!strchr((char *) val, ':')) { |
|
1542 ns = xmlSearchNs(node->doc, node, 0); |
|
1543 if (ns) { |
|
1544 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
|
1545 return (val); |
|
1546 } |
|
1547 } |
|
1548 ret = xmlSplitQName3(val, &len); |
|
1549 if (ret == NULL) { |
|
1550 return (val); |
|
1551 } |
|
1552 ret = xmlDictLookup(ctxt->dict, ret, -1); |
|
1553 prefix = xmlDictLookup(ctxt->dict, val, len); |
|
1554 |
|
1555 ns = xmlSearchNs(node->doc, node, prefix); |
|
1556 if (ns == NULL) { |
|
1557 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED, |
|
1558 "Attribute %s: the QName prefix %s is undefined\n", |
|
1559 (const xmlChar *) name, prefix); |
|
1560 } else { |
|
1561 *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
|
1562 } |
|
1563 return (ret); |
|
1564 } |
|
1565 |
|
1566 /** |
|
1567 * xmlGetMaxOccurs: |
|
1568 * @ctxt: a schema validation context |
|
1569 * @node: a subtree containing XML Schema informations |
|
1570 * |
|
1571 * Get the maxOccurs property |
|
1572 * |
|
1573 * Returns the default if not found, or the value |
|
1574 */ |
|
1575 static int |
|
1576 xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) |
|
1577 { |
|
1578 const xmlChar *val, *cur; |
|
1579 int ret = 0; |
|
1580 |
|
1581 val = xmlSchemaGetProp(ctxt, node, "maxOccurs"); |
|
1582 if (val == NULL) |
|
1583 return (1); |
|
1584 |
|
1585 if (xmlStrEqual(val, (const xmlChar *) "unbounded")) { |
|
1586 return (UNBOUNDED); /* encoding it with -1 might be another option */ |
|
1587 } |
|
1588 |
|
1589 cur = val; |
|
1590 while (IS_BLANK_CH(*cur)) |
|
1591 cur++; |
|
1592 while ((*cur >= '0') && (*cur <= '9')) { |
|
1593 ret = ret * 10 + (*cur - '0'); |
|
1594 cur++; |
|
1595 } |
|
1596 while (IS_BLANK_CH(*cur)) |
|
1597 cur++; |
|
1598 if (*cur != 0) { |
|
1599 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS, |
|
1600 "invalid value for maxOccurs: %s\n", val, NULL); |
|
1601 return (1); |
|
1602 } |
|
1603 return (ret); |
|
1604 } |
|
1605 |
|
1606 /** |
|
1607 * xmlGetMinOccurs: |
|
1608 * @ctxt: a schema validation context |
|
1609 * @node: a subtree containing XML Schema informations |
|
1610 * |
|
1611 * Get the minOccurs property |
|
1612 * |
|
1613 * Returns the default if not found, or the value |
|
1614 */ |
|
1615 static int |
|
1616 xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) |
|
1617 { |
|
1618 const xmlChar *val, *cur; |
|
1619 int ret = 0; |
|
1620 |
|
1621 val = xmlSchemaGetProp(ctxt, node, "minOccurs"); |
|
1622 if (val == NULL) |
|
1623 return (1); |
|
1624 |
|
1625 cur = val; |
|
1626 while (IS_BLANK_CH(*cur)) |
|
1627 cur++; |
|
1628 while ((*cur >= '0') && (*cur <= '9')) { |
|
1629 ret = ret * 10 + (*cur - '0'); |
|
1630 cur++; |
|
1631 } |
|
1632 while (IS_BLANK_CH(*cur)) |
|
1633 cur++; |
|
1634 if (*cur != 0) { |
|
1635 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS, |
|
1636 "invalid value for minOccurs: %s\n", val, NULL); |
|
1637 return (1); |
|
1638 } |
|
1639 return (ret); |
|
1640 } |
|
1641 |
|
1642 /** |
|
1643 * xmlGetBooleanProp: |
|
1644 * @ctxt: a schema validation context |
|
1645 * @node: a subtree containing XML Schema informations |
|
1646 * @name: the attribute name |
|
1647 * @def: the default value |
|
1648 * |
|
1649 * Get is a bolean property is set |
|
1650 * |
|
1651 * Returns the default if not found, 0 if found to be false, |
|
1652 * 1 if found to be true |
|
1653 */ |
|
1654 static int |
|
1655 xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, |
|
1656 const char *name, int def) |
|
1657 { |
|
1658 const xmlChar *val; |
|
1659 |
|
1660 val = xmlSchemaGetProp(ctxt, node, name); |
|
1661 if (val == NULL) |
|
1662 return (def); |
|
1663 |
|
1664 if (xmlStrEqual(val, BAD_CAST "true")) |
|
1665 def = 1; |
|
1666 else if (xmlStrEqual(val, BAD_CAST "false")) |
|
1667 def = 0; |
|
1668 else { |
|
1669 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_BOOLEAN, |
|
1670 "Attribute %s: the value %s is not boolean\n", |
|
1671 (const xmlChar *) name, val); |
|
1672 } |
|
1673 return (def); |
|
1674 } |
|
1675 |
|
1676 /************************************************************************ |
|
1677 * * |
|
1678 * Shema extraction from an Infoset * |
|
1679 * * |
|
1680 ************************************************************************/ |
|
1681 static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr |
|
1682 ctxt, xmlSchemaPtr schema, |
|
1683 xmlNodePtr node); |
|
1684 static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr |
|
1685 ctxt, |
|
1686 xmlSchemaPtr schema, |
|
1687 xmlNodePtr node); |
|
1688 static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr |
|
1689 ctxt, |
|
1690 xmlSchemaPtr schema, |
|
1691 xmlNodePtr node, |
|
1692 int simple); |
|
1693 static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, |
|
1694 xmlSchemaPtr schema, |
|
1695 xmlNodePtr node); |
|
1696 static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, |
|
1697 xmlSchemaPtr schema, |
|
1698 xmlNodePtr node); |
|
1699 static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr |
|
1700 ctxt, |
|
1701 xmlSchemaPtr schema, |
|
1702 xmlNodePtr node, |
|
1703 int topLevel); |
|
1704 static xmlSchemaAttributeGroupPtr |
|
1705 xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
|
1706 xmlSchemaPtr schema, xmlNodePtr node); |
|
1707 static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, |
|
1708 xmlSchemaPtr schema, |
|
1709 xmlNodePtr node); |
|
1710 static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, |
|
1711 xmlSchemaPtr schema, |
|
1712 xmlNodePtr node); |
|
1713 static xmlSchemaAttributePtr |
|
1714 xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, |
|
1715 xmlSchemaPtr schema, xmlNodePtr node); |
|
1716 |
|
1717 /** |
|
1718 * xmlSchemaParseAttrDecls: |
|
1719 * @ctxt: a schema validation context |
|
1720 * @schema: the schema being built |
|
1721 * @node: a subtree containing XML Schema informations |
|
1722 * @type: the hosting type |
|
1723 * |
|
1724 * parse a XML schema attrDecls declaration corresponding to |
|
1725 * <!ENTITY % attrDecls |
|
1726 * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'> |
|
1727 */ |
|
1728 static xmlNodePtr |
|
1729 xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1730 xmlNodePtr child, xmlSchemaTypePtr type) |
|
1731 { |
|
1732 xmlSchemaAttributePtr lastattr, attr; |
|
1733 |
|
1734 lastattr = NULL; |
|
1735 while ((IS_SCHEMA(child, "attribute")) || |
|
1736 (IS_SCHEMA(child, "attributeGroup"))) { |
|
1737 attr = NULL; |
|
1738 if (IS_SCHEMA(child, "attribute")) { |
|
1739 attr = xmlSchemaParseAttribute(ctxt, schema, child, 0); |
|
1740 } else if (IS_SCHEMA(child, "attributeGroup")) { |
|
1741 attr = (xmlSchemaAttributePtr) |
|
1742 xmlSchemaParseAttributeGroup(ctxt, schema, child); |
|
1743 } |
|
1744 if (attr != NULL) { |
|
1745 if (lastattr == NULL) { |
|
1746 type->attributes = attr; |
|
1747 lastattr = attr; |
|
1748 } else { |
|
1749 lastattr->next = attr; |
|
1750 lastattr = attr; |
|
1751 } |
|
1752 } |
|
1753 child = child->next; |
|
1754 } |
|
1755 if (IS_SCHEMA(child, "anyAttribute")) { |
|
1756 attr = xmlSchemaParseAnyAttribute(ctxt, schema, child); |
|
1757 if (attr != NULL) { |
|
1758 if (lastattr == NULL) { |
|
1759 type->attributes = attr; |
|
1760 lastattr = attr; |
|
1761 } else { |
|
1762 lastattr->next = attr; |
|
1763 lastattr = attr; |
|
1764 } |
|
1765 } |
|
1766 child = child->next; |
|
1767 } |
|
1768 return (child); |
|
1769 } |
|
1770 |
|
1771 /** |
|
1772 * xmlSchemaParseAnnotation: |
|
1773 * @ctxt: a schema validation context |
|
1774 * @schema: the schema being built |
|
1775 * @node: a subtree containing XML Schema informations |
|
1776 * |
|
1777 * parse a XML schema Attrribute declaration |
|
1778 * *WARNING* this interface is highly subject to change |
|
1779 * |
|
1780 * Returns -1 in case of error, 0 if the declaration is improper and |
|
1781 * 1 in case of success. |
|
1782 */ |
|
1783 static xmlSchemaAnnotPtr |
|
1784 xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1785 xmlNodePtr node) |
|
1786 { |
|
1787 xmlSchemaAnnotPtr ret; |
|
1788 |
|
1789 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
1790 return (NULL); |
|
1791 ret = xmlSchemaNewAnnot(ctxt, node); |
|
1792 |
|
1793 return (ret); |
|
1794 } |
|
1795 |
|
1796 /** |
|
1797 * xmlSchemaParseFacet: |
|
1798 * @ctxt: a schema validation context |
|
1799 * @schema: the schema being built |
|
1800 * @node: a subtree containing XML Schema informations |
|
1801 * |
|
1802 * parse a XML schema Facet declaration |
|
1803 * *WARNING* this interface is highly subject to change |
|
1804 * |
|
1805 * Returns the new type structure or NULL in case of error |
|
1806 */ |
|
1807 static xmlSchemaFacetPtr |
|
1808 xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1809 xmlNodePtr node) |
|
1810 { |
|
1811 xmlSchemaFacetPtr facet; |
|
1812 xmlNodePtr child = NULL; |
|
1813 const xmlChar *value; |
|
1814 |
|
1815 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
1816 return (NULL); |
|
1817 |
|
1818 facet = xmlSchemaNewFacet(); |
|
1819 if (facet == NULL) { |
|
1820 xmlSchemaPErrMemory(ctxt, "allocating facet", node); |
|
1821 return (NULL); |
|
1822 } |
|
1823 facet->node = node; |
|
1824 value = xmlSchemaGetProp(ctxt, node, "value"); |
|
1825 if (value == NULL) { |
|
1826 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE, |
|
1827 "Facet %s has no value\n", node->name, NULL); |
|
1828 xmlSchemaFreeFacet(facet); |
|
1829 return (NULL); |
|
1830 } |
|
1831 if (IS_SCHEMA(node, "minInclusive")) { |
|
1832 facet->type = XML_SCHEMA_FACET_MININCLUSIVE; |
|
1833 } else if (IS_SCHEMA(node, "minExclusive")) { |
|
1834 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; |
|
1835 } else if (IS_SCHEMA(node, "maxInclusive")) { |
|
1836 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; |
|
1837 } else if (IS_SCHEMA(node, "maxExclusive")) { |
|
1838 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; |
|
1839 } else if (IS_SCHEMA(node, "totalDigits")) { |
|
1840 facet->type = XML_SCHEMA_FACET_TOTALDIGITS; |
|
1841 } else if (IS_SCHEMA(node, "fractionDigits")) { |
|
1842 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; |
|
1843 } else if (IS_SCHEMA(node, "pattern")) { |
|
1844 facet->type = XML_SCHEMA_FACET_PATTERN; |
|
1845 } else if (IS_SCHEMA(node, "enumeration")) { |
|
1846 facet->type = XML_SCHEMA_FACET_ENUMERATION; |
|
1847 } else if (IS_SCHEMA(node, "whiteSpace")) { |
|
1848 facet->type = XML_SCHEMA_FACET_WHITESPACE; |
|
1849 } else if (IS_SCHEMA(node, "length")) { |
|
1850 facet->type = XML_SCHEMA_FACET_LENGTH; |
|
1851 } else if (IS_SCHEMA(node, "maxLength")) { |
|
1852 facet->type = XML_SCHEMA_FACET_MAXLENGTH; |
|
1853 } else if (IS_SCHEMA(node, "minLength")) { |
|
1854 facet->type = XML_SCHEMA_FACET_MINLENGTH; |
|
1855 } else { |
|
1856 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE, |
|
1857 "Unknown facet type %s\n", node->name, NULL); |
|
1858 xmlSchemaFreeFacet(facet); |
|
1859 return (NULL); |
|
1860 } |
|
1861 facet->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
1862 facet->value = value; |
|
1863 child = node->children; |
|
1864 |
|
1865 if (IS_SCHEMA(child, "annotation")) { |
|
1866 facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
1867 child = child->next; |
|
1868 } |
|
1869 if (child != NULL) { |
|
1870 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD, |
|
1871 "Facet %s has unexpected child content\n", |
|
1872 node->name, NULL); |
|
1873 } |
|
1874 return (facet); |
|
1875 } |
|
1876 |
|
1877 /** |
|
1878 * xmlSchemaParseAny: |
|
1879 * @ctxt: a schema validation context |
|
1880 * @schema: the schema being built |
|
1881 * @node: a subtree containing XML Schema informations |
|
1882 * |
|
1883 * parse a XML schema Any declaration |
|
1884 * *WARNING* this interface is highly subject to change |
|
1885 * |
|
1886 * Returns the new type structure or NULL in case of error |
|
1887 */ |
|
1888 static xmlSchemaTypePtr |
|
1889 xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1890 xmlNodePtr node) |
|
1891 { |
|
1892 xmlSchemaTypePtr type; |
|
1893 xmlNodePtr child = NULL; |
|
1894 xmlChar name[30]; |
|
1895 |
|
1896 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
1897 return (NULL); |
|
1898 snprintf((char *) name, 30, "any %d", ctxt->counter++ + 1); |
|
1899 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
1900 if (type == NULL) |
|
1901 return (NULL); |
|
1902 type->node = node; |
|
1903 type->type = XML_SCHEMA_TYPE_ANY; |
|
1904 child = node->children; |
|
1905 type->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
1906 type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
1907 |
|
1908 if (IS_SCHEMA(child, "annotation")) { |
|
1909 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
1910 child = child->next; |
|
1911 } |
|
1912 if (child != NULL) { |
|
1913 xmlSchemaPErr2(ctxt, node, child, |
|
1914 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, |
|
1915 "Sequence %s has unexpected content\n", type->name, |
|
1916 NULL); |
|
1917 } |
|
1918 |
|
1919 return (type); |
|
1920 } |
|
1921 |
|
1922 /** |
|
1923 * xmlSchemaParseNotation: |
|
1924 * @ctxt: a schema validation context |
|
1925 * @schema: the schema being built |
|
1926 * @node: a subtree containing XML Schema informations |
|
1927 * |
|
1928 * parse a XML schema Notation declaration |
|
1929 * |
|
1930 * Returns the new structure or NULL in case of error |
|
1931 */ |
|
1932 static xmlSchemaNotationPtr |
|
1933 xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
1934 xmlNodePtr node) |
|
1935 { |
|
1936 const xmlChar *name; |
|
1937 xmlSchemaNotationPtr ret; |
|
1938 xmlNodePtr child = NULL; |
|
1939 |
|
1940 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
1941 return (NULL); |
|
1942 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
1943 if (name == NULL) { |
|
1944 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME, |
|
1945 "Notation has no name\n", NULL, NULL); |
|
1946 return (NULL); |
|
1947 } |
|
1948 ret = xmlSchemaAddNotation(ctxt, schema, name); |
|
1949 if (ret == NULL) { |
|
1950 return (NULL); |
|
1951 } |
|
1952 child = node->children; |
|
1953 if (IS_SCHEMA(child, "annotation")) { |
|
1954 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
1955 child = child->next; |
|
1956 } |
|
1957 if (child != NULL) { |
|
1958 xmlSchemaPErr2(ctxt, node, child, |
|
1959 XML_SCHEMAP_UNKNOWN_NOTATION_CHILD, |
|
1960 "notation %s has unexpected content\n", name, NULL); |
|
1961 } |
|
1962 |
|
1963 return (ret); |
|
1964 } |
|
1965 |
|
1966 /** |
|
1967 * xmlSchemaParseAnyAttribute: |
|
1968 * @ctxt: a schema validation context |
|
1969 * @schema: the schema being built |
|
1970 * @node: a subtree containing XML Schema informations |
|
1971 * |
|
1972 * parse a XML schema AnyAttrribute declaration |
|
1973 * *WARNING* this interface is highly subject to change |
|
1974 * |
|
1975 * Returns an attribute def structure or NULL |
|
1976 */ |
|
1977 static xmlSchemaAttributePtr |
|
1978 xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, |
|
1979 xmlSchemaPtr schema, xmlNodePtr node) |
|
1980 { |
|
1981 const xmlChar *processContents; |
|
1982 xmlSchemaAttributePtr ret; |
|
1983 xmlNodePtr child = NULL; |
|
1984 char name[100]; |
|
1985 |
|
1986 |
|
1987 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
1988 return (NULL); |
|
1989 |
|
1990 snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1); |
|
1991 |
|
1992 /* local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns); */ |
|
1993 |
|
1994 /* |
|
1995 * TODO: namespace = ((##any | ##other) | List of (anyURI | |
|
1996 * (##targetNamespace | * ##local)) ) : ##any |
|
1997 */ |
|
1998 ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, NULL); |
|
1999 if (ret == NULL) { |
|
2000 return (NULL); |
|
2001 } |
|
2002 ret->type = XML_SCHEMA_TYPE_ANY_ATTRIBUTE; |
|
2003 ret->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2004 processContents = xmlSchemaGetProp(ctxt, node, "processContents"); |
|
2005 if ((processContents == NULL) |
|
2006 || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) { |
|
2007 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; |
|
2008 } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) { |
|
2009 ret->occurs = XML_SCHEMAS_ANYATTR_SKIP; |
|
2010 } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) { |
|
2011 ret->occurs = XML_SCHEMAS_ANYATTR_LAX; |
|
2012 } else { |
|
2013 xmlSchemaPErr2(ctxt, node, child, |
|
2014 XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, |
|
2015 "anyAttribute has unexpected content " |
|
2016 "for processContents: %s\n", |
|
2017 processContents, NULL); |
|
2018 ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; |
|
2019 } |
|
2020 |
|
2021 child = node->children; |
|
2022 if (IS_SCHEMA(child, "annotation")) { |
|
2023 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2024 child = child->next; |
|
2025 } |
|
2026 if (child != NULL) { |
|
2027 xmlSchemaPErr2(ctxt, node, child, |
|
2028 XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, |
|
2029 "anyAttribute %s has unexpected content\n", |
|
2030 (const xmlChar *) name, NULL); |
|
2031 } |
|
2032 |
|
2033 return (ret); |
|
2034 } |
|
2035 |
|
2036 |
|
2037 /** |
|
2038 * xmlSchemaParseAttribute: |
|
2039 * @ctxt: a schema validation context |
|
2040 * @schema: the schema being built |
|
2041 * @node: a subtree containing XML Schema informations |
|
2042 * |
|
2043 * parse a XML schema Attrribute declaration |
|
2044 * *WARNING* this interface is highly subject to change |
|
2045 * |
|
2046 * Returns the attribute declaration. |
|
2047 */ |
|
2048 static xmlSchemaAttributePtr |
|
2049 xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2050 xmlNodePtr node, int topLevel) |
|
2051 { |
|
2052 const xmlChar *name, *refNs = NULL, *ref = NULL, *attrVal; |
|
2053 xmlSchemaAttributePtr ret; |
|
2054 xmlNodePtr child = NULL; |
|
2055 char buf[100]; |
|
2056 int hasRefType = 0; |
|
2057 |
|
2058 /* |
|
2059 * Note that the w3c spec assumes the schema to be validated with schema |
|
2060 * for schemas beforehand. |
|
2061 * |
|
2062 * 3.2.3 Constraints on XML Representations of Attribute Declarations |
|
2063 * |
|
2064 * TODO: Complete implementation of: |
|
2065 * 3.2.6 Schema Component Constraint: Attribute Declaration Properties |
|
2066 * Correct |
|
2067 */ |
|
2068 |
|
2069 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2070 return (NULL); |
|
2071 |
|
2072 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
2073 if (name == NULL) { |
|
2074 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
|
2075 /* 3.2.3 : 3.1 |
|
2076 * One of ref or name must be present, but not both |
|
2077 */ |
|
2078 if (ref == NULL) { |
|
2079 xmlSchemaPErr(ctxt, node, |
|
2080 XML_SCHEMAP_ATTR_NONAME_NOREF, |
|
2081 "Attribute declaration has no \"name\" or \"ref\"\n", |
|
2082 NULL, NULL); |
|
2083 return (NULL); |
|
2084 } |
|
2085 hasRefType = 1; |
|
2086 snprintf(buf, 99, "anonattr %d", ctxt->counter++ + 1); |
|
2087 name = (const xmlChar *) buf; |
|
2088 ret = xmlSchemaAddAttribute(ctxt, schema, name, NULL); |
|
2089 if (!topLevel) { |
|
2090 /* 3.2.3 : 3.2 |
|
2091 * If ref is present, then all of <simpleType>, |
|
2092 * form and type must be absent. |
|
2093 */ |
|
2094 if (xmlSchemaGetProp(ctxt, node, "form") != NULL) { |
|
2095 xmlSchemaPErr(ctxt, node, |
|
2096 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2097 "Attribute declaration %s has \"ref\", thus " |
|
2098 "\"form\" must be absent\n", name, NULL); |
|
2099 } |
|
2100 if (xmlSchemaGetProp(ctxt, node, "type") != NULL) { |
|
2101 xmlSchemaPErr(ctxt, node, |
|
2102 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2103 "Attribute declaration %s has \"ref\", thus " |
|
2104 "\"type\" must be absent\n", name, NULL); |
|
2105 } |
|
2106 } |
|
2107 } else { |
|
2108 const xmlChar *ns = NULL; |
|
2109 /* 3.2.3 : 3.1 |
|
2110 * One of ref or name must be present, but not both |
|
2111 */ |
|
2112 if ((!topLevel) && (xmlSchemaGetProp(ctxt, node, "ref") != NULL)) { |
|
2113 xmlSchemaPErr(ctxt, node, |
|
2114 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2115 "Attribute declaration has both, \"name\" and " |
|
2116 "\"ref\"\n", NULL, NULL); |
|
2117 } |
|
2118 |
|
2119 /* local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ |
|
2120 /* Evaluate the target namespace */ |
|
2121 if (schema->targetNamespace != NULL) { |
|
2122 if (topLevel) { |
|
2123 ns = schema->targetNamespace; |
|
2124 } else if (xmlSchemaGetProp(ctxt, node, "form") != NULL) { |
|
2125 if (xmlStrEqual( xmlSchemaGetProp(ctxt, node, "form"), |
|
2126 BAD_CAST "qualified")) { |
|
2127 ns = schema->targetNamespace; |
|
2128 } |
|
2129 } else if (schema->flags & XML_SCHEMAS_QUALIF_ATTR) { |
|
2130 ns = schema->targetNamespace; |
|
2131 } |
|
2132 } |
|
2133 ret = xmlSchemaAddAttribute(ctxt, schema, name, ns); |
|
2134 |
|
2135 /* 3.2.6 Schema Component Constraint: xmlns Not Allowed */ |
|
2136 if (xmlStrEqual(name, BAD_CAST "xmlns")) { |
|
2137 xmlSchemaPErr(ctxt, node, |
|
2138 XML_SCHEMAP_INVALID_ATTR_NAME, |
|
2139 "The name of an attribute declaration must not match " |
|
2140 "\"xmlns\".\n", NULL, NULL); |
|
2141 } |
|
2142 |
|
2143 /* 3.2.6 Schema Component Constraint: xsi: Not Allowed */ |
|
2144 if (xmlStrEqual(ret->targetNamespace, xmlSchemaInstanceNs)) { |
|
2145 xmlSchemaPErr(ctxt, node, |
|
2146 XML_SCHEMAP_INVALID_ATTR_NAME, |
|
2147 "The target namespace of an attribute declaration, " |
|
2148 "must not match \"http://www.w3.org/2001/" |
|
2149 "XMLSchema-instance\"", NULL, NULL); |
|
2150 } |
|
2151 } |
|
2152 if (ret == NULL) { |
|
2153 return (NULL); |
|
2154 } |
|
2155 ret->type = XML_SCHEMA_TYPE_ATTRIBUTE; |
|
2156 |
|
2157 /* Handle the "use" attribute. */ |
|
2158 attrVal = xmlSchemaGetProp(ctxt, node, "use"); |
|
2159 if (attrVal != NULL) { |
|
2160 if (xmlStrEqual(attrVal, BAD_CAST "optional")) |
|
2161 ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL; |
|
2162 else if (xmlStrEqual(attrVal, BAD_CAST "prohibited")) |
|
2163 ret->occurs = XML_SCHEMAS_ATTR_USE_PROHIBITED; |
|
2164 else if (xmlStrEqual(attrVal, BAD_CAST "required")) |
|
2165 ret->occurs = XML_SCHEMAS_ATTR_USE_REQUIRED; |
|
2166 else |
|
2167 xmlSchemaPErr(ctxt, node, |
|
2168 XML_SCHEMAP_INVALID_ATTR_USE, |
|
2169 "Attribute declaration %s has an invalid " |
|
2170 "value for \"use\"\n", name, NULL); |
|
2171 } else |
|
2172 ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL; |
|
2173 |
|
2174 |
|
2175 if (xmlSchemaGetProp(ctxt, node, "default") != NULL) { |
|
2176 /* 3.2.3 : 1 |
|
2177 * default and fixed must not both be present. |
|
2178 */ |
|
2179 if (xmlSchemaGetProp(ctxt, node, "fixed") != NULL) { |
|
2180 xmlSchemaPErr(ctxt, node, |
|
2181 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2182 "Attribute declaration has both, \"default\" " |
|
2183 "and \"fixed\"\n", NULL, NULL); |
|
2184 } |
|
2185 /* 3.2.3 : 2 |
|
2186 * If default and use are both present, use must have |
|
2187 * the actual value optional. |
|
2188 */ |
|
2189 if (ret->occurs != XML_SCHEMAS_ATTR_USE_OPTIONAL) { |
|
2190 xmlSchemaPErr(ctxt, node, |
|
2191 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2192 "Attribute declaration has \"default\" but " |
|
2193 "\"use\" is not \"optional\"\n", NULL, NULL); |
|
2194 } |
|
2195 } |
|
2196 |
|
2197 ret->ref = ref; |
|
2198 ret->refNs = refNs; |
|
2199 /* |
|
2200 * The setting of XML_SCHEMAS_ATTR_NSDEFAULT is not needed anymore, |
|
2201 * since the target namespace was already evaluated and took |
|
2202 * attributeFormDefault into account. |
|
2203 */ |
|
2204 /* |
|
2205 if ((ret->targetNamespace != NULL) && |
|
2206 ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) && |
|
2207 (xmlStrEqual(ret->targetNamespace, schema->targetNamespace))) |
|
2208 ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT; |
|
2209 */ |
|
2210 ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs)); |
|
2211 if (ret->typeName != NULL) |
|
2212 hasRefType = 1; |
|
2213 ret->node = node; |
|
2214 child = node->children; |
|
2215 if (IS_SCHEMA(child, "annotation")) { |
|
2216 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2217 child = child->next; |
|
2218 } |
|
2219 if (IS_SCHEMA(child, "simpleType")) { |
|
2220 if (hasRefType) { |
|
2221 /* 3.2.3 : 4 |
|
2222 * type and <simpleType> must not both be present. |
|
2223 * |
|
2224 * TODO: XML_SCHEMAP_INVALID_ATTR_COMBINATION seems not to be |
|
2225 * a proper error type here. |
|
2226 */ |
|
2227 xmlSchemaPErr2(ctxt, node, child, |
|
2228 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2229 "Attribute declaration %s has both (\"ref\" or " |
|
2230 "\"type\") and <simpleType>\n", name, NULL); |
|
2231 } else |
|
2232 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); |
|
2233 child = child->next; |
|
2234 } |
|
2235 if (child != NULL) { |
|
2236 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD, |
|
2237 "attribute %s has unexpected content\n", name, |
|
2238 NULL); |
|
2239 } |
|
2240 |
|
2241 return (ret); |
|
2242 } |
|
2243 |
|
2244 /** |
|
2245 * xmlSchemaParseAttributeGroup: |
|
2246 * @ctxt: a schema validation context |
|
2247 * @schema: the schema being built |
|
2248 * @node: a subtree containing XML Schema informations |
|
2249 * |
|
2250 * parse a XML schema Attribute Group declaration |
|
2251 * *WARNING* this interface is highly subject to change |
|
2252 * |
|
2253 * Returns the attribute group or NULL in case of error. |
|
2254 */ |
|
2255 static xmlSchemaAttributeGroupPtr |
|
2256 xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
|
2257 xmlSchemaPtr schema, xmlNodePtr node) |
|
2258 { |
|
2259 const xmlChar *name, *refNs = NULL, *ref = NULL; |
|
2260 xmlSchemaAttributeGroupPtr ret; |
|
2261 xmlSchemaAttributePtr last = NULL, attr; |
|
2262 xmlNodePtr child = NULL; |
|
2263 const xmlChar *oldcontainer; |
|
2264 char buf[100]; |
|
2265 |
|
2266 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2267 return (NULL); |
|
2268 oldcontainer = ctxt->container; |
|
2269 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
2270 if (name == NULL) { |
|
2271 |
|
2272 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
|
2273 if (ref == NULL) { |
|
2274 xmlSchemaPErr2(ctxt, node, child, |
|
2275 XML_SCHEMAP_ATTRGRP_NONAME_NOREF, |
|
2276 "AttributeGroup has no name nor ref\n", NULL, |
|
2277 NULL); |
|
2278 return (NULL); |
|
2279 } |
|
2280 snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1); |
|
2281 name = (const xmlChar *) buf; |
|
2282 if (name == NULL) { |
|
2283 xmlSchemaPErrMemory(ctxt, "creating attribute group", node); |
|
2284 return (NULL); |
|
2285 } |
|
2286 } |
|
2287 ret = xmlSchemaAddAttributeGroup(ctxt, schema, name); |
|
2288 if (ret == NULL) { |
|
2289 return (NULL); |
|
2290 } |
|
2291 ret->ref = ref; |
|
2292 ret->refNs = refNs; |
|
2293 ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP; |
|
2294 ret->node = node; |
|
2295 child = node->children; |
|
2296 ctxt->container = name; |
|
2297 if (IS_SCHEMA(child, "annotation")) { |
|
2298 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2299 child = child->next; |
|
2300 } |
|
2301 while ((IS_SCHEMA(child, "attribute")) || |
|
2302 (IS_SCHEMA(child, "attributeGroup"))) { |
|
2303 attr = NULL; |
|
2304 if (IS_SCHEMA(child, "attribute")) { |
|
2305 attr = xmlSchemaParseAttribute(ctxt, schema, child, 0); |
|
2306 } else if (IS_SCHEMA(child, "attributeGroup")) { |
|
2307 attr = (xmlSchemaAttributePtr) |
|
2308 xmlSchemaParseAttributeGroup(ctxt, schema, child); |
|
2309 } |
|
2310 if (attr != NULL) { |
|
2311 if (last == NULL) { |
|
2312 ret->attributes = attr; |
|
2313 last = attr; |
|
2314 } else { |
|
2315 last->next = attr; |
|
2316 last = attr; |
|
2317 } |
|
2318 } |
|
2319 child = child->next; |
|
2320 } |
|
2321 if (IS_SCHEMA(child, "anyAttribute")) { |
|
2322 TODO |
|
2323 child = child->next; |
|
2324 } |
|
2325 if (child != NULL) { |
|
2326 xmlSchemaPErr2(ctxt, node, child, |
|
2327 XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, |
|
2328 "attribute group %s has unexpected content\n", name, |
|
2329 NULL); |
|
2330 } |
|
2331 ctxt->container = oldcontainer; |
|
2332 return (ret); |
|
2333 } |
|
2334 |
|
2335 /** |
|
2336 * xmlSchemaParseElement: |
|
2337 * @ctxt: a schema validation context |
|
2338 * @schema: the schema being built |
|
2339 * @node: a subtree containing XML Schema informations |
|
2340 * |
|
2341 * parse a XML schema Element declaration |
|
2342 * *WARNING* this interface is highly subject to change |
|
2343 * |
|
2344 * Returns the parsed element declaration. |
|
2345 */ |
|
2346 static xmlSchemaElementPtr |
|
2347 xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2348 xmlNodePtr node, int toplevel) |
|
2349 { |
|
2350 const xmlChar *name, *fixed; |
|
2351 const xmlChar *refNs = NULL, *ref = NULL; |
|
2352 xmlSchemaElementPtr ret; |
|
2353 xmlNodePtr child = NULL; |
|
2354 const xmlChar *oldcontainer; |
|
2355 char buf[100]; |
|
2356 xmlAttrPtr attr; |
|
2357 |
|
2358 /* 3.3.3 Constraints on XML Representations of Element Declarations */ |
|
2359 /* TODO: Complete implementation of 3.3.6 */ |
|
2360 |
|
2361 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2362 return (NULL); |
|
2363 oldcontainer = ctxt->container; |
|
2364 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
2365 if (name == NULL) { |
|
2366 |
|
2367 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
|
2368 /* 3.3.3 : 2.1 |
|
2369 * One of ref or name must be present, but not both |
|
2370 */ |
|
2371 if (ref == NULL) { |
|
2372 xmlSchemaPErr(ctxt, node, |
|
2373 XML_SCHEMAP_ELEM_NONAME_NOREF, |
|
2374 "Element has no name nor ref\n", NULL, NULL); |
|
2375 return (NULL); |
|
2376 } |
|
2377 snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1); |
|
2378 name = (const xmlChar *) buf; |
|
2379 ret = xmlSchemaAddElement(ctxt, schema, name, NULL); |
|
2380 } else { |
|
2381 const xmlChar *ns = NULL; |
|
2382 |
|
2383 /* Evaluate the target namespace */ |
|
2384 if (schema->targetNamespace != NULL) { |
|
2385 if (toplevel) { |
|
2386 ns = schema->targetNamespace; |
|
2387 } else if (xmlSchemaGetProp(ctxt, node, "form") != NULL) { |
|
2388 if (xmlStrEqual( xmlSchemaGetProp(ctxt, node, "form"), |
|
2389 BAD_CAST "qualified")) { |
|
2390 ns = schema->targetNamespace; |
|
2391 } |
|
2392 } else if (schema->flags & XML_SCHEMAS_QUALIF_ATTR) { |
|
2393 ns = schema->targetNamespace; |
|
2394 } |
|
2395 } |
|
2396 /*local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ |
|
2397 ret = xmlSchemaAddElement(ctxt, schema, name, ns); |
|
2398 /* 3.3.3 : 2.1 |
|
2399 * One of ref or name must be present, but not both |
|
2400 */ |
|
2401 if ((!toplevel) && (xmlSchemaGetProp(ctxt, node, "ref") != NULL)) { |
|
2402 xmlSchemaPErr(ctxt, node, |
|
2403 XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2404 "Element declaration has both, \"name\" and " |
|
2405 "\"ref\"\n", NULL, NULL); |
|
2406 } |
|
2407 } |
|
2408 if (ret != NULL) |
|
2409 ret->node = node; |
|
2410 if (ret == NULL) { |
|
2411 return (NULL); |
|
2412 } |
|
2413 ret->type = XML_SCHEMA_TYPE_ELEMENT; |
|
2414 ret->ref = ref; |
|
2415 ret->refNs = refNs; |
|
2416 if (ref != NULL) |
|
2417 ret->flags |= XML_SCHEMAS_ELEM_REF; |
|
2418 |
|
2419 /* 3.3.3 : 2.2 */ |
|
2420 if ((!toplevel) && (ref != NULL)) { |
|
2421 attr = node->properties; |
|
2422 while (attr != NULL) { |
|
2423 if ((attr->ns == NULL) && |
|
2424 (!xmlStrEqual(attr->name, BAD_CAST "ref")) && |
|
2425 (!xmlStrEqual(attr->name, BAD_CAST "id")) && |
|
2426 (!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) && |
|
2427 (!xmlStrEqual(attr->name, BAD_CAST "minOccurs"))) { |
|
2428 |
|
2429 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2430 "Element declaration %s: only minOccurs, maxOccurs " |
|
2431 "and id are allowed in addition to ref\n", |
|
2432 ret->name, NULL); |
|
2433 } |
|
2434 attr = attr->next; |
|
2435 } |
|
2436 } |
|
2437 |
|
2438 if (toplevel) |
|
2439 ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL; |
|
2440 if (xmlGetBooleanProp(ctxt, node, "nillable", 0)) |
|
2441 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; |
|
2442 if (xmlGetBooleanProp(ctxt, node, "abstract", 0)) |
|
2443 ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; |
|
2444 ctxt->container = name; |
|
2445 |
|
2446 ret->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2447 ret->namedType = |
|
2448 xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs)); |
|
2449 ret->substGroup = |
|
2450 xmlGetQNameProp(ctxt, node, "substitutionGroup", |
|
2451 &(ret->substGroupNs)); |
|
2452 if ((ret->substGroup != NULL) && (!toplevel)) { |
|
2453 /* 3.3.6 : 3 */ |
|
2454 /* |
|
2455 * TODO: This seems to be redundant, since the schema for schemas |
|
2456 * already prohibits the use of the "substitutionGroup" attribute |
|
2457 * in local element declarations. |
|
2458 */ |
|
2459 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_ATTR_COMBINATION, |
|
2460 "Element declaration %s: substitutionGroup is allowed " |
|
2461 "on top-level declarations only\n", ret->name, NULL); |
|
2462 |
|
2463 } |
|
2464 fixed = xmlSchemaGetProp(ctxt, node, "fixed"); |
|
2465 ret->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
2466 ret->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
2467 |
|
2468 ret->value = xmlSchemaGetProp(ctxt, node, "default"); |
|
2469 if ((ret->value != NULL) && (fixed != NULL)) { |
|
2470 /* 3.3.3 : 1 |
|
2471 * default and fixed must not both be present. |
|
2472 */ |
|
2473 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED, |
|
2474 "Element %s has both default and fixed\n", |
|
2475 ret->name, NULL); |
|
2476 } else if (fixed != NULL) { |
|
2477 ret->flags |= XML_SCHEMAS_ELEM_FIXED; |
|
2478 ret->value = fixed; |
|
2479 } |
|
2480 |
|
2481 child = node->children; |
|
2482 if (IS_SCHEMA(child, "annotation")) { |
|
2483 ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2484 child = child->next; |
|
2485 } |
|
2486 if (ref != NULL) { |
|
2487 /* 3.3.3 (2.2) */ |
|
2488 while (child != NULL) { |
|
2489 if ((IS_SCHEMA(child, "complexType")) || |
|
2490 (IS_SCHEMA(child, "simpleType")) || |
|
2491 (IS_SCHEMA(child, "unique")) || |
|
2492 (IS_SCHEMA(child, "key")) || |
|
2493 (IS_SCHEMA(child, "keyref"))) { |
|
2494 |
|
2495 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_REF_AND_CONTENT, |
|
2496 "Element declaration %s: only annotation is " |
|
2497 "allowed as content in addition to ref\n", |
|
2498 ret->name, NULL); |
|
2499 } else { |
|
2500 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD, |
|
2501 "element %s has unexpected content\n", name, NULL); |
|
2502 } |
|
2503 child = child->next; |
|
2504 } |
|
2505 } else { |
|
2506 if (IS_SCHEMA(child, "complexType")) { |
|
2507 /* 3.3.3 : 3 |
|
2508 * type and either <simpleType> or <complexType> are mutually |
|
2509 * exclusive |
|
2510 */ |
|
2511 if (ret->namedType != NULL) { |
|
2512 xmlSchemaPErr2(ctxt, node, child, |
|
2513 XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION, |
|
2514 "Element declaration %s has both \"type\" " |
|
2515 "and a local complex type\n", |
|
2516 ret->name, NULL); |
|
2517 } else |
|
2518 ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child); |
|
2519 child = child->next; |
|
2520 } else if (IS_SCHEMA(child, "simpleType")) { |
|
2521 /* 3.3.3 : 3 |
|
2522 * type and either <simpleType> or <complexType> are |
|
2523 * mutually exclusive |
|
2524 */ |
|
2525 if (ret->namedType != NULL) { |
|
2526 xmlSchemaPErr2(ctxt, node, child, |
|
2527 XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION, |
|
2528 "Element declaration %s has both \"type\" " |
|
2529 "and a local simple type\n", |
|
2530 ret->name, NULL); |
|
2531 } else |
|
2532 ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); |
|
2533 child = child->next; |
|
2534 } |
|
2535 |
|
2536 while ((IS_SCHEMA(child, "unique")) || |
|
2537 (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) { |
|
2538 TODO child = child->next; |
|
2539 } |
|
2540 if (child != NULL) { |
|
2541 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD, |
|
2542 "element %s has unexpected content\n", name, NULL); |
|
2543 } |
|
2544 } |
|
2545 |
|
2546 ctxt->container = oldcontainer; |
|
2547 return (ret); |
|
2548 } |
|
2549 |
|
2550 /** |
|
2551 * xmlSchemaParseUnion: |
|
2552 * @ctxt: a schema validation context |
|
2553 * @schema: the schema being built |
|
2554 * @node: a subtree containing XML Schema informations |
|
2555 * |
|
2556 * parse a XML schema Union definition |
|
2557 * *WARNING* this interface is highly subject to change |
|
2558 * |
|
2559 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2560 * 1 in case of success. |
|
2561 */ |
|
2562 static xmlSchemaTypePtr |
|
2563 xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2564 xmlNodePtr node) |
|
2565 { |
|
2566 xmlSchemaTypePtr type, subtype, last = NULL; |
|
2567 xmlNodePtr child = NULL; |
|
2568 xmlChar name[30]; |
|
2569 |
|
2570 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2571 return (NULL); |
|
2572 |
|
2573 |
|
2574 snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1); |
|
2575 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
2576 if (type == NULL) |
|
2577 return (NULL); |
|
2578 type->node = node; |
|
2579 type->type = XML_SCHEMA_TYPE_UNION; |
|
2580 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2581 type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes"); |
|
2582 |
|
2583 child = node->children; |
|
2584 if (IS_SCHEMA(child, "annotation")) { |
|
2585 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2586 child = child->next; |
|
2587 } |
|
2588 while (IS_SCHEMA(child, "simpleType")) { |
|
2589 subtype = (xmlSchemaTypePtr) |
|
2590 xmlSchemaParseSimpleType(ctxt, schema, child); |
|
2591 if (subtype != NULL) { |
|
2592 if (last == NULL) { |
|
2593 type->subtypes = subtype; |
|
2594 last = subtype; |
|
2595 } else { |
|
2596 last->next = subtype; |
|
2597 last = subtype; |
|
2598 } |
|
2599 last->next = NULL; |
|
2600 } |
|
2601 child = child->next; |
|
2602 } |
|
2603 if (child != NULL) { |
|
2604 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD, |
|
2605 "Union %s has unexpected content\n", type->name, |
|
2606 NULL); |
|
2607 } |
|
2608 return (type); |
|
2609 } |
|
2610 |
|
2611 /** |
|
2612 * xmlSchemaParseList: |
|
2613 * @ctxt: a schema validation context |
|
2614 * @schema: the schema being built |
|
2615 * @node: a subtree containing XML Schema informations |
|
2616 * |
|
2617 * parse a XML schema List definition |
|
2618 * *WARNING* this interface is highly subject to change |
|
2619 * |
|
2620 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2621 * 1 in case of success. |
|
2622 */ |
|
2623 static xmlSchemaTypePtr |
|
2624 xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2625 xmlNodePtr node) |
|
2626 { |
|
2627 xmlSchemaTypePtr type, subtype; |
|
2628 xmlNodePtr child = NULL; |
|
2629 xmlChar name[30]; |
|
2630 |
|
2631 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2632 return (NULL); |
|
2633 |
|
2634 snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1); |
|
2635 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
2636 if (type == NULL) |
|
2637 return (NULL); |
|
2638 type->node = node; |
|
2639 type->type = XML_SCHEMA_TYPE_LIST; |
|
2640 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2641 type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs)); |
|
2642 |
|
2643 child = node->children; |
|
2644 if (IS_SCHEMA(child, "annotation")) { |
|
2645 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2646 child = child->next; |
|
2647 } |
|
2648 |
|
2649 subtype = NULL; |
|
2650 if (IS_SCHEMA(child, "simpleType")) { |
|
2651 subtype = (xmlSchemaTypePtr) |
|
2652 xmlSchemaParseSimpleType(ctxt, schema, child); |
|
2653 child = child->next; |
|
2654 type->subtypes = subtype; |
|
2655 } |
|
2656 if (child != NULL) { |
|
2657 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD, |
|
2658 "List %s has unexpected content\n", type->name, |
|
2659 NULL); |
|
2660 } |
|
2661 return (type); |
|
2662 } |
|
2663 |
|
2664 /** |
|
2665 * xmlSchemaParseSimpleType: |
|
2666 * @ctxt: a schema validation context |
|
2667 * @schema: the schema being built |
|
2668 * @node: a subtree containing XML Schema informations |
|
2669 * |
|
2670 * parse a XML schema Simple Type definition |
|
2671 * *WARNING* this interface is highly subject to change |
|
2672 * |
|
2673 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2674 * 1 in case of success. |
|
2675 */ |
|
2676 static xmlSchemaTypePtr |
|
2677 xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2678 xmlNodePtr node) |
|
2679 { |
|
2680 xmlSchemaTypePtr type, subtype; |
|
2681 xmlNodePtr child = NULL; |
|
2682 const xmlChar *name; |
|
2683 |
|
2684 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2685 return (NULL); |
|
2686 |
|
2687 |
|
2688 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
2689 if (name == NULL) { |
|
2690 char buf[100]; |
|
2691 |
|
2692 snprintf(buf, 99, "simpleType %d", ctxt->counter++ + 1); |
|
2693 type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL); |
|
2694 } else { |
|
2695 /* local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ |
|
2696 type = xmlSchemaAddType(ctxt, schema, name, schema->targetNamespace); |
|
2697 } |
|
2698 if (type == NULL) |
|
2699 return (NULL); |
|
2700 type->node = node; |
|
2701 type->type = XML_SCHEMA_TYPE_SIMPLE; |
|
2702 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2703 |
|
2704 child = node->children; |
|
2705 if (IS_SCHEMA(child, "annotation")) { |
|
2706 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2707 child = child->next; |
|
2708 } |
|
2709 subtype = NULL; |
|
2710 if (IS_SCHEMA(child, "restriction")) { |
|
2711 subtype = (xmlSchemaTypePtr) |
|
2712 xmlSchemaParseRestriction(ctxt, schema, child, 1); |
|
2713 child = child->next; |
|
2714 } else if (IS_SCHEMA(child, "list")) { |
|
2715 subtype = (xmlSchemaTypePtr) |
|
2716 xmlSchemaParseList(ctxt, schema, child); |
|
2717 child = child->next; |
|
2718 } else if (IS_SCHEMA(child, "union")) { |
|
2719 subtype = (xmlSchemaTypePtr) |
|
2720 xmlSchemaParseUnion(ctxt, schema, child); |
|
2721 child = child->next; |
|
2722 } |
|
2723 type->subtypes = subtype; |
|
2724 if (subtype == NULL) { |
|
2725 xmlSchemaPErr2(ctxt, node, child, |
|
2726 XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD, |
|
2727 "SimpleType %s does not define a variety\n", |
|
2728 type->name, NULL); |
|
2729 } |
|
2730 if (child != NULL) { |
|
2731 xmlSchemaPErr2(ctxt, node, child, |
|
2732 XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, |
|
2733 "SimpleType %s has unexpected content\n", |
|
2734 type->name, NULL); |
|
2735 } |
|
2736 |
|
2737 return (type); |
|
2738 } |
|
2739 |
|
2740 |
|
2741 /** |
|
2742 * xmlSchemaParseGroup: |
|
2743 * @ctxt: a schema validation context |
|
2744 * @schema: the schema being built |
|
2745 * @node: a subtree containing XML Schema informations |
|
2746 * |
|
2747 * parse a XML schema Group definition |
|
2748 * *WARNING* this interface is highly subject to change |
|
2749 * |
|
2750 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2751 * 1 in case of success. |
|
2752 */ |
|
2753 static xmlSchemaTypePtr |
|
2754 xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2755 xmlNodePtr node) |
|
2756 { |
|
2757 xmlSchemaTypePtr type, subtype; |
|
2758 xmlNodePtr child = NULL; |
|
2759 const xmlChar *name; |
|
2760 const xmlChar *ref = NULL, *refNs = NULL; |
|
2761 char buf[100]; |
|
2762 |
|
2763 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2764 return (NULL); |
|
2765 |
|
2766 |
|
2767 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
2768 if (name == NULL) { |
|
2769 |
|
2770 ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
|
2771 if (ref == NULL) { |
|
2772 xmlSchemaPErr2(ctxt, node, child, |
|
2773 XML_SCHEMAP_GROUP_NONAME_NOREF, |
|
2774 "Group has no name nor ref\n", NULL, NULL); |
|
2775 return (NULL); |
|
2776 } |
|
2777 if (refNs == NULL) |
|
2778 refNs = schema->targetNamespace; |
|
2779 snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1); |
|
2780 name = (const xmlChar *) buf; |
|
2781 } |
|
2782 type = xmlSchemaAddGroup(ctxt, schema, name); |
|
2783 if (type == NULL) |
|
2784 return (NULL); |
|
2785 |
|
2786 type->node = node; |
|
2787 type->type = XML_SCHEMA_TYPE_GROUP; |
|
2788 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2789 type->ref = ref; |
|
2790 type->refNs = refNs; |
|
2791 type->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
2792 type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
2793 |
|
2794 child = node->children; |
|
2795 if (IS_SCHEMA(child, "annotation")) { |
|
2796 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2797 child = child->next; |
|
2798 } |
|
2799 subtype = NULL; |
|
2800 if (IS_SCHEMA(child, "all")) { |
|
2801 subtype = (xmlSchemaTypePtr) |
|
2802 xmlSchemaParseAll(ctxt, schema, child); |
|
2803 child = child->next; |
|
2804 } else if (IS_SCHEMA(child, "choice")) { |
|
2805 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
2806 child = child->next; |
|
2807 } else if (IS_SCHEMA(child, "sequence")) { |
|
2808 subtype = (xmlSchemaTypePtr) |
|
2809 xmlSchemaParseSequence(ctxt, schema, child); |
|
2810 child = child->next; |
|
2811 } |
|
2812 if (subtype != NULL) |
|
2813 type->subtypes = subtype; |
|
2814 if (child != NULL) { |
|
2815 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD, |
|
2816 "Group %s has unexpected content\n", type->name, |
|
2817 NULL); |
|
2818 } |
|
2819 |
|
2820 return (type); |
|
2821 } |
|
2822 |
|
2823 /** |
|
2824 * xmlSchemaParseAll: |
|
2825 * @ctxt: a schema validation context |
|
2826 * @schema: the schema being built |
|
2827 * @node: a subtree containing XML Schema informations |
|
2828 * |
|
2829 * parse a XML schema All definition |
|
2830 * *WARNING* this interface is highly subject to change |
|
2831 * |
|
2832 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2833 * 1 in case of success. |
|
2834 */ |
|
2835 static xmlSchemaTypePtr |
|
2836 xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2837 xmlNodePtr node) |
|
2838 { |
|
2839 xmlSchemaTypePtr type, subtype, last = NULL; |
|
2840 xmlNodePtr child = NULL; |
|
2841 xmlChar name[30]; |
|
2842 |
|
2843 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2844 return (NULL); |
|
2845 |
|
2846 |
|
2847 snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1); |
|
2848 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
2849 if (type == NULL) |
|
2850 return (NULL); |
|
2851 type->node = node; |
|
2852 type->type = XML_SCHEMA_TYPE_ALL; |
|
2853 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
2854 type->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
2855 if (type->minOccurs > 1) |
|
2856 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS, |
|
2857 "invalid value for minOccurs (must be 0 or 1)\n", NULL, NULL); |
|
2858 type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
2859 if (type->maxOccurs > 1) |
|
2860 xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS, |
|
2861 "invalid value for maxOccurs (must be 0 or 1)\n", NULL, NULL); |
|
2862 |
|
2863 child = node->children; |
|
2864 if (IS_SCHEMA(child, "annotation")) { |
|
2865 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
2866 child = child->next; |
|
2867 } |
|
2868 while (IS_SCHEMA(child, "element")) { |
|
2869 subtype = (xmlSchemaTypePtr) |
|
2870 xmlSchemaParseElement(ctxt, schema, child, 0); |
|
2871 if (subtype != NULL) { |
|
2872 if (subtype->minOccurs > 1) |
|
2873 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MINOCCURS, |
|
2874 "invalid value for minOccurs (must be 0 or 1)\n", |
|
2875 NULL, NULL); |
|
2876 if (subtype->maxOccurs > 1) |
|
2877 xmlSchemaPErr(ctxt, child, XML_SCHEMAP_INVALID_MAXOCCURS, |
|
2878 "invalid value for maxOccurs (must be 0 or 1)\n", |
|
2879 NULL, NULL); |
|
2880 if (last == NULL) { |
|
2881 type->subtypes = subtype; |
|
2882 last = subtype; |
|
2883 } else { |
|
2884 last->next = subtype; |
|
2885 last = subtype; |
|
2886 } |
|
2887 last->next = NULL; |
|
2888 } |
|
2889 child = child->next; |
|
2890 } |
|
2891 if (child != NULL) { |
|
2892 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD, |
|
2893 "All %s has unexpected content\n", type->name, |
|
2894 NULL); |
|
2895 } |
|
2896 |
|
2897 return (type); |
|
2898 } |
|
2899 |
|
2900 /** |
|
2901 * xmlSchemaImportSchema |
|
2902 * |
|
2903 * @ctxt: a schema validation context |
|
2904 * @schemaLocation: an URI defining where to find the imported schema |
|
2905 * |
|
2906 * import a XML schema |
|
2907 * *WARNING* this interface is highly subject to change |
|
2908 * |
|
2909 * Returns -1 in case of error and 1 in case of success. |
|
2910 */ |
|
2911 static xmlSchemaImportPtr |
|
2912 xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt, |
|
2913 const xmlChar *schemaLocation) |
|
2914 { |
|
2915 xmlSchemaImportPtr import; |
|
2916 xmlSchemaParserCtxtPtr newctxt; |
|
2917 |
|
2918 newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); |
|
2919 if (newctxt == NULL) { |
|
2920 xmlSchemaPErrMemory(ctxt, "allocating schama parser context", |
|
2921 NULL); |
|
2922 return (NULL); |
|
2923 } |
|
2924 memset(newctxt, 0, sizeof(xmlSchemaParserCtxt)); |
|
2925 /* Keep the same dictionnary for parsing, really */ |
|
2926 xmlDictReference(ctxt->dict); |
|
2927 newctxt->dict = ctxt->dict; |
|
2928 newctxt->includes = 0; |
|
2929 newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1); |
|
2930 |
|
2931 xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning, |
|
2932 ctxt->userData); |
|
2933 |
|
2934 import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport)); |
|
2935 if (import == NULL) { |
|
2936 xmlSchemaPErrMemory(NULL, "allocating imported schema", |
|
2937 NULL); |
|
2938 xmlSchemaFreeParserCtxt(newctxt); |
|
2939 return (NULL); |
|
2940 } |
|
2941 |
|
2942 memset(import, 0, sizeof(xmlSchemaImport)); |
|
2943 import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1); |
|
2944 import->schema = xmlSchemaParse(newctxt); |
|
2945 |
|
2946 if (import->schema == NULL) { |
|
2947 /* FIXME use another error enum here ? */ |
|
2948 xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL, |
|
2949 "failed to import schema at location %s\n", |
|
2950 schemaLocation, NULL); |
|
2951 |
|
2952 xmlSchemaFreeParserCtxt(newctxt); |
|
2953 if (import->schemaLocation != NULL) |
|
2954 xmlFree((xmlChar *)import->schemaLocation); |
|
2955 xmlFree(import); |
|
2956 return NULL; |
|
2957 } |
|
2958 |
|
2959 xmlSchemaFreeParserCtxt(newctxt); |
|
2960 return import; |
|
2961 } |
|
2962 |
|
2963 |
|
2964 /** |
|
2965 * xmlSchemaParseImport: |
|
2966 * @ctxt: a schema validation context |
|
2967 * @schema: the schema being built |
|
2968 * @node: a subtree containing XML Schema informations |
|
2969 * |
|
2970 * parse a XML schema Import definition |
|
2971 * *WARNING* this interface is highly subject to change |
|
2972 * |
|
2973 * Returns -1 in case of error, 0 if the declaration is improper and |
|
2974 * 1 in case of success. |
|
2975 */ |
|
2976 static int |
|
2977 xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
2978 xmlNodePtr node) |
|
2979 { |
|
2980 xmlNodePtr child = NULL; |
|
2981 xmlSchemaImportPtr import = NULL; |
|
2982 const xmlChar *namespace; |
|
2983 const xmlChar *schemaLocation; |
|
2984 const xmlChar *previous; |
|
2985 xmlURIPtr check; |
|
2986 |
|
2987 |
|
2988 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
2989 return (-1); |
|
2990 |
|
2991 namespace = xmlSchemaGetProp(ctxt, node, "namespace"); |
|
2992 if (namespace != NULL) { |
|
2993 check = xmlParseURI((const char *) namespace); |
|
2994 if (check == NULL) { |
|
2995 xmlSchemaPErr2(ctxt, node, child, |
|
2996 XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI, |
|
2997 "Import namespace attribute is not an URI: %s\n", |
|
2998 namespace, NULL); |
|
2999 return (-1); |
|
3000 } else { |
|
3001 xmlFreeURI(check); |
|
3002 } |
|
3003 } |
|
3004 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation"); |
|
3005 if (schemaLocation != NULL) { |
|
3006 xmlChar *base = NULL; |
|
3007 xmlChar *URI = NULL; |
|
3008 check = xmlParseURI((const char *) schemaLocation); |
|
3009 if (check == NULL) { |
|
3010 xmlSchemaPErr2(ctxt, node, child, |
|
3011 XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI, |
|
3012 "Import schemaLocation attribute is not an URI: %s\n", |
|
3013 schemaLocation, NULL); |
|
3014 return (-1); |
|
3015 } else { |
|
3016 xmlFreeURI(check); |
|
3017 } |
|
3018 base = xmlNodeGetBase(node->doc, node); |
|
3019 if (base == NULL) { |
|
3020 URI = xmlBuildURI(schemaLocation, node->doc->URL); |
|
3021 } else { |
|
3022 URI = xmlBuildURI(schemaLocation, base); |
|
3023 xmlFree(base); |
|
3024 } |
|
3025 if (URI != NULL) { |
|
3026 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1); |
|
3027 xmlFree(URI); |
|
3028 } |
|
3029 } |
|
3030 if (schema->schemasImports == NULL) { |
|
3031 schema->schemasImports = xmlHashCreate(10); |
|
3032 if (schema->schemasImports == NULL) { |
|
3033 xmlSchemaPErr2(ctxt, node, child, |
|
3034 XML_SCHEMAP_FAILED_BUILD_IMPORT, |
|
3035 "Internal: failed to build import table\n", |
|
3036 NULL, NULL); |
|
3037 return (-1); |
|
3038 } |
|
3039 } |
|
3040 if (namespace == NULL) { |
|
3041 import = xmlHashLookup(schema->schemasImports, |
|
3042 XML_SCHEMAS_DEFAULT_NAMESPACE); |
|
3043 if (import != NULL) |
|
3044 previous = import->schemaLocation; |
|
3045 else |
|
3046 previous = NULL; |
|
3047 |
|
3048 if (schemaLocation != NULL) { |
|
3049 if (previous != NULL) { |
|
3050 if (!xmlStrEqual(schemaLocation, previous)) { |
|
3051 xmlSchemaPErr2(ctxt, node, child, |
|
3052 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, |
|
3053 "Redefining import for default namespace " |
|
3054 "with a different URI: %s\n", |
|
3055 schemaLocation, NULL); |
|
3056 } |
|
3057 } else { |
|
3058 import = xmlSchemaImportSchema(ctxt, schemaLocation); |
|
3059 if (import == NULL) { |
|
3060 return (-1); |
|
3061 } |
|
3062 xmlHashAddEntry(schema->schemasImports, |
|
3063 XML_SCHEMAS_DEFAULT_NAMESPACE, |
|
3064 import); |
|
3065 } |
|
3066 } |
|
3067 } else { |
|
3068 import = xmlHashLookup(schema->schemasImports, namespace); |
|
3069 if (import != NULL) |
|
3070 previous = import->schemaLocation; |
|
3071 else |
|
3072 previous = NULL; |
|
3073 |
|
3074 if (schemaLocation != NULL) { |
|
3075 if (previous != NULL) { |
|
3076 if (!xmlStrEqual(schemaLocation, previous)) { |
|
3077 xmlSchemaPErr2(ctxt, node, child, |
|
3078 XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, |
|
3079 "Redefining import for namespace %s with " |
|
3080 "a different URI: %s\n", |
|
3081 namespace, schemaLocation); |
|
3082 } |
|
3083 } else { |
|
3084 import = xmlSchemaImportSchema(ctxt, schemaLocation); |
|
3085 if (import == NULL) { |
|
3086 return (-1); |
|
3087 } |
|
3088 xmlHashAddEntry(schema->schemasImports, |
|
3089 namespace, import); |
|
3090 } |
|
3091 } |
|
3092 } |
|
3093 |
|
3094 child = node->children; |
|
3095 while (IS_SCHEMA(child, "annotation")) { |
|
3096 /* |
|
3097 * the annotations here are simply discarded ... |
|
3098 */ |
|
3099 child = child->next; |
|
3100 } |
|
3101 if (child != NULL) { |
|
3102 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD, |
|
3103 "Import has unexpected content\n", NULL, NULL); |
|
3104 return (-1); |
|
3105 } |
|
3106 return (1); |
|
3107 } |
|
3108 |
|
3109 /** |
|
3110 * xmlSchemaCleanupDoc: |
|
3111 * @ctxt: a schema validation context |
|
3112 * @node: the root of the document. |
|
3113 * |
|
3114 * removes unwanted nodes in a schemas document tree |
|
3115 */ |
|
3116 static void |
|
3117 xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root) |
|
3118 { |
|
3119 xmlNodePtr delete, cur; |
|
3120 |
|
3121 if ((ctxt == NULL) || (root == NULL)) return; |
|
3122 |
|
3123 /* |
|
3124 * Remove all the blank text nodes |
|
3125 */ |
|
3126 delete = NULL; |
|
3127 cur = root; |
|
3128 while (cur != NULL) { |
|
3129 if (delete != NULL) { |
|
3130 xmlUnlinkNode(delete); |
|
3131 xmlFreeNode(delete); |
|
3132 delete = NULL; |
|
3133 } |
|
3134 if (cur->type == XML_TEXT_NODE) { |
|
3135 if (IS_BLANK_NODE(cur)) { |
|
3136 if (xmlNodeGetSpacePreserve(cur) != 1) { |
|
3137 delete = cur; |
|
3138 } |
|
3139 } |
|
3140 } else if ((cur->type != XML_ELEMENT_NODE) && |
|
3141 (cur->type != XML_CDATA_SECTION_NODE)) { |
|
3142 delete = cur; |
|
3143 goto skip_children; |
|
3144 } |
|
3145 |
|
3146 /* |
|
3147 * Skip to next node |
|
3148 */ |
|
3149 if (cur->children != NULL) { |
|
3150 if ((cur->children->type != XML_ENTITY_DECL) && |
|
3151 (cur->children->type != XML_ENTITY_REF_NODE) && |
|
3152 (cur->children->type != XML_ENTITY_NODE)) { |
|
3153 cur = cur->children; |
|
3154 continue; |
|
3155 } |
|
3156 } |
|
3157 skip_children: |
|
3158 if (cur->next != NULL) { |
|
3159 cur = cur->next; |
|
3160 continue; |
|
3161 } |
|
3162 |
|
3163 do { |
|
3164 cur = cur->parent; |
|
3165 if (cur == NULL) |
|
3166 break; |
|
3167 if (cur == root) { |
|
3168 cur = NULL; |
|
3169 break; |
|
3170 } |
|
3171 if (cur->next != NULL) { |
|
3172 cur = cur->next; |
|
3173 break; |
|
3174 } |
|
3175 } while (cur != NULL); |
|
3176 } |
|
3177 if (delete != NULL) { |
|
3178 xmlUnlinkNode(delete); |
|
3179 xmlFreeNode(delete); |
|
3180 delete = NULL; |
|
3181 } |
|
3182 } |
|
3183 |
|
3184 /** |
|
3185 * xmlSchemaParseSchemaTopLevel: |
|
3186 * @ctxt: a schema validation context |
|
3187 * @schema: the schemas |
|
3188 * @nodes: the list of top level nodes |
|
3189 * |
|
3190 * Returns the internal XML Schema structure built from the resource or |
|
3191 * NULL in case of error |
|
3192 */ |
|
3193 static void |
|
3194 xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, |
|
3195 xmlSchemaPtr schema, xmlNodePtr nodes) |
|
3196 { |
|
3197 xmlNodePtr child; |
|
3198 xmlSchemaAnnotPtr annot; |
|
3199 |
|
3200 if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL)) |
|
3201 return; |
|
3202 |
|
3203 child = nodes; |
|
3204 while ((IS_SCHEMA(child, "include")) || |
|
3205 (IS_SCHEMA(child, "import")) || |
|
3206 (IS_SCHEMA(child, "redefine")) || |
|
3207 (IS_SCHEMA(child, "annotation"))) { |
|
3208 if (IS_SCHEMA(child, "annotation")) { |
|
3209 annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3210 if (schema->annot == NULL) |
|
3211 schema->annot = annot; |
|
3212 else |
|
3213 xmlSchemaFreeAnnot(annot); |
|
3214 } else if (IS_SCHEMA(child, "import")) { |
|
3215 xmlSchemaParseImport(ctxt, schema, child); |
|
3216 } else if (IS_SCHEMA(child, "include")) { |
|
3217 ctxt->includes++; |
|
3218 xmlSchemaParseInclude(ctxt, schema, child); |
|
3219 ctxt->includes--; |
|
3220 } else if (IS_SCHEMA(child, "redefine")) { |
|
3221 TODO |
|
3222 } |
|
3223 child = child->next; |
|
3224 } |
|
3225 while (child != NULL) { |
|
3226 if (IS_SCHEMA(child, "complexType")) { |
|
3227 xmlSchemaParseComplexType(ctxt, schema, child); |
|
3228 child = child->next; |
|
3229 } else if (IS_SCHEMA(child, "simpleType")) { |
|
3230 xmlSchemaParseSimpleType(ctxt, schema, child); |
|
3231 child = child->next; |
|
3232 } else if (IS_SCHEMA(child, "element")) { |
|
3233 xmlSchemaParseElement(ctxt, schema, child, 1); |
|
3234 child = child->next; |
|
3235 } else if (IS_SCHEMA(child, "attribute")) { |
|
3236 xmlSchemaParseAttribute(ctxt, schema, child, 1); |
|
3237 child = child->next; |
|
3238 } else if (IS_SCHEMA(child, "attributeGroup")) { |
|
3239 xmlSchemaParseAttributeGroup(ctxt, schema, child); |
|
3240 child = child->next; |
|
3241 } else if (IS_SCHEMA(child, "group")) { |
|
3242 xmlSchemaParseGroup(ctxt, schema, child); |
|
3243 child = child->next; |
|
3244 } else if (IS_SCHEMA(child, "notation")) { |
|
3245 xmlSchemaParseNotation(ctxt, schema, child); |
|
3246 child = child->next; |
|
3247 } else { |
|
3248 xmlSchemaPErr2(ctxt, NULL, child, |
|
3249 XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD, |
|
3250 "Schemas: unexpected element %s here \n", |
|
3251 child->name, NULL); |
|
3252 child = child->next; |
|
3253 } |
|
3254 while (IS_SCHEMA(child, "annotation")) { |
|
3255 annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3256 if (schema->annot == NULL) |
|
3257 schema->annot = annot; |
|
3258 else |
|
3259 xmlSchemaFreeAnnot(annot); |
|
3260 child = child->next; |
|
3261 } |
|
3262 } |
|
3263 } |
|
3264 |
|
3265 /** |
|
3266 * xmlSchemaParseInclude: |
|
3267 * @ctxt: a schema validation context |
|
3268 * @schema: the schema being built |
|
3269 * @node: a subtree containing XML Schema informations |
|
3270 * |
|
3271 * parse a XML schema Include definition |
|
3272 * |
|
3273 * Returns -1 in case of error, 0 if the declaration is improper and |
|
3274 * 1 in case of success. |
|
3275 */ |
|
3276 static int |
|
3277 xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3278 xmlNodePtr node) |
|
3279 { |
|
3280 xmlNodePtr child = NULL; |
|
3281 const xmlChar *schemaLocation; |
|
3282 xmlURIPtr check; |
|
3283 xmlDocPtr doc; |
|
3284 xmlNodePtr root; |
|
3285 xmlSchemaIncludePtr include; |
|
3286 |
|
3287 |
|
3288 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3289 return (-1); |
|
3290 |
|
3291 /* |
|
3292 * Preliminary step, extract the URI-Reference for the include and |
|
3293 * make an URI from the base. |
|
3294 */ |
|
3295 schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation"); |
|
3296 if (schemaLocation != NULL) { |
|
3297 xmlChar *base = NULL; |
|
3298 xmlChar *URI = NULL; |
|
3299 check = xmlParseURI((const char *) schemaLocation); |
|
3300 if (check == NULL) { |
|
3301 xmlSchemaPErr2(ctxt, node, child, |
|
3302 XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI, |
|
3303 "Include schemaLocation attribute is not an URI: %s\n", |
|
3304 schemaLocation, NULL); |
|
3305 return (-1); |
|
3306 } else { |
|
3307 xmlFreeURI(check); |
|
3308 } |
|
3309 base = xmlNodeGetBase(node->doc, node); |
|
3310 if (base == NULL) { |
|
3311 URI = xmlBuildURI(schemaLocation, node->doc->URL); |
|
3312 } else { |
|
3313 URI = xmlBuildURI(schemaLocation, base); |
|
3314 xmlFree(base); |
|
3315 } |
|
3316 if (URI != NULL) { |
|
3317 schemaLocation = xmlDictLookup(ctxt->dict, URI, -1); |
|
3318 xmlFree(URI); |
|
3319 } |
|
3320 } else { |
|
3321 xmlSchemaPErr2(ctxt, node, child, |
|
3322 XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI, |
|
3323 "Include schemaLocation attribute missing\n", |
|
3324 NULL, NULL); |
|
3325 return (-1); |
|
3326 } |
|
3327 |
|
3328 child = node->children; |
|
3329 while (IS_SCHEMA(child, "annotation")) { |
|
3330 /* |
|
3331 * the annotations here are simply discarded ... |
|
3332 */ |
|
3333 child = child->next; |
|
3334 } |
|
3335 if (child != NULL) { |
|
3336 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD, |
|
3337 "Include has unexpected content\n", NULL, NULL); |
|
3338 return (-1); |
|
3339 } |
|
3340 |
|
3341 /* |
|
3342 * First step is to parse the input document into an DOM/Infoset |
|
3343 */ |
|
3344 doc = xmlReadFile((const char *) schemaLocation, NULL, |
|
3345 SCHEMAS_PARSE_OPTIONS); |
|
3346 if (doc == NULL) { |
|
3347 xmlSchemaPErr(ctxt, NULL, |
|
3348 XML_SCHEMAP_FAILED_LOAD, |
|
3349 "xmlSchemaParse: could not load %s\n", |
|
3350 ctxt->URL, NULL); |
|
3351 return(-1); |
|
3352 } |
|
3353 |
|
3354 /* |
|
3355 * Then extract the root of the schema |
|
3356 */ |
|
3357 root = xmlDocGetRootElement(doc); |
|
3358 if (root == NULL) { |
|
3359 xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
|
3360 XML_SCHEMAP_NOROOT, |
|
3361 "schemas %s has no root", schemaLocation, NULL); |
|
3362 xmlFreeDoc(doc); |
|
3363 return (-1); |
|
3364 } |
|
3365 |
|
3366 /* |
|
3367 * Remove all the blank text nodes |
|
3368 */ |
|
3369 xmlSchemaCleanupDoc(ctxt, root); |
|
3370 |
|
3371 /* |
|
3372 * Check the schemas top level element |
|
3373 */ |
|
3374 if (!IS_SCHEMA(root, "schema")) { |
|
3375 xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
|
3376 XML_SCHEMAP_NOT_SCHEMA, |
|
3377 "File %s is not a schemas", schemaLocation, NULL); |
|
3378 xmlFreeDoc(doc); |
|
3379 return (-1); |
|
3380 } |
|
3381 |
|
3382 /* |
|
3383 * register the include |
|
3384 */ |
|
3385 include = (xmlSchemaIncludePtr) xmlMalloc(sizeof(xmlSchemaInclude)); |
|
3386 if (include == NULL) { |
|
3387 xmlSchemaPErrMemory(ctxt, "allocating included schema", NULL); |
|
3388 xmlFreeDoc(doc); |
|
3389 return (-1); |
|
3390 } |
|
3391 |
|
3392 memset(include, 0, sizeof(xmlSchemaInclude)); |
|
3393 include->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1); |
|
3394 include->doc = doc; |
|
3395 include->next = schema->includes; |
|
3396 schema->includes = include; |
|
3397 |
|
3398 |
|
3399 /* |
|
3400 * parse the declarations in the included file like if they |
|
3401 * were in the original file. |
|
3402 */ |
|
3403 xmlSchemaParseSchemaTopLevel(ctxt, schema, root->children); |
|
3404 |
|
3405 return (1); |
|
3406 } |
|
3407 |
|
3408 /** |
|
3409 * xmlSchemaParseChoice: |
|
3410 * @ctxt: a schema validation context |
|
3411 * @schema: the schema being built |
|
3412 * @node: a subtree containing XML Schema informations |
|
3413 * |
|
3414 * parse a XML schema Choice definition |
|
3415 * *WARNING* this interface is highly subject to change |
|
3416 * |
|
3417 * Returns -1 in case of error, 0 if the declaration is improper and |
|
3418 * 1 in case of success. |
|
3419 */ |
|
3420 static xmlSchemaTypePtr |
|
3421 xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3422 xmlNodePtr node) |
|
3423 { |
|
3424 xmlSchemaTypePtr type, subtype, last = NULL; |
|
3425 xmlNodePtr child = NULL; |
|
3426 xmlChar name[30]; |
|
3427 |
|
3428 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3429 return (NULL); |
|
3430 |
|
3431 |
|
3432 snprintf((char *) name, 30, "choice %d", ctxt->counter++ + 1); |
|
3433 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3434 if (type == NULL) |
|
3435 return (NULL); |
|
3436 type->node = node; |
|
3437 type->type = XML_SCHEMA_TYPE_CHOICE; |
|
3438 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3439 type->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
3440 type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
3441 |
|
3442 child = node->children; |
|
3443 if (IS_SCHEMA(child, "annotation")) { |
|
3444 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3445 child = child->next; |
|
3446 } |
|
3447 while ((IS_SCHEMA(child, "element")) || |
|
3448 (IS_SCHEMA(child, "group")) || |
|
3449 (IS_SCHEMA(child, "any")) || |
|
3450 (IS_SCHEMA(child, "choice")) || |
|
3451 (IS_SCHEMA(child, "sequence"))) { |
|
3452 subtype = NULL; |
|
3453 if (IS_SCHEMA(child, "element")) { |
|
3454 subtype = (xmlSchemaTypePtr) |
|
3455 xmlSchemaParseElement(ctxt, schema, child, 0); |
|
3456 } else if (IS_SCHEMA(child, "group")) { |
|
3457 subtype = xmlSchemaParseGroup(ctxt, schema, child); |
|
3458 } else if (IS_SCHEMA(child, "any")) { |
|
3459 subtype = xmlSchemaParseAny(ctxt, schema, child); |
|
3460 } else if (IS_SCHEMA(child, "sequence")) { |
|
3461 subtype = xmlSchemaParseSequence(ctxt, schema, child); |
|
3462 } else if (IS_SCHEMA(child, "choice")) { |
|
3463 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
3464 } |
|
3465 if (subtype != NULL) { |
|
3466 if (last == NULL) { |
|
3467 type->subtypes = subtype; |
|
3468 last = subtype; |
|
3469 } else { |
|
3470 last->next = subtype; |
|
3471 last = subtype; |
|
3472 } |
|
3473 last->next = NULL; |
|
3474 } |
|
3475 child = child->next; |
|
3476 } |
|
3477 if (child != NULL) { |
|
3478 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_CHOICE_CHILD, |
|
3479 "Choice %s has unexpected content\n", type->name, |
|
3480 NULL); |
|
3481 } |
|
3482 |
|
3483 return (type); |
|
3484 } |
|
3485 |
|
3486 /** |
|
3487 * xmlSchemaParseSequence: |
|
3488 * @ctxt: a schema validation context |
|
3489 * @schema: the schema being built |
|
3490 * @node: a subtree containing XML Schema informations |
|
3491 * |
|
3492 * parse a XML schema Sequence definition |
|
3493 * *WARNING* this interface is highly subject to change |
|
3494 * |
|
3495 * Returns -1 in case of error, 0 if the declaration is improper and |
|
3496 * 1 in case of success. |
|
3497 */ |
|
3498 static xmlSchemaTypePtr |
|
3499 xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3500 xmlNodePtr node) |
|
3501 { |
|
3502 xmlSchemaTypePtr type, subtype, last = NULL; |
|
3503 xmlNodePtr child = NULL; |
|
3504 xmlChar name[30]; |
|
3505 |
|
3506 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3507 return (NULL); |
|
3508 |
|
3509 |
|
3510 snprintf((char *) name, 30, "sequence %d", ctxt->counter++ + 1); |
|
3511 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3512 if (type == NULL) |
|
3513 return (NULL); |
|
3514 type->node = node; |
|
3515 type->type = XML_SCHEMA_TYPE_SEQUENCE; |
|
3516 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3517 type->minOccurs = xmlGetMinOccurs(ctxt, node); |
|
3518 type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
|
3519 |
|
3520 child = node->children; |
|
3521 if (IS_SCHEMA(child, "annotation")) { |
|
3522 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3523 child = child->next; |
|
3524 } |
|
3525 while ((IS_SCHEMA(child, "element")) || |
|
3526 (IS_SCHEMA(child, "group")) || |
|
3527 (IS_SCHEMA(child, "any")) || |
|
3528 (IS_SCHEMA(child, "choice")) || |
|
3529 (IS_SCHEMA(child, "sequence"))) { |
|
3530 subtype = NULL; |
|
3531 if (IS_SCHEMA(child, "element")) { |
|
3532 subtype = (xmlSchemaTypePtr) |
|
3533 xmlSchemaParseElement(ctxt, schema, child, 0); |
|
3534 } else if (IS_SCHEMA(child, "group")) { |
|
3535 subtype = xmlSchemaParseGroup(ctxt, schema, child); |
|
3536 } else if (IS_SCHEMA(child, "any")) { |
|
3537 subtype = xmlSchemaParseAny(ctxt, schema, child); |
|
3538 } else if (IS_SCHEMA(child, "choice")) { |
|
3539 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
3540 } else if (IS_SCHEMA(child, "sequence")) { |
|
3541 subtype = xmlSchemaParseSequence(ctxt, schema, child); |
|
3542 } |
|
3543 if (subtype != NULL) { |
|
3544 if (last == NULL) { |
|
3545 type->subtypes = subtype; |
|
3546 last = subtype; |
|
3547 } else { |
|
3548 last->next = subtype; |
|
3549 last = subtype; |
|
3550 } |
|
3551 last->next = NULL; |
|
3552 } |
|
3553 child = child->next; |
|
3554 } |
|
3555 if (child != NULL) { |
|
3556 xmlSchemaPErr2(ctxt, node, child, |
|
3557 XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, |
|
3558 "Sequence %s has unexpected content\n", type->name, |
|
3559 NULL); |
|
3560 } |
|
3561 |
|
3562 return (type); |
|
3563 } |
|
3564 |
|
3565 /** |
|
3566 * xmlSchemaParseRestriction: |
|
3567 * @ctxt: a schema validation context |
|
3568 * @schema: the schema being built |
|
3569 * @node: a subtree containing XML Schema informations |
|
3570 * @simple: is that part of a simple type. |
|
3571 * |
|
3572 * parse a XML schema Restriction definition |
|
3573 * *WARNING* this interface is highly subject to change |
|
3574 * |
|
3575 * Returns the type definition or NULL in case of error |
|
3576 */ |
|
3577 static xmlSchemaTypePtr |
|
3578 xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3579 xmlNodePtr node, int simple) |
|
3580 { |
|
3581 xmlSchemaTypePtr type, subtype; |
|
3582 xmlSchemaFacetPtr facet, lastfacet = NULL; |
|
3583 xmlNodePtr child = NULL; |
|
3584 xmlChar name[30]; |
|
3585 const xmlChar *oldcontainer; |
|
3586 |
|
3587 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3588 return (NULL); |
|
3589 |
|
3590 oldcontainer = ctxt->container; |
|
3591 |
|
3592 snprintf((char *) name, 30, "restriction %d", ctxt->counter++ + 1); |
|
3593 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3594 if (type == NULL) |
|
3595 return (NULL); |
|
3596 type->node = node; |
|
3597 type->type = XML_SCHEMA_TYPE_RESTRICTION; |
|
3598 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3599 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs)); |
|
3600 if ((!simple) && (type->base == NULL)) { |
|
3601 xmlSchemaPErr2(ctxt, node, child, |
|
3602 XML_SCHEMAP_RESTRICTION_NONAME_NOREF, |
|
3603 "Restriction %s has no base\n", type->name, NULL); |
|
3604 } |
|
3605 ctxt->container = name; |
|
3606 |
|
3607 child = node->children; |
|
3608 if (IS_SCHEMA(child, "annotation")) { |
|
3609 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3610 child = child->next; |
|
3611 } |
|
3612 subtype = NULL; |
|
3613 |
|
3614 if (IS_SCHEMA(child, "all")) { |
|
3615 subtype = (xmlSchemaTypePtr) |
|
3616 xmlSchemaParseAll(ctxt, schema, child); |
|
3617 child = child->next; |
|
3618 type->subtypes = subtype; |
|
3619 } else if (IS_SCHEMA(child, "choice")) { |
|
3620 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
3621 child = child->next; |
|
3622 type->subtypes = subtype; |
|
3623 } else if (IS_SCHEMA(child, "sequence")) { |
|
3624 subtype = (xmlSchemaTypePtr) |
|
3625 xmlSchemaParseSequence(ctxt, schema, child); |
|
3626 child = child->next; |
|
3627 type->subtypes = subtype; |
|
3628 } else if (IS_SCHEMA(child, "group")) { |
|
3629 subtype = (xmlSchemaTypePtr) |
|
3630 xmlSchemaParseGroup(ctxt, schema, child); |
|
3631 child = child->next; |
|
3632 type->subtypes = subtype; |
|
3633 } else { |
|
3634 if (IS_SCHEMA(child, "simpleType")) { |
|
3635 subtype = (xmlSchemaTypePtr) |
|
3636 xmlSchemaParseSimpleType(ctxt, schema, child); |
|
3637 child = child->next; |
|
3638 type->baseType = subtype; |
|
3639 } |
|
3640 /* |
|
3641 * Facets |
|
3642 */ |
|
3643 while ((IS_SCHEMA(child, "minInclusive")) || |
|
3644 (IS_SCHEMA(child, "minExclusive")) || |
|
3645 (IS_SCHEMA(child, "maxInclusive")) || |
|
3646 (IS_SCHEMA(child, "maxExclusive")) || |
|
3647 (IS_SCHEMA(child, "totalDigits")) || |
|
3648 (IS_SCHEMA(child, "fractionDigits")) || |
|
3649 (IS_SCHEMA(child, "pattern")) || |
|
3650 (IS_SCHEMA(child, "enumeration")) || |
|
3651 (IS_SCHEMA(child, "whiteSpace")) || |
|
3652 (IS_SCHEMA(child, "length")) || |
|
3653 (IS_SCHEMA(child, "maxLength")) || |
|
3654 (IS_SCHEMA(child, "minLength"))) { |
|
3655 facet = xmlSchemaParseFacet(ctxt, schema, child); |
|
3656 if (facet != NULL) { |
|
3657 if (lastfacet == NULL) { |
|
3658 type->facets = facet; |
|
3659 lastfacet = facet; |
|
3660 } else { |
|
3661 lastfacet->next = facet; |
|
3662 lastfacet = facet; |
|
3663 } |
|
3664 lastfacet->next = NULL; |
|
3665 } |
|
3666 child = child->next; |
|
3667 } |
|
3668 } |
|
3669 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type); |
|
3670 if (child != NULL) { |
|
3671 xmlSchemaPErr2(ctxt, node, child, |
|
3672 XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, |
|
3673 "Restriction %s has unexpected content\n", |
|
3674 type->name, NULL); |
|
3675 } |
|
3676 ctxt->container = oldcontainer; |
|
3677 return (type); |
|
3678 } |
|
3679 |
|
3680 /** |
|
3681 * xmlSchemaParseExtension: |
|
3682 * @ctxt: a schema validation context |
|
3683 * @schema: the schema being built |
|
3684 * @node: a subtree containing XML Schema informations |
|
3685 * |
|
3686 * parse a XML schema Extension definition |
|
3687 * *WARNING* this interface is highly subject to change |
|
3688 * |
|
3689 * Returns the type definition or NULL in case of error |
|
3690 */ |
|
3691 static xmlSchemaTypePtr |
|
3692 xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3693 xmlNodePtr node) |
|
3694 { |
|
3695 xmlSchemaTypePtr type, subtype; |
|
3696 xmlNodePtr child = NULL; |
|
3697 xmlChar name[30]; |
|
3698 const xmlChar *oldcontainer; |
|
3699 |
|
3700 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3701 return (NULL); |
|
3702 |
|
3703 oldcontainer = ctxt->container; |
|
3704 |
|
3705 snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1); |
|
3706 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3707 if (type == NULL) |
|
3708 return (NULL); |
|
3709 type->node = node; |
|
3710 type->type = XML_SCHEMA_TYPE_EXTENSION; |
|
3711 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3712 ctxt->container = name; |
|
3713 |
|
3714 type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs)); |
|
3715 if (type->base == NULL) { |
|
3716 xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_EXTENSION_NO_BASE, |
|
3717 "Extension %s has no base\n", type->name, NULL); |
|
3718 } |
|
3719 child = node->children; |
|
3720 if (IS_SCHEMA(child, "annotation")) { |
|
3721 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3722 child = child->next; |
|
3723 } |
|
3724 subtype = NULL; |
|
3725 |
|
3726 if (IS_SCHEMA(child, "all")) { |
|
3727 subtype = xmlSchemaParseAll(ctxt, schema, child); |
|
3728 child = child->next; |
|
3729 } else if (IS_SCHEMA(child, "choice")) { |
|
3730 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
3731 child = child->next; |
|
3732 } else if (IS_SCHEMA(child, "sequence")) { |
|
3733 subtype = xmlSchemaParseSequence(ctxt, schema, child); |
|
3734 child = child->next; |
|
3735 } else if (IS_SCHEMA(child, "group")) { |
|
3736 subtype = xmlSchemaParseGroup(ctxt, schema, child); |
|
3737 child = child->next; |
|
3738 } |
|
3739 if (subtype != NULL) |
|
3740 type->subtypes = subtype; |
|
3741 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type); |
|
3742 if (child != NULL) { |
|
3743 xmlSchemaPErr2(ctxt, node, child, |
|
3744 XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD, |
|
3745 "Extension %s has unexpected content\n", type->name, |
|
3746 NULL); |
|
3747 } |
|
3748 ctxt->container = oldcontainer; |
|
3749 return (type); |
|
3750 } |
|
3751 |
|
3752 /** |
|
3753 * xmlSchemaParseSimpleContent: |
|
3754 * @ctxt: a schema validation context |
|
3755 * @schema: the schema being built |
|
3756 * @node: a subtree containing XML Schema informations |
|
3757 * |
|
3758 * parse a XML schema SimpleContent definition |
|
3759 * *WARNING* this interface is highly subject to change |
|
3760 * |
|
3761 * Returns the type definition or NULL in case of error |
|
3762 */ |
|
3763 static xmlSchemaTypePtr |
|
3764 xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, |
|
3765 xmlSchemaPtr schema, xmlNodePtr node) |
|
3766 { |
|
3767 xmlSchemaTypePtr type, subtype; |
|
3768 xmlNodePtr child = NULL; |
|
3769 xmlChar name[30]; |
|
3770 |
|
3771 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3772 return (NULL); |
|
3773 |
|
3774 |
|
3775 snprintf((char *) name, 30, "simpleContent %d", ctxt->counter++ + 1); |
|
3776 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3777 if (type == NULL) |
|
3778 return (NULL); |
|
3779 type->node = node; |
|
3780 type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT; |
|
3781 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3782 |
|
3783 child = node->children; |
|
3784 if (IS_SCHEMA(child, "annotation")) { |
|
3785 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3786 child = child->next; |
|
3787 } |
|
3788 subtype = NULL; |
|
3789 if (IS_SCHEMA(child, "restriction")) { |
|
3790 subtype = (xmlSchemaTypePtr) |
|
3791 xmlSchemaParseRestriction(ctxt, schema, child, 0); |
|
3792 child = child->next; |
|
3793 } else if (IS_SCHEMA(child, "extension")) { |
|
3794 subtype = (xmlSchemaTypePtr) |
|
3795 xmlSchemaParseExtension(ctxt, schema, child); |
|
3796 child = child->next; |
|
3797 } |
|
3798 type->subtypes = subtype; |
|
3799 if (child != NULL) { |
|
3800 xmlSchemaPErr2(ctxt, node, child, |
|
3801 XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD, |
|
3802 "SimpleContent %s has unexpected content\n", |
|
3803 type->name, NULL); |
|
3804 } |
|
3805 return (type); |
|
3806 } |
|
3807 |
|
3808 /** |
|
3809 * xmlSchemaParseComplexContent: |
|
3810 * @ctxt: a schema validation context |
|
3811 * @schema: the schema being built |
|
3812 * @node: a subtree containing XML Schema informations |
|
3813 * |
|
3814 * parse a XML schema ComplexContent definition |
|
3815 * *WARNING* this interface is highly subject to change |
|
3816 * |
|
3817 * Returns the type definition or NULL in case of error |
|
3818 */ |
|
3819 static xmlSchemaTypePtr |
|
3820 xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, |
|
3821 xmlSchemaPtr schema, xmlNodePtr node) |
|
3822 { |
|
3823 xmlSchemaTypePtr type, subtype; |
|
3824 xmlNodePtr child = NULL; |
|
3825 xmlChar name[30]; |
|
3826 |
|
3827 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3828 return (NULL); |
|
3829 |
|
3830 |
|
3831 snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1); |
|
3832 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3833 if (type == NULL) |
|
3834 return (NULL); |
|
3835 type->node = node; |
|
3836 type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT; |
|
3837 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3838 |
|
3839 child = node->children; |
|
3840 if (IS_SCHEMA(child, "annotation")) { |
|
3841 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3842 child = child->next; |
|
3843 } |
|
3844 subtype = NULL; |
|
3845 if (IS_SCHEMA(child, "restriction")) { |
|
3846 subtype = (xmlSchemaTypePtr) |
|
3847 xmlSchemaParseRestriction(ctxt, schema, child, 0); |
|
3848 child = child->next; |
|
3849 } else if (IS_SCHEMA(child, "extension")) { |
|
3850 subtype = (xmlSchemaTypePtr) |
|
3851 xmlSchemaParseExtension(ctxt, schema, child); |
|
3852 child = child->next; |
|
3853 } |
|
3854 type->subtypes = subtype; |
|
3855 if (child != NULL) { |
|
3856 xmlSchemaPErr2(ctxt, node, child, |
|
3857 XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD, |
|
3858 "ComplexContent %s has unexpected content\n", |
|
3859 type->name, NULL); |
|
3860 } |
|
3861 return (type); |
|
3862 } |
|
3863 |
|
3864 /** |
|
3865 * xmlSchemaParseComplexType: |
|
3866 * @ctxt: a schema validation context |
|
3867 * @schema: the schema being built |
|
3868 * @node: a subtree containing XML Schema informations |
|
3869 * |
|
3870 * parse a XML schema Complex Type definition |
|
3871 * *WARNING* this interface is highly subject to change |
|
3872 * |
|
3873 * Returns the type definition or NULL in case of error |
|
3874 */ |
|
3875 static xmlSchemaTypePtr |
|
3876 xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
|
3877 xmlNodePtr node) |
|
3878 { |
|
3879 xmlSchemaTypePtr type, subtype; |
|
3880 xmlNodePtr child = NULL; |
|
3881 const xmlChar *name; |
|
3882 const xmlChar *oldcontainer; |
|
3883 char buf[100]; |
|
3884 |
|
3885 if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
|
3886 return (NULL); |
|
3887 |
|
3888 oldcontainer = ctxt->container; |
|
3889 name = xmlSchemaGetProp(ctxt, node, "name"); |
|
3890 if (name == NULL) { |
|
3891 |
|
3892 snprintf(buf, 99, "complexType %d", ctxt->counter++ + 1); |
|
3893 name = (const xmlChar *)buf; |
|
3894 type = xmlSchemaAddType(ctxt, schema, name, NULL); |
|
3895 } else { |
|
3896 |
|
3897 /* local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ |
|
3898 type = xmlSchemaAddType(ctxt, schema, name, schema->targetNamespace); |
|
3899 } |
|
3900 if (type == NULL) { |
|
3901 return (NULL); |
|
3902 } |
|
3903 |
|
3904 if (xmlGetBooleanProp(ctxt, node, "mixed", 0)) |
|
3905 type->flags |= XML_SCHEMAS_TYPE_MIXED; |
|
3906 |
|
3907 type->node = node; |
|
3908 type->type = XML_SCHEMA_TYPE_COMPLEX; |
|
3909 type->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3910 ctxt->container = name; |
|
3911 |
|
3912 child = node->children; |
|
3913 if (IS_SCHEMA(child, "annotation")) { |
|
3914 type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
|
3915 child = child->next; |
|
3916 } |
|
3917 if (IS_SCHEMA(child, "simpleContent")) { |
|
3918 /* 3.4.3 : 2.2 |
|
3919 * Specifying mixed='true' when the <simpleContent> |
|
3920 * alternative is chosen has no effect |
|
3921 */ |
|
3922 if (type->flags & XML_SCHEMAS_TYPE_MIXED) |
|
3923 type->flags ^= XML_SCHEMAS_TYPE_MIXED; |
|
3924 type->subtypes = xmlSchemaParseSimpleContent(ctxt, schema, child); |
|
3925 child = child->next; |
|
3926 } else if (IS_SCHEMA(child, "complexContent")) { |
|
3927 type->subtypes = xmlSchemaParseComplexContent(ctxt, schema, child); |
|
3928 child = child->next; |
|
3929 } else { |
|
3930 subtype = NULL; |
|
3931 |
|
3932 if (IS_SCHEMA(child, "all")) { |
|
3933 subtype = xmlSchemaParseAll(ctxt, schema, child); |
|
3934 child = child->next; |
|
3935 } else if (IS_SCHEMA(child, "choice")) { |
|
3936 subtype = xmlSchemaParseChoice(ctxt, schema, child); |
|
3937 child = child->next; |
|
3938 } else if (IS_SCHEMA(child, "sequence")) { |
|
3939 subtype = xmlSchemaParseSequence(ctxt, schema, child); |
|
3940 child = child->next; |
|
3941 } else if (IS_SCHEMA(child, "group")) { |
|
3942 subtype = xmlSchemaParseGroup(ctxt, schema, child); |
|
3943 child = child->next; |
|
3944 } |
|
3945 if (subtype != NULL) |
|
3946 type->subtypes = subtype; |
|
3947 child = xmlSchemaParseAttrDecls(ctxt, schema, child, type); |
|
3948 } |
|
3949 if (child != NULL) { |
|
3950 xmlSchemaPErr2(ctxt, node, child, |
|
3951 XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD, |
|
3952 "ComplexType %s has unexpected content\n", |
|
3953 type->name, NULL); |
|
3954 } |
|
3955 ctxt->container = oldcontainer; |
|
3956 return (type); |
|
3957 } |
|
3958 |
|
3959 /** |
|
3960 * xmlSchemaParseSchema: |
|
3961 * @ctxt: a schema validation context |
|
3962 * @node: a subtree containing XML Schema informations |
|
3963 * |
|
3964 * parse a XML schema definition from a node set |
|
3965 * *WARNING* this interface is highly subject to change |
|
3966 * |
|
3967 * Returns the internal XML Schema structure built from the resource or |
|
3968 * NULL in case of error |
|
3969 */ |
|
3970 static xmlSchemaPtr |
|
3971 xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) |
|
3972 { |
|
3973 xmlSchemaPtr schema = NULL; |
|
3974 xmlNodePtr child = NULL; |
|
3975 const xmlChar *val; |
|
3976 int nberrors; |
|
3977 |
|
3978 if ((ctxt == NULL) || (node == NULL)) |
|
3979 return (NULL); |
|
3980 |
|
3981 nberrors = ctxt->nberrors; |
|
3982 ctxt->nberrors = 0; |
|
3983 if (IS_SCHEMA(node, "schema")) { |
|
3984 schema = xmlSchemaNewSchema(ctxt); |
|
3985 if (schema == NULL) |
|
3986 return (NULL); |
|
3987 val = xmlSchemaGetProp(ctxt, node, "targetNamespace"); |
|
3988 if (val != NULL) { |
|
3989 schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1); |
|
3990 } else { |
|
3991 schema->targetNamespace = NULL; |
|
3992 } |
|
3993 schema->id = xmlSchemaGetProp(ctxt, node, "id"); |
|
3994 schema->version = xmlSchemaGetProp(ctxt, node, "version"); |
|
3995 val = xmlSchemaGetProp(ctxt, node, "elementFormDefault"); |
|
3996 if (val != NULL) { |
|
3997 if (xmlStrEqual(val, BAD_CAST "qualified")) |
|
3998 schema->flags |= XML_SCHEMAS_QUALIF_ELEM; |
|
3999 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) { |
|
4000 xmlSchemaPErr2(ctxt, node, child, |
|
4001 XML_SCHEMAP_ELEMFORMDEFAULT_VALUE, |
|
4002 "Invalid value %s for elementFormDefault\n", |
|
4003 val, NULL); |
|
4004 } |
|
4005 } else { |
|
4006 schema->flags |= XML_SCHEMAS_QUALIF_ELEM; |
|
4007 } |
|
4008 val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault"); |
|
4009 if (val != NULL) { |
|
4010 if (xmlStrEqual(val, BAD_CAST "qualified")) |
|
4011 schema->flags |= XML_SCHEMAS_QUALIF_ATTR; |
|
4012 else if (!xmlStrEqual(val, BAD_CAST "unqualified")) { |
|
4013 xmlSchemaPErr2(ctxt, node, child, |
|
4014 XML_SCHEMAP_ATTRFORMDEFAULT_VALUE, |
|
4015 "Invalid value %s for attributeFormDefault\n", |
|
4016 val, NULL); |
|
4017 } |
|
4018 } |
|
4019 |
|
4020 xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children); |
|
4021 } else { |
|
4022 xmlDocPtr doc; |
|
4023 |
|
4024 doc = node->doc; |
|
4025 |
|
4026 if ((doc != NULL) && (doc->URL != NULL)) { |
|
4027 xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
|
4028 XML_SCHEMAP_NOT_SCHEMA, |
|
4029 "File %s is not a schemas", doc->URL, NULL); |
|
4030 } else { |
|
4031 xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
|
4032 XML_SCHEMAP_NOT_SCHEMA, |
|
4033 "File is not a schemas", NULL, NULL); |
|
4034 } |
|
4035 return(NULL); |
|
4036 } |
|
4037 if (ctxt->nberrors != 0) { |
|
4038 if (schema != NULL) { |
|
4039 xmlSchemaFree(schema); |
|
4040 schema = NULL; |
|
4041 } |
|
4042 } |
|
4043 ctxt->nberrors = nberrors; |
|
4044 #ifdef DEBUG |
|
4045 if (schema == NULL) |
|
4046 xmlGenericError(xmlGenericErrorContext, |
|
4047 "xmlSchemaParse() failed\n"); |
|
4048 #endif |
|
4049 |
|
4050 return (schema); |
|
4051 } |
|
4052 |
|
4053 /************************************************************************ |
|
4054 * * |
|
4055 * Validating using Schemas * |
|
4056 * * |
|
4057 ************************************************************************/ |
|
4058 |
|
4059 /************************************************************************ |
|
4060 * * |
|
4061 * Reading/Writing Schemas * |
|
4062 * * |
|
4063 ************************************************************************/ |
|
4064 |
|
4065 /** |
|
4066 * xmlSchemaNewParserCtxt: |
|
4067 * @URL: the location of the schema |
|
4068 * |
|
4069 * Create an XML Schemas parse context for that file/resource expected |
|
4070 * to contain an XML Schemas file. |
|
4071 * |
|
4072 * Returns the parser context or NULL in case of error |
|
4073 */ |
|
4074 xmlSchemaParserCtxtPtr |
|
4075 xmlSchemaNewParserCtxt(const char *URL) |
|
4076 { |
|
4077 xmlSchemaParserCtxtPtr ret; |
|
4078 |
|
4079 if (URL == NULL) |
|
4080 return (NULL); |
|
4081 |
|
4082 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); |
|
4083 if (ret == NULL) { |
|
4084 xmlSchemaPErrMemory(NULL, "allocating schama parser context", |
|
4085 NULL); |
|
4086 return (NULL); |
|
4087 } |
|
4088 memset(ret, 0, sizeof(xmlSchemaParserCtxt)); |
|
4089 ret->dict = xmlDictCreate(); |
|
4090 ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); |
|
4091 ret->includes = 0; |
|
4092 return (ret); |
|
4093 } |
|
4094 |
|
4095 /** |
|
4096 * xmlSchemaNewMemParserCtxt: |
|
4097 * @buffer: a pointer to a char array containing the schemas |
|
4098 * @size: the size of the array |
|
4099 * |
|
4100 * Create an XML Schemas parse context for that memory buffer expected |
|
4101 * to contain an XML Schemas file. |
|
4102 * |
|
4103 * Returns the parser context or NULL in case of error |
|
4104 */ |
|
4105 xmlSchemaParserCtxtPtr |
|
4106 xmlSchemaNewMemParserCtxt(const char *buffer, int size) |
|
4107 { |
|
4108 xmlSchemaParserCtxtPtr ret; |
|
4109 |
|
4110 if ((buffer == NULL) || (size <= 0)) |
|
4111 return (NULL); |
|
4112 |
|
4113 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); |
|
4114 if (ret == NULL) { |
|
4115 xmlSchemaPErrMemory(NULL, "allocating schama parser context", |
|
4116 NULL); |
|
4117 return (NULL); |
|
4118 } |
|
4119 memset(ret, 0, sizeof(xmlSchemaParserCtxt)); |
|
4120 ret->buffer = buffer; |
|
4121 ret->size = size; |
|
4122 ret->dict = xmlDictCreate(); |
|
4123 return (ret); |
|
4124 } |
|
4125 |
|
4126 /** |
|
4127 * xmlSchemaNewDocParserCtxt: |
|
4128 * @doc: a preparsed document tree |
|
4129 * |
|
4130 * Create an XML Schemas parse context for that document. |
|
4131 * NB. The document may be modified during the parsing process. |
|
4132 * |
|
4133 * Returns the parser context or NULL in case of error |
|
4134 */ |
|
4135 xmlSchemaParserCtxtPtr |
|
4136 xmlSchemaNewDocParserCtxt(xmlDocPtr doc) |
|
4137 { |
|
4138 xmlSchemaParserCtxtPtr ret; |
|
4139 |
|
4140 if (doc == NULL) |
|
4141 return (NULL); |
|
4142 |
|
4143 ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); |
|
4144 if (ret == NULL) { |
|
4145 xmlSchemaPErrMemory(NULL, "allocating schema parser context", |
|
4146 NULL); |
|
4147 return (NULL); |
|
4148 } |
|
4149 memset(ret, 0, sizeof(xmlSchemaParserCtxt)); |
|
4150 ret->doc = doc; |
|
4151 ret->dict = xmlDictCreate(); |
|
4152 /* The application has responsibility for the document */ |
|
4153 ret->preserve = 1; |
|
4154 |
|
4155 return (ret); |
|
4156 } |
|
4157 |
|
4158 /** |
|
4159 * xmlSchemaFreeParserCtxt: |
|
4160 * @ctxt: the schema parser context |
|
4161 * |
|
4162 * Free the resources associated to the schema parser context |
|
4163 */ |
|
4164 void |
|
4165 xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) |
|
4166 { |
|
4167 if (ctxt == NULL) |
|
4168 return; |
|
4169 if (ctxt->doc != NULL && !ctxt->preserve) |
|
4170 xmlFreeDoc(ctxt->doc); |
|
4171 xmlDictFree(ctxt->dict); |
|
4172 xmlFree(ctxt); |
|
4173 } |
|
4174 |
|
4175 /************************************************************************ |
|
4176 * * |
|
4177 * Building the content models * |
|
4178 * * |
|
4179 ************************************************************************/ |
|
4180 |
|
4181 /** |
|
4182 * xmlSchemaBuildAContentModel: |
|
4183 * @type: the schema type definition |
|
4184 * @ctxt: the schema parser context |
|
4185 * @name: the element name whose content is being built |
|
4186 * |
|
4187 * Generate the automata sequence needed for that type |
|
4188 */ |
|
4189 static void |
|
4190 xmlSchemaBuildAContentModel(xmlSchemaTypePtr type, |
|
4191 xmlSchemaParserCtxtPtr ctxt, |
|
4192 const xmlChar * name) |
|
4193 { |
|
4194 if (type == NULL) { |
|
4195 xmlGenericError(xmlGenericErrorContext, |
|
4196 "Found unexpected type = NULL in %s content model\n", |
|
4197 name); |
|
4198 return; |
|
4199 } |
|
4200 switch (type->type) { |
|
4201 case XML_SCHEMA_TYPE_ANY: |
|
4202 /* TODO : handle the namespace too */ |
|
4203 /* TODO : make that a specific transition type */ |
|
4204 TODO ctxt->state = |
|
4205 xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL, |
|
4206 BAD_CAST "*", NULL); |
|
4207 break; |
|
4208 case XML_SCHEMA_TYPE_ELEMENT:{ |
|
4209 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type; |
|
4210 |
|
4211 /* TODO : handle the namespace too */ |
|
4212 xmlAutomataStatePtr oldstate = ctxt->state; |
|
4213 |
|
4214 if (elem->maxOccurs >= UNBOUNDED) { |
|
4215 if (elem->minOccurs > 1) { |
|
4216 xmlAutomataStatePtr tmp; |
|
4217 int counter; |
|
4218 |
|
4219 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, |
|
4220 oldstate, |
|
4221 NULL); |
|
4222 oldstate = ctxt->state; |
|
4223 |
|
4224 counter = xmlAutomataNewCounter(ctxt->am, |
|
4225 elem->minOccurs - |
|
4226 1, UNBOUNDED); |
|
4227 |
|
4228 if (elem->refDecl != NULL) { |
|
4229 xmlSchemaBuildAContentModel((xmlSchemaTypePtr) |
|
4230 elem->refDecl, |
|
4231 ctxt, |
|
4232 elem->refDecl-> |
|
4233 name); |
|
4234 } else { |
|
4235 ctxt->state = |
|
4236 xmlAutomataNewTransition(ctxt->am, |
|
4237 ctxt->state, NULL, |
|
4238 elem->name, type); |
|
4239 } |
|
4240 tmp = ctxt->state; |
|
4241 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate, |
|
4242 counter); |
|
4243 ctxt->state = |
|
4244 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL, |
|
4245 counter); |
|
4246 |
|
4247 } else { |
|
4248 if (elem->refDecl != NULL) { |
|
4249 xmlSchemaBuildAContentModel((xmlSchemaTypePtr) |
|
4250 elem->refDecl, |
|
4251 ctxt, |
|
4252 elem->refDecl-> |
|
4253 name); |
|
4254 } else { |
|
4255 ctxt->state = |
|
4256 xmlAutomataNewTransition(ctxt->am, |
|
4257 ctxt->state, NULL, |
|
4258 elem->name, type); |
|
4259 } |
|
4260 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, |
|
4261 oldstate); |
|
4262 if (elem->minOccurs == 0) { |
|
4263 /* basically an elem* */ |
|
4264 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4265 ctxt->state); |
|
4266 } |
|
4267 } |
|
4268 } else if ((elem->maxOccurs > 1) || (elem->minOccurs > 1)) { |
|
4269 xmlAutomataStatePtr tmp; |
|
4270 int counter; |
|
4271 |
|
4272 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, |
|
4273 oldstate, NULL); |
|
4274 oldstate = ctxt->state; |
|
4275 |
|
4276 counter = xmlAutomataNewCounter(ctxt->am, |
|
4277 elem->minOccurs - 1, |
|
4278 elem->maxOccurs - 1); |
|
4279 |
|
4280 if (elem->refDecl != NULL) { |
|
4281 xmlSchemaBuildAContentModel((xmlSchemaTypePtr) |
|
4282 elem->refDecl, ctxt, |
|
4283 elem->refDecl->name); |
|
4284 } else { |
|
4285 ctxt->state = xmlAutomataNewTransition(ctxt->am, |
|
4286 ctxt->state, |
|
4287 NULL, |
|
4288 elem->name, |
|
4289 type); |
|
4290 } |
|
4291 tmp = ctxt->state; |
|
4292 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate, |
|
4293 counter); |
|
4294 ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, tmp, |
|
4295 NULL, |
|
4296 counter); |
|
4297 if (elem->minOccurs == 0) { |
|
4298 /* basically an elem? */ |
|
4299 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4300 ctxt->state); |
|
4301 } |
|
4302 |
|
4303 } else { |
|
4304 if (elem->refDecl != NULL) { |
|
4305 xmlSchemaBuildAContentModel((xmlSchemaTypePtr) |
|
4306 elem->refDecl, ctxt, |
|
4307 elem->refDecl->name); |
|
4308 } else { |
|
4309 ctxt->state = xmlAutomataNewTransition(ctxt->am, |
|
4310 ctxt->state, |
|
4311 NULL, |
|
4312 elem->name, |
|
4313 type); |
|
4314 } |
|
4315 if (elem->minOccurs == 0) { |
|
4316 /* basically an elem? */ |
|
4317 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4318 ctxt->state); |
|
4319 } |
|
4320 } |
|
4321 break; |
|
4322 } |
|
4323 case XML_SCHEMA_TYPE_SEQUENCE:{ |
|
4324 xmlSchemaTypePtr subtypes; |
|
4325 |
|
4326 /* |
|
4327 * If max and min occurances are default (1) then |
|
4328 * simply iterate over the subtypes |
|
4329 */ |
|
4330 if ((type->minOccurs == 1) && (type->maxOccurs == 1)) { |
|
4331 subtypes = type->subtypes; |
|
4332 while (subtypes != NULL) { |
|
4333 xmlSchemaBuildAContentModel(subtypes, ctxt, name); |
|
4334 subtypes = subtypes->next; |
|
4335 } |
|
4336 } else { |
|
4337 xmlAutomataStatePtr oldstate = ctxt->state; |
|
4338 |
|
4339 if (type->maxOccurs >= UNBOUNDED) { |
|
4340 if (type->minOccurs > 1) { |
|
4341 xmlAutomataStatePtr tmp; |
|
4342 int counter; |
|
4343 |
|
4344 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, |
|
4345 oldstate, |
|
4346 NULL); |
|
4347 oldstate = ctxt->state; |
|
4348 |
|
4349 counter = xmlAutomataNewCounter(ctxt->am, |
|
4350 type-> |
|
4351 minOccurs - 1, |
|
4352 UNBOUNDED); |
|
4353 |
|
4354 subtypes = type->subtypes; |
|
4355 while (subtypes != NULL) { |
|
4356 xmlSchemaBuildAContentModel(subtypes, ctxt, |
|
4357 name); |
|
4358 subtypes = subtypes->next; |
|
4359 } |
|
4360 tmp = ctxt->state; |
|
4361 xmlAutomataNewCountedTrans(ctxt->am, tmp, |
|
4362 oldstate, counter); |
|
4363 ctxt->state = |
|
4364 xmlAutomataNewCounterTrans(ctxt->am, tmp, |
|
4365 NULL, counter); |
|
4366 |
|
4367 } else { |
|
4368 subtypes = type->subtypes; |
|
4369 while (subtypes != NULL) { |
|
4370 xmlSchemaBuildAContentModel(subtypes, ctxt, |
|
4371 name); |
|
4372 subtypes = subtypes->next; |
|
4373 } |
|
4374 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, |
|
4375 oldstate); |
|
4376 if (type->minOccurs == 0) { |
|
4377 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4378 ctxt->state); |
|
4379 } |
|
4380 } |
|
4381 } else if ((type->maxOccurs > 1) |
|
4382 || (type->minOccurs > 1)) { |
|
4383 xmlAutomataStatePtr tmp; |
|
4384 int counter; |
|
4385 |
|
4386 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, |
|
4387 oldstate, |
|
4388 NULL); |
|
4389 oldstate = ctxt->state; |
|
4390 |
|
4391 counter = xmlAutomataNewCounter(ctxt->am, |
|
4392 type->minOccurs - |
|
4393 1, |
|
4394 type->maxOccurs - |
|
4395 1); |
|
4396 |
|
4397 subtypes = type->subtypes; |
|
4398 while (subtypes != NULL) { |
|
4399 xmlSchemaBuildAContentModel(subtypes, ctxt, |
|
4400 name); |
|
4401 subtypes = subtypes->next; |
|
4402 } |
|
4403 tmp = ctxt->state; |
|
4404 xmlAutomataNewCountedTrans(ctxt->am, tmp, oldstate, |
|
4405 counter); |
|
4406 ctxt->state = |
|
4407 xmlAutomataNewCounterTrans(ctxt->am, tmp, NULL, |
|
4408 counter); |
|
4409 if (type->minOccurs == 0) { |
|
4410 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4411 ctxt->state); |
|
4412 } |
|
4413 |
|
4414 } else { |
|
4415 subtypes = type->subtypes; |
|
4416 while (subtypes != NULL) { |
|
4417 xmlSchemaBuildAContentModel(subtypes, ctxt, |
|
4418 name); |
|
4419 subtypes = subtypes->next; |
|
4420 } |
|
4421 if (type->minOccurs == 0) { |
|
4422 xmlAutomataNewEpsilon(ctxt->am, oldstate, |
|
4423 ctxt->state); |
|
4424 } |
|
4425 } |
|
4426 } |
|
4427 break; |
|
4428 } |
|
4429 case XML_SCHEMA_TYPE_CHOICE:{ |
|
4430 xmlSchemaTypePtr subtypes; |
|
4431 xmlAutomataStatePtr start, end; |
|
4432 |
|
4433 start = ctxt->state; |
|
4434 end = xmlAutomataNewState(ctxt->am); |
|
4435 |
|
4436 /* |
|
4437 * iterate over the subtypes and remerge the end with an |
|
4438 * epsilon transition |
|
4439 */ |
|
4440 if (type->maxOccurs == 1) { |
|
4441 subtypes = type->subtypes; |
|
4442 while (subtypes != NULL) { |
|
4443 ctxt->state = start; |
|
4444 xmlSchemaBuildAContentModel(subtypes, ctxt, name); |
|
4445 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, end); |
|
4446 subtypes = subtypes->next; |
|
4447 } |
|
4448 } else { |
|
4449 int counter; |
|
4450 xmlAutomataStatePtr hop; |
|
4451 int maxOccurs = type->maxOccurs == UNBOUNDED ? |
|
4452 UNBOUNDED : type->maxOccurs - 1; |
|
4453 int minOccurs = |
|
4454 type->minOccurs < 1 ? 0 : type->minOccurs - 1; |
|
4455 |
|
4456 /* |
|
4457 * use a counter to keep track of the number of transtions |
|
4458 * which went through the choice. |
|
4459 */ |
|
4460 counter = |
|
4461 xmlAutomataNewCounter(ctxt->am, minOccurs, |
|
4462 maxOccurs); |
|
4463 hop = xmlAutomataNewState(ctxt->am); |
|
4464 |
|
4465 subtypes = type->subtypes; |
|
4466 while (subtypes != NULL) { |
|
4467 ctxt->state = start; |
|
4468 xmlSchemaBuildAContentModel(subtypes, ctxt, name); |
|
4469 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, hop); |
|
4470 subtypes = subtypes->next; |
|
4471 } |
|
4472 xmlAutomataNewCountedTrans(ctxt->am, hop, start, |
|
4473 counter); |
|
4474 xmlAutomataNewCounterTrans(ctxt->am, hop, end, |
|
4475 counter); |
|
4476 } |
|
4477 if (type->minOccurs == 0) { |
|
4478 xmlAutomataNewEpsilon(ctxt->am, start, end); |
|
4479 } |
|
4480 ctxt->state = end; |
|
4481 break; |
|
4482 } |
|
4483 case XML_SCHEMA_TYPE_ALL:{ |
|
4484 xmlAutomataStatePtr start; |
|
4485 xmlSchemaTypePtr subtypes; |
|
4486 xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type; |
|
4487 int lax; |
|
4488 |
|
4489 subtypes = type->subtypes; |
|
4490 if (subtypes == NULL) |
|
4491 break; |
|
4492 start = ctxt->state; |
|
4493 while (subtypes != NULL) { |
|
4494 ctxt->state = start; |
|
4495 /* |
|
4496 * the following 'if' was needed to fix bug 139897 |
|
4497 * not quite sure why it only needs to be done for |
|
4498 * elements with a 'ref', but it seems to work ok. |
|
4499 */ |
|
4500 if (subtypes->ref != NULL) |
|
4501 xmlSchemaBuildAContentModel(subtypes, ctxt, name); |
|
4502 elem = (xmlSchemaElementPtr) subtypes; |
|
4503 /* TODO : handle the namespace too */ |
|
4504 if ((elem->minOccurs == 1) && (elem->maxOccurs == 1)) { |
|
4505 xmlAutomataNewOnceTrans(ctxt->am, ctxt->state, |
|
4506 ctxt->state, elem->name, 1, |
|
4507 1, subtypes); |
|
4508 } else { |
|
4509 xmlAutomataNewCountTrans(ctxt->am, ctxt->state, |
|
4510 ctxt->state, elem->name, |
|
4511 elem->minOccurs, |
|
4512 elem->maxOccurs, |
|
4513 subtypes); |
|
4514 } |
|
4515 subtypes = subtypes->next; |
|
4516 } |
|
4517 lax = type->minOccurs == 0; |
|
4518 ctxt->state = |
|
4519 xmlAutomataNewAllTrans(ctxt->am, ctxt->state, NULL, |
|
4520 lax); |
|
4521 break; |
|
4522 } |
|
4523 case XML_SCHEMA_TYPE_RESTRICTION: |
|
4524 if (type->subtypes != NULL) |
|
4525 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name); |
|
4526 break; |
|
4527 case XML_SCHEMA_TYPE_EXTENSION: |
|
4528 if (type->baseType != NULL) { |
|
4529 xmlSchemaTypePtr subtypes; |
|
4530 |
|
4531 if (type->recurse) { |
|
4532 xmlSchemaPErr(ctxt, type->node, |
|
4533 XML_SCHEMAP_UNKNOWN_BASE_TYPE, |
|
4534 "Schemas: extension type %s is recursive\n", |
|
4535 type->name, NULL); |
|
4536 return; |
|
4537 } |
|
4538 type->recurse = 1; |
|
4539 xmlSchemaBuildAContentModel(type->baseType, ctxt, name); |
|
4540 type->recurse = 0; |
|
4541 subtypes = type->subtypes; |
|
4542 while (subtypes != NULL) { |
|
4543 xmlSchemaBuildAContentModel(subtypes, ctxt, name); |
|
4544 subtypes = subtypes->next; |
|
4545 } |
|
4546 } else if (type->subtypes != NULL) |
|
4547 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name); |
|
4548 break; |
|
4549 case XML_SCHEMA_TYPE_GROUP: |
|
4550 if (type->subtypes == NULL) { |
|
4551 xmlSchemaTypePtr rgroup; |
|
4552 if (type->ref != NULL) { |
|
4553 rgroup = xmlHashLookup2(ctxt->schema->groupDecl, type->ref, |
|
4554 type->refNs); |
|
4555 if (rgroup == NULL) { |
|
4556 xmlSchemaPErr(ctxt, type->node, |
|
4557 XML_SCHEMAP_UNKNOWN_REF, |
|
4558 "Schemas: group %s reference %s is not found", |
|
4559 name, type->ref); |
|
4560 return; |
|
4561 } |
|
4562 xmlSchemaBuildAContentModel(rgroup, ctxt, name); |
|
4563 break; |
|
4564 } |
|
4565 } |
|
4566 case XML_SCHEMA_TYPE_COMPLEX: |
|
4567 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: |
|
4568 if (type->subtypes != NULL) |
|
4569 xmlSchemaBuildAContentModel(type->subtypes, ctxt, name); |
|
4570 break; |
|
4571 default: |
|
4572 xmlGenericError(xmlGenericErrorContext, |
|
4573 "Found unexpected type %d in %s content model\n", |
|
4574 type->type, name); |
|
4575 return; |
|
4576 } |
|
4577 } |
|
4578 |
|
4579 /** |
|
4580 * xmlSchemaBuildContentModel: |
|
4581 * @elem: the element |
|
4582 * @ctxt: the schema parser context |
|
4583 * @name: the element name |
|
4584 * |
|
4585 * Builds the content model of the element. |
|
4586 */ |
|
4587 static void |
|
4588 xmlSchemaBuildContentModel(xmlSchemaElementPtr elem, |
|
4589 xmlSchemaParserCtxtPtr ctxt, |
|
4590 const xmlChar * name) |
|
4591 { |
|
4592 xmlAutomataStatePtr start; |
|
4593 |
|
4594 if (elem->contModel != NULL) |
|
4595 return; |
|
4596 if (elem->subtypes == NULL) { |
|
4597 elem->contentType = XML_SCHEMA_CONTENT_ANY; |
|
4598 return; |
|
4599 } |
|
4600 if (elem->subtypes->type != XML_SCHEMA_TYPE_COMPLEX) |
|
4601 return; |
|
4602 if ((elem->subtypes->contentType == XML_SCHEMA_CONTENT_BASIC) || |
|
4603 (elem->subtypes->contentType == XML_SCHEMA_CONTENT_SIMPLE)) |
|
4604 return; |
|
4605 |
|
4606 #ifdef DEBUG_CONTENT |
|
4607 xmlGenericError(xmlGenericErrorContext, |
|
4608 "Building content model for %s\n", name); |
|
4609 #endif |
|
4610 |
|
4611 ctxt->am = xmlNewAutomata(); |
|
4612 if (ctxt->am == NULL) { |
|
4613 xmlGenericError(xmlGenericErrorContext, |
|
4614 "Cannot create automata for elem %s\n", name); |
|
4615 return; |
|
4616 } |
|
4617 start = ctxt->state = xmlAutomataGetInitState(ctxt->am); |
|
4618 xmlSchemaBuildAContentModel(elem->subtypes, ctxt, name); |
|
4619 xmlAutomataSetFinalState(ctxt->am, ctxt->state); |
|
4620 elem->contModel = xmlAutomataCompile(ctxt->am); |
|
4621 if (elem->contModel == NULL) { |
|
4622 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_INTERNAL, |
|
4623 "failed to compile %s content model\n", name, NULL); |
|
4624 } else if (xmlRegexpIsDeterminist(elem->contModel) != 1) { |
|
4625 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAS_ERR_NOTDETERMINIST, |
|
4626 "Content model of %s is not determinist:\n", name, |
|
4627 NULL); |
|
4628 } else { |
|
4629 #ifdef DEBUG_CONTENT_REGEXP |
|
4630 xmlGenericError(xmlGenericErrorContext, |
|
4631 "Content model of %s:\n", name); |
|
4632 xmlRegexpPrint(stderr, elem->contModel); |
|
4633 #endif |
|
4634 } |
|
4635 ctxt->state = NULL; |
|
4636 xmlFreeAutomata(ctxt->am); |
|
4637 ctxt->am = NULL; |
|
4638 } |
|
4639 |
|
4640 /** |
|
4641 * xmlSchemaRefFixupCallback: |
|
4642 * @elem: the schema element context |
|
4643 * @ctxt: the schema parser context |
|
4644 * |
|
4645 * Free the resources associated to the schema parser context |
|
4646 */ |
|
4647 static void |
|
4648 xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem, |
|
4649 xmlSchemaParserCtxtPtr ctxt, |
|
4650 const xmlChar * name, |
|
4651 const xmlChar * context ATTRIBUTE_UNUSED, |
|
4652 const xmlChar * namespace ATTRIBUTE_UNUSED) |
|
4653 { |
|
4654 if ((ctxt == NULL) || (elem == NULL)) |
|
4655 return; |
|
4656 if (elem->ref != NULL) { |
|
4657 xmlSchemaElementPtr elemDecl; |
|
4658 |
|
4659 if (elem->subtypes != NULL) { |
|
4660 xmlSchemaPErr(ctxt, elem->node, |
|
4661 XML_SCHEMAP_INVALID_REF_AND_SUBTYPE, |
|
4662 "Schemas: element %s have both ref and subtype\n", |
|
4663 name, NULL); |
|
4664 return; |
|
4665 } |
|
4666 elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0); |
|
4667 |
|
4668 if (elemDecl == NULL) { |
|
4669 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF, |
|
4670 "Schemas: element %s ref to %s not found\n", |
|
4671 name, elem->ref); |
|
4672 return; |
|
4673 } |
|
4674 elem->refDecl = elemDecl; |
|
4675 } else if (elem->namedType != NULL) { |
|
4676 xmlSchemaTypePtr typeDecl; |
|
4677 |
|
4678 if (elem->subtypes != NULL) { |
|
4679 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE, |
|
4680 "Schemas: element %s have both type and subtype\n", |
|
4681 name, NULL); |
|
4682 return; |
|
4683 } |
|
4684 typeDecl = xmlSchemaGetType(ctxt->schema, elem->namedType, |
|
4685 elem->namedTypeNs); |
|
4686 |
|
4687 if (typeDecl == NULL) { |
|
4688 xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE, |
|
4689 "Schemas: element %s type %s not found\n", name, |
|
4690 elem->namedType); |
|
4691 return; |
|
4692 } |
|
4693 elem->subtypes = typeDecl; |
|
4694 } |
|
4695 } |
|
4696 |
|
4697 /** |
|
4698 * xmlSchemaParseListRefFixup: |
|
4699 * @type: the schema type definition |
|
4700 * @ctxt: the schema parser context |
|
4701 * |
|
4702 * Fixup of the itemType reference of the list type. |
|
4703 */ |
|
4704 static void |
|
4705 xmlSchemaParseListRefFixup(xmlSchemaTypePtr type, xmlSchemaParserCtxtPtr ctxt) |
|
4706 { |
|
4707 const xmlChar *itemType, *namespace; |
|
4708 xmlSchemaTypePtr subtype; |
|
4709 |
|
4710 /* Handle the "itemType" attribute. */ |
|
4711 itemType = xmlGetQNameProp(ctxt, type->node, "itemType", &namespace); |
|
4712 if (itemType != NULL) { |
|
4713 /* Do not allow more that one item type. */ |
|
4714 if (type->subtypes != NULL) { |
|
4715 xmlSchemaPErr(ctxt, type->node, |
|
4716 XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE, |
|
4717 "List %s has more than one item type defined\n", |
|
4718 type->name, NULL); |
|
4719 } |
|
4720 subtype = xmlSchemaGetType(ctxt->schema, itemType, namespace); |
|
4721 if (subtype == NULL) { |
|
4722 xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_UNKNOWN_TYPE, |
|
4723 "List %s references an unknown item type: %s\n", |
|
4724 type->name, xmlSchemaGetProp(ctxt, type->node, |
|
4725 "itemType")); |
|
4726 } else |
|
4727 type->subtypes = subtype; |
|
4728 } |
|
4729 } |
|
4730 |
|
4731 /** |
|
4732 * xmlSchemaParseUnionRefCheck: |
|
4733 * @typeDecl: the schema type definition |
|
4734 * @ctxt: the schema parser context |
|
4735 * |
|
4736 * Checks the memberTypes references of the union type. |
|
4737 */ |
|
4738 static void |
|
4739 xmlSchemaParseUnionRefCheck(xmlSchemaTypePtr type, |
|
4740 xmlSchemaParserCtxtPtr ctxt) |
|
4741 { |
|
4742 const xmlChar *cur, *end, *prefix, *ncName, *namespace; |
|
4743 xmlChar *tmp; |
|
4744 xmlSchemaTypePtr subtype; |
|
4745 xmlNsPtr ns; |
|
4746 int len; |
|
4747 |
|
4748 if ((type->type != XML_SCHEMA_TYPE_UNION) || (type->ref == NULL)) |
|
4749 return; |
|
4750 |
|
4751 cur = type->ref; |
|
4752 do { |
|
4753 while (IS_BLANK_CH(*cur)) |
|
4754 cur++; |
|
4755 end = cur; |
|
4756 while ((*end != 0) && (!(IS_BLANK_CH(*end)))) |
|
4757 end++; |
|
4758 if (end == cur) |
|
4759 break; |
|
4760 tmp = xmlStrndup(cur, end - cur); |
|
4761 ncName = xmlSplitQName3(tmp, &len); |
|
4762 if (ncName != NULL) { |
|
4763 prefix = xmlDictLookup(ctxt->dict, tmp, len); |
|
4764 } else { |
|
4765 prefix = NULL; |
|
4766 ncName = tmp; |
|
4767 } |
|
4768 ns = xmlSearchNs(type->node->doc, type->node, prefix); |
|
4769 if (ns == NULL) { |
|
4770 if (prefix != NULL) { |
|
4771 xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_PREFIX_UNDEFINED, |
|
4772 "Union %s: the namespace prefix of member type " |
|
4773 "%s is undefined\n", |
|
4774 type->name, (const xmlChar *) tmp); |
|
4775 } |
|
4776 namespace = NULL; |
|
4777 } else { |
|
4778 namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
|
4779 } |
|
4780 /* Lookup the referenced type */ |
|
4781 subtype = xmlSchemaGetType(ctxt->schema, ncName, namespace); |
|
4782 if (subtype == NULL) { |
|
4783 xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, |
|
4784 "Union %s references an unknown member type %s\n", |
|
4785 type->name, (const xmlChar *) tmp); |
|
4786 } |
|
4787 xmlFree(tmp); |
|
4788 cur = end; |
|
4789 } while (*cur != 0); |
|
4790 } |
|
4791 |
|
4792 /** |
|
4793 * xmlSchemaTypeFixup: |
|
4794 * @typeDecl: the schema type definition |
|
4795 * @ctxt: the schema parser context |
|
4796 * |
|
4797 * Fixes the content model of the type. |
|
4798 */ |
|
4799 static void |
|
4800 xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl, |
|
4801 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) |
|
4802 { |
|
4803 if (typeDecl == NULL) |
|
4804 return; |
|
4805 if (name == NULL) |
|
4806 name = typeDecl->name; |
|
4807 if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) { |
|
4808 switch (typeDecl->type) { |
|
4809 case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{ |
|
4810 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); |
|
4811 if (typeDecl->subtypes != NULL) |
|
4812 typeDecl->contentType = |
|
4813 typeDecl->subtypes->contentType; |
|
4814 break; |
|
4815 } |
|
4816 case XML_SCHEMA_TYPE_RESTRICTION:{ |
|
4817 if (typeDecl->subtypes != NULL) |
|
4818 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); |
|
4819 |
|
4820 if (typeDecl->base != NULL) { |
|
4821 xmlSchemaTypePtr baseType; |
|
4822 |
|
4823 baseType = |
|
4824 xmlSchemaGetType(ctxt->schema, typeDecl->base, |
|
4825 typeDecl->baseNs); |
|
4826 if (baseType == NULL) { |
|
4827 xmlSchemaPErr(ctxt, typeDecl->node, |
|
4828 XML_SCHEMAP_UNKNOWN_BASE_TYPE, |
|
4829 "Schemas: type %s base type %s not found\n", |
|
4830 name, typeDecl->base); |
|
4831 } |
|
4832 typeDecl->baseType = baseType; |
|
4833 } |
|
4834 if (typeDecl->subtypes == NULL) |
|
4835 if (typeDecl->baseType != NULL) { |
|
4836 /* The base type might be not "type fixed" yet, |
|
4837 * so do it now. */ |
|
4838 if (typeDecl->baseType->contentType == |
|
4839 XML_SCHEMA_CONTENT_UNKNOWN) |
|
4840 xmlSchemaTypeFixup(typeDecl->baseType, ctxt, NULL); |
|
4841 typeDecl->contentType = |
|
4842 typeDecl->baseType->contentType; |
|
4843 } else |
|
4844 /* 1.1.1 */ |
|
4845 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4846 else if ((typeDecl->subtypes->subtypes == NULL) && |
|
4847 ((typeDecl->subtypes->type == |
|
4848 XML_SCHEMA_TYPE_ALL) |
|
4849 || (typeDecl->subtypes->type == |
|
4850 XML_SCHEMA_TYPE_SEQUENCE))) |
|
4851 /* 1.1.2 */ |
|
4852 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4853 else if ((typeDecl->subtypes->type == |
|
4854 XML_SCHEMA_TYPE_CHOICE) |
|
4855 && (typeDecl->subtypes->subtypes == NULL)) |
|
4856 /* 1.1.3 */ |
|
4857 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4858 else { |
|
4859 /* 1.2 and 2.X are applied at the other layer */ |
|
4860 typeDecl->contentType = |
|
4861 XML_SCHEMA_CONTENT_ELEMENTS; |
|
4862 } |
|
4863 break; |
|
4864 } |
|
4865 case XML_SCHEMA_TYPE_EXTENSION:{ |
|
4866 xmlSchemaContentType explicitContentType; |
|
4867 xmlSchemaTypePtr base; |
|
4868 |
|
4869 if (typeDecl->base != NULL) { |
|
4870 xmlSchemaTypePtr baseType; |
|
4871 |
|
4872 baseType = |
|
4873 xmlSchemaGetType(ctxt->schema, typeDecl->base, |
|
4874 typeDecl->baseNs); |
|
4875 if (baseType == NULL) { |
|
4876 xmlSchemaPErr(ctxt, typeDecl->node, |
|
4877 XML_SCHEMAP_UNKNOWN_BASE_TYPE, |
|
4878 "Schemas: type %s base type %s not found\n", |
|
4879 name, typeDecl->base); |
|
4880 } |
|
4881 typeDecl->baseType = baseType; |
|
4882 } |
|
4883 if (typeDecl->subtypes != NULL) |
|
4884 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); |
|
4885 |
|
4886 explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS; |
|
4887 if (typeDecl->subtypes == NULL) |
|
4888 /* 1.1.1 */ |
|
4889 explicitContentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4890 else if ((typeDecl->subtypes->subtypes == NULL) && |
|
4891 ((typeDecl->subtypes->type == |
|
4892 XML_SCHEMA_TYPE_ALL) |
|
4893 || (typeDecl->subtypes->type == |
|
4894 XML_SCHEMA_TYPE_SEQUENCE))) |
|
4895 /* 1.1.2 */ |
|
4896 explicitContentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4897 else if ((typeDecl->subtypes->type == |
|
4898 XML_SCHEMA_TYPE_CHOICE) |
|
4899 && (typeDecl->subtypes->subtypes == NULL)) |
|
4900 /* 1.1.3 */ |
|
4901 explicitContentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4902 |
|
4903 base = xmlSchemaGetType(ctxt->schema, typeDecl->base, |
|
4904 typeDecl->baseNs); |
|
4905 if (base == NULL) { |
|
4906 xmlSchemaPErr(ctxt, typeDecl->node, |
|
4907 XML_SCHEMAP_UNKNOWN_BASE_TYPE, |
|
4908 "Schemas: base type %s of type %s not found\n", |
|
4909 typeDecl->base, name); |
|
4910 return; |
|
4911 } |
|
4912 if (typeDecl->recurse) { |
|
4913 xmlSchemaPErr(ctxt, typeDecl->node, |
|
4914 XML_SCHEMAP_UNKNOWN_BASE_TYPE, |
|
4915 "Schemas: extension type %s is recursive\n", |
|
4916 name, NULL); |
|
4917 return; |
|
4918 } |
|
4919 typeDecl->recurse = 1; |
|
4920 xmlSchemaTypeFixup(base, ctxt, NULL); |
|
4921 typeDecl->recurse = 0; |
|
4922 if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) { |
|
4923 /* 2.1 */ |
|
4924 typeDecl->contentType = base->contentType; |
|
4925 } else if (base->contentType == |
|
4926 XML_SCHEMA_CONTENT_EMPTY) { |
|
4927 /* 2.2 imbitable ! */ |
|
4928 typeDecl->contentType = |
|
4929 XML_SCHEMA_CONTENT_ELEMENTS; |
|
4930 } else { |
|
4931 /* 2.3 imbitable pareil ! */ |
|
4932 typeDecl->contentType = |
|
4933 XML_SCHEMA_CONTENT_ELEMENTS; |
|
4934 } |
|
4935 break; |
|
4936 } |
|
4937 case XML_SCHEMA_TYPE_COMPLEX:{ |
|
4938 if (typeDecl->subtypes == NULL) { |
|
4939 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4940 |
|
4941 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) |
|
4942 typeDecl->contentType = |
|
4943 XML_SCHEMA_CONTENT_MIXED; |
|
4944 } else { |
|
4945 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) |
|
4946 typeDecl->contentType = |
|
4947 XML_SCHEMA_CONTENT_MIXED; |
|
4948 else { |
|
4949 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, |
|
4950 NULL); |
|
4951 if (typeDecl->subtypes != NULL) |
|
4952 typeDecl->contentType = |
|
4953 typeDecl->subtypes->contentType; |
|
4954 } |
|
4955 if (typeDecl->attributes == NULL) |
|
4956 typeDecl->attributes = |
|
4957 typeDecl->subtypes->attributes; |
|
4958 } |
|
4959 break; |
|
4960 } |
|
4961 case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{ |
|
4962 if (typeDecl->subtypes == NULL) { |
|
4963 typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; |
|
4964 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) |
|
4965 typeDecl->contentType = |
|
4966 XML_SCHEMA_CONTENT_MIXED; |
|
4967 } else { |
|
4968 if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) |
|
4969 typeDecl->contentType = |
|
4970 XML_SCHEMA_CONTENT_MIXED; |
|
4971 else { |
|
4972 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, |
|
4973 NULL); |
|
4974 if (typeDecl->subtypes != NULL) |
|
4975 typeDecl->contentType = |
|
4976 typeDecl->subtypes->contentType; |
|
4977 } |
|
4978 if (typeDecl->attributes == NULL) |
|
4979 typeDecl->attributes = |
|
4980 typeDecl->subtypes->attributes; |
|
4981 } |
|
4982 break; |
|
4983 } |
|
4984 case XML_SCHEMA_TYPE_SEQUENCE: |
|
4985 case XML_SCHEMA_TYPE_GROUP: |
|
4986 case XML_SCHEMA_TYPE_ALL: |
|
4987 case XML_SCHEMA_TYPE_CHOICE: |
|
4988 typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS; |
|
4989 break; |
|
4990 case XML_SCHEMA_TYPE_BASIC: |
|
4991 case XML_SCHEMA_TYPE_ANY: |
|
4992 case XML_SCHEMA_TYPE_FACET: |
|
4993 case XML_SCHEMA_TYPE_SIMPLE: |
|
4994 case XML_SCHEMA_TYPE_UR: |
|
4995 case XML_SCHEMA_TYPE_ELEMENT: |
|
4996 case XML_SCHEMA_TYPE_ATTRIBUTE: |
|
4997 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: |
|
4998 case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: |
|
4999 case XML_SCHEMA_TYPE_NOTATION: |
|
5000 case XML_SCHEMA_TYPE_LIST: |
|
5001 xmlSchemaParseListRefFixup(typeDecl, ctxt); |
|
5002 case XML_SCHEMA_TYPE_UNION: |
|
5003 xmlSchemaParseUnionRefCheck(typeDecl, ctxt); |
|
5004 case XML_SCHEMA_FACET_MININCLUSIVE: |
|
5005 case XML_SCHEMA_FACET_MINEXCLUSIVE: |
|
5006 case XML_SCHEMA_FACET_MAXINCLUSIVE: |
|
5007 case XML_SCHEMA_FACET_MAXEXCLUSIVE: |
|
5008 case XML_SCHEMA_FACET_TOTALDIGITS: |
|
5009 case XML_SCHEMA_FACET_FRACTIONDIGITS: |
|
5010 case XML_SCHEMA_FACET_PATTERN: |
|
5011 case XML_SCHEMA_FACET_ENUMERATION: |
|
5012 case XML_SCHEMA_FACET_WHITESPACE: |
|
5013 case XML_SCHEMA_FACET_LENGTH: |
|
5014 case XML_SCHEMA_FACET_MAXLENGTH: |
|
5015 case XML_SCHEMA_FACET_MINLENGTH: |
|
5016 typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE; |
|
5017 if (typeDecl->subtypes != NULL) |
|
5018 xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); |
|
5019 break; |
|
5020 } |
|
5021 } |
|
5022 #ifdef DEBUG_TYPE |
|
5023 if (typeDecl->node != NULL) { |
|
5024 xmlGenericError(xmlGenericErrorContext, |
|
5025 "Type of %s : %s:%d :", name, |
|
5026 typeDecl->node->doc->URL, |
|
5027 xmlGetLineNo(typeDecl->node)); |
|
5028 } else { |
|
5029 xmlGenericError(xmlGenericErrorContext, "Type of %s :", name); |
|
5030 } |
|
5031 switch (typeDecl->contentType) { |
|
5032 case XML_SCHEMA_CONTENT_SIMPLE: |
|
5033 xmlGenericError(xmlGenericErrorContext, "simple\n"); |
|
5034 break; |
|
5035 case XML_SCHEMA_CONTENT_ELEMENTS: |
|
5036 xmlGenericError(xmlGenericErrorContext, "elements\n"); |
|
5037 break; |
|
5038 case XML_SCHEMA_CONTENT_UNKNOWN: |
|
5039 xmlGenericError(xmlGenericErrorContext, "unknown !!!\n"); |
|
5040 break; |
|
5041 case XML_SCHEMA_CONTENT_EMPTY: |
|
5042 xmlGenericError(xmlGenericErrorContext, "empty\n"); |
|
5043 break; |
|
5044 case XML_SCHEMA_CONTENT_MIXED: |
|
5045 xmlGenericError(xmlGenericErrorContext, "mixed\n"); |
|
5046 break; |
|
5047 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: |
|
5048 xmlGenericError(xmlGenericErrorContext, "mixed or elems\n"); |
|
5049 break; |
|
5050 case XML_SCHEMA_CONTENT_BASIC: |
|
5051 xmlGenericError(xmlGenericErrorContext, "basic\n"); |
|
5052 break; |
|
5053 default: |
|
5054 xmlGenericError(xmlGenericErrorContext, |
|
5055 "not registered !!!\n"); |
|
5056 break; |
|
5057 } |
|
5058 #endif |
|
5059 } |
|
5060 |
|
5061 ///#if defined(LIBXML_SCHEMAS_ENABLED) |
|
5062 /** |
|
5063 * xmlSchemaCheckFacet: |
|
5064 * @facet: the facet |
|
5065 * @typeDecl: the schema type definition |
|
5066 * @ctxt: the schema parser context or NULL |
|
5067 * @name: name of the type |
|
5068 * |
|
5069 * Checks the default values types, especially for facets |
|
5070 * |
|
5071 * Returns 0 if okay or -1 in cae of error |
|
5072 */ |
|
5073 int |
|
5074 xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, |
|
5075 xmlSchemaTypePtr typeDecl, |
|
5076 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) |
|
5077 { |
|
5078 static xmlSchemaTypePtr nonNegativeIntegerType = NULL; |
|
5079 int ret = 0; |
|
5080 |
|
5081 if (nonNegativeIntegerType == NULL) { |
|
5082 nonNegativeIntegerType = |
|
5083 xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger", |
|
5084 xmlSchemaNs); |
|
5085 } |
|
5086 switch (facet->type) { |
|
5087 case XML_SCHEMA_FACET_MININCLUSIVE: |
|
5088 case XML_SCHEMA_FACET_MINEXCLUSIVE: |
|
5089 case XML_SCHEMA_FACET_MAXINCLUSIVE: |
|
5090 case XML_SCHEMA_FACET_MAXEXCLUSIVE:{ |
|
5091 /* |
|
5092 * Okay we need to validate the value |
|
5093 * at that point. |
|
5094 */ |
|
5095 xmlSchemaValidCtxtPtr vctxt; |
|
5096 |
|
5097 vctxt = xmlSchemaNewValidCtxt(NULL); |
|
5098 if (vctxt == NULL) |
|
5099 break; |
|
5100 xmlSchemaValidateSimpleValue(vctxt, typeDecl, |
|
5101 facet->value); |
|
5102 facet->val = vctxt->value; |
|
5103 vctxt->value = NULL; |
|
5104 if (facet->val == NULL) { |
|
5105 /* error code */ |
|
5106 if (ctxt != NULL) { |
|
5107 xmlSchemaPErr(ctxt, facet->node, |
|
5108 XML_SCHEMAP_INVALID_FACET, |
|
5109 "Schemas: type %s facet value %s invalid\n", |
|
5110 name, facet->value); |
|
5111 } |
|
5112 ret = -1; |
|
5113 } |
|
5114 xmlSchemaFreeValidCtxt(vctxt); |
|
5115 break; |
|
5116 } |
|
5117 case XML_SCHEMA_FACET_ENUMERATION:{ |
|
5118 /* |
|
5119 * Okay we need to validate the value |
|
5120 * at that point. |
|
5121 */ |
|
5122 xmlSchemaValidCtxtPtr vctxt; |
|
5123 int tmp; |
|
5124 |
|
5125 vctxt = xmlSchemaNewValidCtxt(NULL); |
|
5126 if (vctxt == NULL) |
|
5127 break; |
|
5128 tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl, |
|
5129 facet->value); |
|
5130 if (tmp != 0) { |
|
5131 if (ctxt != NULL) { |
|
5132 xmlSchemaPErr(ctxt, facet->node, |
|
5133 XML_SCHEMAP_INVALID_ENUM, |
|
5134 "Schemas: type %s enumeration value %s invalid\n", |
|
5135 name, facet->value); |
|
5136 } |
|
5137 ret = -1; |
|
5138 } |
|
5139 xmlSchemaFreeValidCtxt(vctxt); |
|
5140 break; |
|
5141 } |
|
5142 case XML_SCHEMA_FACET_PATTERN: |
|
5143 facet->regexp = xmlRegexpCompile(facet->value); |
|
5144 if (facet->regexp == NULL) { |
|
5145 xmlSchemaPErr(ctxt, typeDecl->node, |
|
5146 XML_SCHEMAP_REGEXP_INVALID, |
|
5147 "Schemas: type %s facet regexp %s invalid\n", |
|
5148 name, facet->value); |
|
5149 ret = -1; |
|
5150 } |
|
5151 break; |
|
5152 case XML_SCHEMA_FACET_TOTALDIGITS: |
|
5153 case XML_SCHEMA_FACET_FRACTIONDIGITS: |
|
5154 case XML_SCHEMA_FACET_LENGTH: |
|
5155 case XML_SCHEMA_FACET_MAXLENGTH: |
|
5156 case XML_SCHEMA_FACET_MINLENGTH:{ |
|
5157 int tmp; |
|
5158 |
|
5159 tmp = |
|
5160 xmlSchemaValidatePredefinedType(nonNegativeIntegerType, |
|
5161 facet->value, |
|
5162 &facet->val); |
|
5163 if (tmp != 0) { |
|
5164 /* error code */ |
|
5165 if (ctxt != NULL) { |
|
5166 xmlSchemaPErr(ctxt, facet->node, |
|
5167 XML_SCHEMAP_INVALID_FACET_VALUE, |
|
5168 "Schemas: type %s facet value %s invalid\n", |
|
5169 name, facet->value); |
|
5170 } |
|
5171 ret = -1; |
|
5172 } |
|
5173 break; |
|
5174 } |
|
5175 case XML_SCHEMA_FACET_WHITESPACE:{ |
|
5176 if (xmlStrEqual(facet->value, BAD_CAST "preserve")) { |
|
5177 facet->whitespace = XML_SCHEMAS_FACET_PRESERVE; |
|
5178 } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) { |
|
5179 facet->whitespace = XML_SCHEMAS_FACET_REPLACE; |
|
5180 } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) { |
|
5181 facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE; |
|
5182 } else { |
|
5183 if (ctxt != NULL) { |
|
5184 xmlSchemaPErr(ctxt, facet->node, |
|
5185 XML_SCHEMAP_INVALID_WHITE_SPACE, |
|
5186 "Schemas: type %s whiteSpace value %s invalid\n", |
|
5187 name, facet->value); |
|
5188 } |
|
5189 ret = -1; |
|
5190 } |
|
5191 } |
|
5192 default: |
|
5193 break; |
|
5194 } |
|
5195 return (ret); |
|
5196 } |
|
5197 |
|
5198 /** |
|
5199 * xmlSchemaCheckDefaults: |
|
5200 * @typeDecl: the schema type definition |
|
5201 * @ctxt: the schema parser context |
|
5202 * |
|
5203 * Checks the default values types, especially for facets |
|
5204 */ |
|
5205 static void |
|
5206 xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl, |
|
5207 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) |
|
5208 { |
|
5209 if (name == NULL) |
|
5210 name = typeDecl->name; |
|
5211 if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) { |
|
5212 if (typeDecl->facets != NULL) { |
|
5213 xmlSchemaFacetPtr facet = typeDecl->facets; |
|
5214 |
|
5215 while (facet != NULL) { |
|
5216 xmlSchemaCheckFacet(facet, typeDecl, ctxt, name); |
|
5217 facet = facet->next; |
|
5218 } |
|
5219 } |
|
5220 } |
|
5221 } |
|
5222 |
|
5223 /** |
|
5224 * xmlSchemaAttrGrpFixup: |
|
5225 * @attrgrpDecl: the schema attribute definition |
|
5226 * @ctxt: the schema parser context |
|
5227 * @name: the attribute name |
|
5228 * |
|
5229 * Fixes finish doing the computations on the attributes definitions |
|
5230 */ |
|
5231 static void |
|
5232 xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl, |
|
5233 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) |
|
5234 { |
|
5235 if (name == NULL) |
|
5236 name = attrgrpDecl->name; |
|
5237 if (attrgrpDecl->attributes != NULL) |
|
5238 return; |
|
5239 if (attrgrpDecl->ref != NULL) { |
|
5240 xmlSchemaAttributeGroupPtr ref; |
|
5241 |
|
5242 ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref, |
|
5243 attrgrpDecl->refNs); |
|
5244 if (ref == NULL) { |
|
5245 xmlSchemaPErr(ctxt, attrgrpDecl->node, |
|
5246 XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP, |
|
5247 "Schemas: attribute group %s reference %s not found\n", |
|
5248 name, attrgrpDecl->ref); |
|
5249 return; |
|
5250 } |
|
5251 xmlSchemaAttrGrpFixup(ref, ctxt, NULL); |
|
5252 attrgrpDecl->attributes = ref->attributes; |
|
5253 } else { |
|
5254 xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF, |
|
5255 "Schemas: attribute %s has no attributes nor reference\n", |
|
5256 name, NULL); |
|
5257 } |
|
5258 } |
|
5259 |
|
5260 /** |
|
5261 * xmlSchemaAttrFixup: |
|
5262 * @attrDecl: the schema attribute definition |
|
5263 * @ctxt: the schema parser context |
|
5264 * @name: the attribute name |
|
5265 * |
|
5266 * Fixes finish doing the computations on the attributes definitions |
|
5267 */ |
|
5268 static void |
|
5269 xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl, |
|
5270 xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) |
|
5271 { |
|
5272 if (name == NULL) |
|
5273 name = attrDecl->name; |
|
5274 if (attrDecl->subtypes != NULL) |
|
5275 return; |
|
5276 if (attrDecl->typeName != NULL) { |
|
5277 xmlSchemaTypePtr type; |
|
5278 |
|
5279 type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName, |
|
5280 attrDecl->typeNs); |
|
5281 if (type == NULL) { |
|
5282 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE, |
|
5283 "Schemas: attribute %s type %s not found\n", |
|
5284 name, attrDecl->typeName); |
|
5285 } |
|
5286 attrDecl->subtypes = type; |
|
5287 } else if (attrDecl->ref != NULL) { |
|
5288 xmlSchemaAttributePtr ref; |
|
5289 |
|
5290 ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref, |
|
5291 attrDecl->refNs); |
|
5292 if (ref == NULL) { |
|
5293 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF, |
|
5294 "Schemas: attribute %s reference %s not found\n", |
|
5295 name, attrDecl->ref); |
|
5296 return; |
|
5297 } |
|
5298 xmlSchemaAttrFixup(ref, ctxt, NULL); |
|
5299 attrDecl->subtypes = ref->subtypes; |
|
5300 } else if (attrDecl->type != XML_SCHEMA_TYPE_ANY_ATTRIBUTE) { |
|
5301 xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF, |
|
5302 "Schemas: attribute %s has no type nor reference\n", |
|
5303 name, NULL); |
|
5304 } |
|
5305 } |
|
5306 |
|
5307 /** |
|
5308 * xmlSchemaParse: |
|
5309 * @ctxt: a schema validation context |
|
5310 * |
|
5311 * parse a schema definition resource and build an internal |
|
5312 * XML Shema struture which can be used to validate instances. |
|
5313 * *WARNING* this interface is highly subject to change |
|
5314 * |
|
5315 * Returns the internal XML Schema structure built from the resource or |
|
5316 * NULL in case of error |
|
5317 */ |
|
5318 xmlSchemaPtr |
|
5319 xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt) |
|
5320 { |
|
5321 xmlSchemaPtr ret = NULL; |
|
5322 xmlDocPtr doc; |
|
5323 xmlNodePtr root; |
|
5324 int nberrors; |
|
5325 int preserve = 0; |
|
5326 |
|
5327 xmlSchemaInitTypes(); |
|
5328 |
|
5329 if (ctxt == NULL) |
|
5330 return (NULL); |
|
5331 |
|
5332 nberrors = ctxt->nberrors; |
|
5333 ctxt->nberrors = 0; |
|
5334 ctxt->counter = 0; |
|
5335 ctxt->container = NULL; |
|
5336 |
|
5337 /* |
|
5338 * First step is to parse the input document into an DOM/Infoset |
|
5339 */ |
|
5340 if (ctxt->URL != NULL) { |
|
5341 doc = xmlReadFile((const char *) ctxt->URL, NULL, |
|
5342 SCHEMAS_PARSE_OPTIONS); |
|
5343 if (doc == NULL) { |
|
5344 xmlSchemaPErr(ctxt, NULL, |
|
5345 XML_SCHEMAP_FAILED_LOAD, |
|
5346 "xmlSchemaParse: could not load %s\n", |
|
5347 ctxt->URL, NULL); |
|
5348 return (NULL); |
|
5349 } |
|
5350 } else if (ctxt->buffer != NULL) { |
|
5351 doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL, |
|
5352 SCHEMAS_PARSE_OPTIONS); |
|
5353 if (doc == NULL) { |
|
5354 xmlSchemaPErr(ctxt, NULL, |
|
5355 XML_SCHEMAP_FAILED_PARSE, |
|
5356 "xmlSchemaParse: could not parse\n", |
|
5357 NULL, NULL); |
|
5358 return (NULL); |
|
5359 } |
|
5360 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); |
|
5361 ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1); |
|
5362 } else if (ctxt->doc != NULL) { |
|
5363 doc = ctxt->doc; |
|
5364 preserve = 1; |
|
5365 } else { |
|
5366 xmlSchemaPErr(ctxt, NULL, |
|
5367 XML_SCHEMAP_NOTHING_TO_PARSE, |
|
5368 "xmlSchemaParse: could not parse\n", |
|
5369 NULL, NULL); |
|
5370 return (NULL); |
|
5371 } |
|
5372 |
|
5373 /* |
|
5374 * Then extract the root and Schema parse it |
|
5375 */ |
|
5376 root = xmlDocGetRootElement(doc); |
|
5377 if (root == NULL) { |
|
5378 xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
|
5379 XML_SCHEMAP_NOROOT, |
|
5380 "schemas has no root", NULL, NULL); |
|
5381 if (!preserve) { |
|
5382 xmlFreeDoc(doc); |
|
5383 } |
|
5384 return (NULL); |
|
5385 } |
|
5386 |
|
5387 /* |
|
5388 * Remove all the blank text nodes |
|
5389 */ |
|
5390 xmlSchemaCleanupDoc(ctxt, root); |
|
5391 |
|
5392 /* |
|
5393 * Then do the parsing for good |
|
5394 */ |
|
5395 ret = xmlSchemaParseSchema(ctxt, root); |
|
5396 if (ret == NULL) { |
|
5397 if (!preserve) { |
|
5398 xmlFreeDoc(doc); |
|
5399 } |
|
5400 return (NULL); |
|
5401 } |
|
5402 ret->doc = doc; |
|
5403 ret->preserve = preserve; |
|
5404 |
|
5405 /* |
|
5406 * Then fix all the references. |
|
5407 */ |
|
5408 ctxt->schema = ret; |
|
5409 xmlHashScanFull(ret->elemDecl, |
|
5410 (xmlHashScannerFull) xmlSchemaRefFixupCallback, ctxt); |
|
5411 |
|
5412 /* |
|
5413 * Then fixup all attributes declarations |
|
5414 */ |
|
5415 xmlHashScan(ret->attrDecl, (xmlHashScanner) xmlSchemaAttrFixup, ctxt); |
|
5416 |
|
5417 /* |
|
5418 * Then fixup all attributes group declarations |
|
5419 */ |
|
5420 xmlHashScan(ret->attrgrpDecl, (xmlHashScanner) xmlSchemaAttrGrpFixup, |
|
5421 ctxt); |
|
5422 |
|
5423 /* |
|
5424 * Then fixup all types properties |
|
5425 */ |
|
5426 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt); |
|
5427 |
|
5428 /* |
|
5429 * Then build the content model for all elements |
|
5430 */ |
|
5431 xmlHashScan(ret->elemDecl, |
|
5432 (xmlHashScanner) xmlSchemaBuildContentModel, ctxt); |
|
5433 |
|
5434 /* |
|
5435 * Then check the defaults part of the type like facets values |
|
5436 */ |
|
5437 xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaCheckDefaults, |
|
5438 ctxt); |
|
5439 |
|
5440 if (ctxt->nberrors != 0) { |
|
5441 xmlSchemaFree(ret); |
|
5442 ret = NULL; |
|
5443 } |
|
5444 return (ret); |
|
5445 } |
|
5446 |
|
5447 /** |
|
5448 * xmlSchemaSetParserErrors: |
|
5449 * @ctxt: a schema validation context |
|
5450 * @err: the error callback |
|
5451 * @warn: the warning callback |
|
5452 * @ctx: contextual data for the callbacks |
|
5453 * |
|
5454 * Set the callback functions used to handle errors for a validation context |
|
5455 */ |
|
5456 void |
|
5457 xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt, |
|
5458 xmlSchemaValidityErrorFunc err, |
|
5459 xmlSchemaValidityWarningFunc warn, void *ctx) |
|
5460 { |
|
5461 if (ctxt == NULL) |
|
5462 return; |
|
5463 ctxt->error = err; |
|
5464 ctxt->warning = warn; |
|
5465 ctxt->userData = ctx; |
|
5466 } |
|
5467 |
|
5468 /** |
|
5469 * xmlSchemaFacetTypeToString: |
|
5470 * @type: the facet type |
|
5471 * |
|
5472 * Convert the xmlSchemaTypeType to a char string. |
|
5473 * |
|
5474 * Returns the char string representation of the facet type if the |
|
5475 * type is a facet and an "Internal Error" string otherwise. |
|
5476 */ |
|
5477 static const char * |
|
5478 xmlSchemaFacetTypeToString(xmlSchemaTypeType type) |
|
5479 { |
|
5480 switch (type) { |
|
5481 case XML_SCHEMA_FACET_PATTERN: |
|
5482 return ("pattern"); |
|
5483 case XML_SCHEMA_FACET_MAXEXCLUSIVE: |
|
5484 return ("maxExclusive"); |
|
5485 case XML_SCHEMA_FACET_MAXINCLUSIVE: |
|
5486 return ("maxInclusive"); |
|
5487 case XML_SCHEMA_FACET_MINEXCLUSIVE: |
|
5488 return ("minExclusive"); |
|
5489 case XML_SCHEMA_FACET_MININCLUSIVE: |
|
5490 return ("minInclusive"); |
|
5491 case XML_SCHEMA_FACET_WHITESPACE: |
|
5492 return ("whiteSpace"); |
|
5493 case XML_SCHEMA_FACET_ENUMERATION: |
|
5494 return ("enumeration"); |
|
5495 case XML_SCHEMA_FACET_LENGTH: |
|
5496 return ("length"); |
|
5497 case XML_SCHEMA_FACET_MAXLENGTH: |
|
5498 return ("maxLength"); |
|
5499 case XML_SCHEMA_FACET_MINLENGTH: |
|
5500 return ("minLength"); |
|
5501 case XML_SCHEMA_FACET_TOTALDIGITS: |
|
5502 return ("totalDigits"); |
|
5503 case XML_SCHEMA_FACET_FRACTIONDIGITS: |
|
5504 return ("fractionDigits"); |
|
5505 default: |
|
5506 break; |
|
5507 } |
|
5508 return ("Internal Error"); |
|
5509 } |
|
5510 |
|
5511 /** |
|
5512 * xmlSchemaValidateFacetsInternal: |
|
5513 * @ctxt: a schema validation context |
|
5514 * @base: the base type |
|
5515 * @facets: the list of facets to check |
|
5516 * @value: the lexical repr of the value to validate |
|
5517 * @val: the precomputed value |
|
5518 * @fireErrors: if 0, only internal errors will be fired; |
|
5519 * otherwise all errors will be fired. |
|
5520 * |
|
5521 * Check a value against all facet conditions |
|
5522 * |
|
5523 * Returns 0 if the element is schemas valid, a positive error code |
|
5524 * number otherwise and -1 in case of internal or API error. |
|
5525 */ |
|
5526 static int |
|
5527 xmlSchemaValidateFacetsInternal(xmlSchemaValidCtxtPtr ctxt, |
|
5528 xmlSchemaTypePtr base, |
|
5529 xmlSchemaFacetPtr facets, |
|
5530 const xmlChar * value, int fireErrors) |
|
5531 { |
|
5532 int ret = 0; |
|
5533 int tmp = 0; |
|
5534 xmlSchemaTypeType type; |
|
5535 xmlSchemaFacetPtr facet = facets; |
|
5536 |
|
5537 while (facet != NULL) { |
|
5538 type = facet->type; |
|
5539 if (type == XML_SCHEMA_FACET_ENUMERATION) { |
|
5540 tmp = 1; |
|
5541 |
|
5542 while (facet != NULL) { |
|
5543 tmp = |
|
5544 xmlSchemaValidateFacet(base, facet, value, |
|
5545 ctxt->value); |
|
5546 if (tmp == 0) { |
|
5547 return 0; |
|
5548 } |
|
5549 facet = facet->next; |
|
5550 } |
|
5551 } else |
|
5552 tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value); |
|
5553 |
|
5554 if (tmp != 0) { |
|
5555 ret = tmp; |
|
5556 if (fireErrors) |
|
5557 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_FACET, |
|
5558 "Failed to validate type with facet %s\n", |
|
5559 (const xmlChar *) xmlSchemaFacetTypeToString(type), |
|
5560 NULL); |
|
5561 } |
|
5562 if (facet != NULL) |
|
5563 facet = facet->next; |
|
5564 } |
|
5565 return (ret); |
|
5566 } |
|
5567 |
|
5568 /** |
|
5569 * xmlSchemaValidateFacets: |
|
5570 * @ctxt: a schema validation context |
|
5571 * @base: the base type |
|
5572 * @facets: the list of facets to check |
|
5573 * @value: the lexical repr of the value to validate |
|
5574 * @val: the precomputed value |
|
5575 * |
|
5576 * Check a value against all facet conditions |
|
5577 * |
|
5578 * Returns 0 if the element is schemas valid, a positive error code |
|
5579 * number otherwise and -1 in case of internal or API error. |
|
5580 */ |
|
5581 static int |
|
5582 xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt, |
|
5583 xmlSchemaTypePtr base, |
|
5584 xmlSchemaFacetPtr facets, const xmlChar * value) |
|
5585 { |
|
5586 return(xmlSchemaValidateFacetsInternal(ctxt, base, facets, value, 1)); |
|
5587 } |
|
5588 |
|
5589 /************************************************************************ |
|
5590 * * |
|
5591 * Simple type validation * |
|
5592 * * |
|
5593 ************************************************************************/ |
|
5594 |
|
5595 /** |
|
5596 * xmlSchemaValidateSimpleValueUnion: |
|
5597 * @ctxt: a schema validation context |
|
5598 * @type: the type declaration |
|
5599 * @value: the value to validate |
|
5600 * |
|
5601 * Validates a value against a union. |
|
5602 * |
|
5603 * Returns 0 if the value is valid, a positive error code |
|
5604 * number otherwise and -1 in case of internal or API error. |
|
5605 */ |
|
5606 static int |
|
5607 xmlSchemaValidateSimpleValueUnion(xmlSchemaValidCtxtPtr ctxt, |
|
5608 xmlSchemaTypePtr type, const xmlChar * value) |
|
5609 { |
|
5610 int ret = 0; |
|
5611 const xmlChar *cur, *end, *prefix, *ncName; |
|
5612 xmlChar *tmp; |
|
5613 xmlSchemaTypePtr subtype; |
|
5614 xmlNsPtr ns; |
|
5615 int len; |
|
5616 |
|
5617 |
|
5618 /* Process referenced memberTypes. */ |
|
5619 cur = type->ref; |
|
5620 do { |
|
5621 while (IS_BLANK_CH(*cur)) |
|
5622 cur++; |
|
5623 end = cur; |
|
5624 while ((*end != 0) && (!(IS_BLANK_CH(*end)))) |
|
5625 end++; |
|
5626 if (end == cur) |
|
5627 break; |
|
5628 tmp = xmlStrndup(cur, end - cur); |
|
5629 ncName = xmlSplitQName3(tmp, &len); |
|
5630 if (ncName != NULL) { |
|
5631 prefix = xmlStrndup(tmp, len); |
|
5632 /* prefix = xmlDictLookup(ctxt->doc->dict, tmp, len); */ |
|
5633 } else { |
|
5634 prefix = NULL; |
|
5635 ncName = tmp; |
|
5636 } |
|
5637 /* We won't do additional checks here, |
|
5638 * since they have been performed during parsing. */ |
|
5639 ns = xmlSearchNs(type->node->doc, type->node, prefix); |
|
5640 /* namespace = xmlDictLookup(ctxt->doc->dict, ns->href, -1); */ |
|
5641 subtype = xmlSchemaGetType(ctxt->schema, ncName, ns->href); |
|
5642 if (tmp != NULL) |
|
5643 xmlFree(tmp); |
|
5644 if (prefix != NULL) |
|
5645 xmlFree((void *)prefix); |
|
5646 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0); |
|
5647 if ((ret == 0) || (ret == -1)) { |
|
5648 return (ret); |
|
5649 } |
|
5650 cur = end; |
|
5651 } while (*cur != 0); |
|
5652 |
|
5653 if (type->subtypes != NULL) { |
|
5654 subtype = type->subtypes; |
|
5655 do { |
|
5656 ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0); |
|
5657 if ((ret == 0) || (ret == -1)) { |
|
5658 return (ret); |
|
5659 } |
|
5660 subtype = subtype->next; |
|
5661 } while (subtype != NULL); |
|
5662 } |
|
5663 return (ret); |
|
5664 } |
|
5665 |
|
5666 /** |
|
5667 * xmlSchemaValidateSimpleValue: |
|
5668 * @ctxt: a schema validation context |
|
5669 * @type: the type declaration |
|
5670 * @value: the value to validate |
|
5671 * |
|
5672 * Validate a value against a simple type |
|
5673 * |
|
5674 * Returns 0 if the value is valid, a positive error code |
|
5675 * number otherwise and -1 in case of internal or API error. |
|
5676 */ |
|
5677 static int |
|
5678 xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt, |
|
5679 xmlSchemaTypePtr type, const xmlChar * value) |
|
5680 { |
|
5681 return (xmlSchemaValidateSimpleValueInternal(ctxt, type, value, 1)); |
|
5682 } |
|
5683 |
|
5684 /** |
|
5685 * xmlSchemaValidateSimpleValue: |
|
5686 * @ctxt: a schema validation context |
|
5687 * @type: the type declaration |
|
5688 * @value: the value to validate |
|
5689 * @fireErrors: if 0, only internal errors will be fired; |
|
5690 * otherwise all errors will be fired. |
|
5691 * |
|
5692 * Validate a value against a simple type |
|
5693 * |
|
5694 * Returns 0 if the value is valid, a positive error code |
|
5695 * number otherwise and -1 in case of internal or API error. |
|
5696 */ |
|
5697 static int |
|
5698 xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, |
|
5699 xmlSchemaTypePtr type, |
|
5700 const xmlChar * value, |
|
5701 int fireErrors) |
|
5702 { |
|
5703 int ret = 0; |
|
5704 |
|
5705 /* |
|
5706 * First normalize the value accordingly to Schema Datatype |
|
5707 * 4.3.6 whiteSpace definition of the whiteSpace facet of type |
|
5708 * |
|
5709 * Then check the normalized value against the lexical space of the |
|
5710 * type. |
|
5711 */ |
|
5712 if (type->type == XML_SCHEMA_TYPE_BASIC) { |
|
5713 if (ctxt->value != NULL) { |
|
5714 xmlSchemaFreeValue(ctxt->value); |
|
5715 ctxt->value = NULL; |
|
5716 } |
|
5717 ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value), |
|
5718 ctxt->cur); |
|
5719 if ((fireErrors) && (ret != 0)) { |
|
5720 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, |
|
5721 "Failed to validate basic type %s\n", |
|
5722 type->name, NULL); |
|
5723 } |
|
5724 } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) { |
|
5725 xmlSchemaTypePtr base; |
|
5726 xmlSchemaFacetPtr facet; |
|
5727 |
|
5728 base = type->baseType; |
|
5729 if (base != NULL) { |
|
5730 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, |
|
5731 value, fireErrors); |
|
5732 } else if (type->subtypes != NULL) { |
|
5733 TODO |
|
5734 } |
|
5735 |
|
5736 /* |
|
5737 * Do not validate facets or attributes when working on |
|
5738 * building the Schemas |
|
5739 */ |
|
5740 if (ctxt->schema != NULL) { |
|
5741 if (ret == 0) { |
|
5742 facet = type->facets; |
|
5743 ret = xmlSchemaValidateFacetsInternal(ctxt, base, facet, |
|
5744 value, fireErrors); |
|
5745 } |
|
5746 } |
|
5747 } else if (type->type == XML_SCHEMA_TYPE_SIMPLE) { |
|
5748 xmlSchemaTypePtr base; |
|
5749 |
|
5750 base = type->subtypes; |
|
5751 if (base != NULL) { |
|
5752 ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, |
|
5753 value, fireErrors); |
|
5754 } else { |
|
5755 TODO} |
|
5756 } else if (type->type == XML_SCHEMA_TYPE_LIST) { |
|
5757 xmlSchemaTypePtr base; |
|
5758 const xmlChar *cur, *end; |
|
5759 xmlChar *tmp; |
|
5760 int ret2; |
|
5761 |
|
5762 base = type->subtypes; |
|
5763 if (base == NULL) { |
|
5764 xmlSchemaVErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL, |
|
5765 "Internal: List type %s has no base type\n", |
|
5766 type->name, NULL); |
|
5767 return (-1); |
|
5768 } |
|
5769 cur = value; |
|
5770 do { |
|
5771 while (IS_BLANK_CH(*cur)) |
|
5772 cur++; |
|
5773 end = cur; |
|
5774 while ((*end != 0) && (!(IS_BLANK_CH(*end)))) |
|
5775 end++; |
|
5776 if (end == cur) |
|
5777 break; |
|
5778 tmp = xmlStrndup(cur, end - cur); |
|
5779 ret2 = xmlSchemaValidateSimpleValueInternal(ctxt, base, |
|
5780 tmp, fireErrors); |
|
5781 xmlFree(tmp); |
|
5782 if (ret2 != 0) |
|
5783 ret = 1; |
|
5784 cur = end; |
|
5785 } while (*cur != 0); |
|
5786 } else if (type->type == XML_SCHEMA_TYPE_UNION) { |
|
5787 ret = xmlSchemaValidateSimpleValueUnion(ctxt, type, value); |
|
5788 if ((fireErrors) && (ret != 0)) { |
|
5789 xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, |
|
5790 "Failed to validate type %s\n", type->name, NULL); |
|
5791 } |
|
5792 } else { |
|
5793 TODO |
|
5794 } |
|
5795 return (ret); |
|
5796 } |
|
5797 |
|
5798 /************************************************************************ |
|
5799 * * |
|
5800 * DOM Validation code * |
|
5801 * * |
|
5802 ************************************************************************/ |
|
5803 |
|
5804 static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, |
|
5805 xmlNodePtr node); |
|
5806 static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, |
|
5807 xmlNodePtr elem, |
|
5808 xmlSchemaAttributePtr attributes); |
|
5809 static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, |
|
5810 xmlNodePtr elem, |
|
5811 xmlSchemaElementPtr elemDecl, |
|
5812 xmlSchemaTypePtr type); |
|
5813 |
|
5814 /** |
|
5815 * xmlSchemaRegisterAttributes: |
|
5816 * @ctxt: a schema validation context |
|
5817 * @attrs: a list of attributes |
|
5818 * |
|
5819 * Register the list of attributes as the set to be validated on that element |
|
5820 * |
|
5821 * Returns -1 in case of error, 0 otherwise |
|
5822 */ |
|
5823 static int |
|
5824 xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs) |
|
5825 { |
|
5826 while (attrs != NULL) { |
|
5827 if ((attrs->ns != NULL) && |
|
5828 (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) { |
|
5829 attrs = attrs->next; |
|
5830 continue; |
|
5831 } |
|
5832 if (ctxt->attrNr >= ctxt->attrMax) { |
|
5833 xmlSchemaAttrStatePtr tmp; |
|
5834 |
|
5835 ctxt->attrMax *= 2; |
|
5836 tmp = (xmlSchemaAttrStatePtr) |
|
5837 xmlRealloc(ctxt->attr, ctxt->attrMax * |
|
5838 sizeof(xmlSchemaAttrState)); |
|
5839 if (tmp == NULL) { |
|
5840 xmlSchemaVErrMemory(ctxt, "registering attributes", NULL); |
|
5841 ctxt->attrMax /= 2; |
|
5842 return (-1); |
|
5843 } |
|
5844 ctxt->attr = tmp; |
|
5845 } |
|
5846 ctxt->attr[ctxt->attrNr].attr = attrs; |
|
5847 ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN; |
|
5848 ctxt->attrNr++; |
|
5849 attrs = attrs->next; |
|
5850 } |
|
5851 return (0); |
|
5852 } |
|
5853 |
|
5854 /** |
|
5855 * xmlSchemaCheckAttributes: |
|
5856 * @ctxt: a schema validation context |
|
5857 * @node: the node carrying it. |
|
5858 * |
|
5859 * Check that the registered set of attributes on the current node |
|
5860 * has been properly validated. |
|
5861 * |
|
5862 * Returns 0 if validity constraints are met, 1 otherwise. |
|
5863 */ |
|
5864 static int |
|
5865 xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
5866 { |
|
5867 int ret = 0; |
|
5868 int i; |
|
5869 |
|
5870 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) { |
|
5871 if (ctxt->attr[i].attr == NULL) |
|
5872 break; |
|
5873 if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) { |
|
5874 ret = 1; |
|
5875 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, |
|
5876 "Attribute %s on %s is unknown\n", |
|
5877 ctxt->attr[i].attr->name, node->name); |
|
5878 } |
|
5879 } |
|
5880 return (ret); |
|
5881 } |
|
5882 |
|
5883 #if 0 /* Not currently used - remove if ever needed */ |
|
5884 /** |
|
5885 * xmlSchemaValidateSimpleContent: |
|
5886 * @ctxt: a schema validation context |
|
5887 * @elem: an element |
|
5888 * @type: the type declaration |
|
5889 * |
|
5890 * Validate the content of an element expected to be a simple type |
|
5891 * |
|
5892 * Returns 0 if the element is schemas valid, a positive error code |
|
5893 * number otherwise and -1 in case of internal or API error. |
|
5894 */ |
|
5895 static int |
|
5896 xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt, |
|
5897 xmlNodePtr node ATTRIBUTE_UNUSED) |
|
5898 { |
|
5899 xmlNodePtr child; |
|
5900 xmlSchemaTypePtr type, base; |
|
5901 xmlChar *value; |
|
5902 int ret = 0; |
|
5903 |
|
5904 child = ctxt->node; |
|
5905 type = ctxt->type; |
|
5906 |
|
5907 /* |
|
5908 * Validation Rule: Element Locally Valid (Type): 3.1.3 |
|
5909 */ |
|
5910 value = xmlNodeGetContent(child); |
|
5911 /* xmlSchemaValidateSimpleValue(ctxt, type, value); */ |
|
5912 switch (type->type) { |
|
5913 case XML_SCHEMA_TYPE_RESTRICTION:{ |
|
5914 xmlSchemaFacetPtr facet; |
|
5915 |
|
5916 base = type->baseType; |
|
5917 if (base != NULL) { |
|
5918 ret = xmlSchemaValidateSimpleValue(ctxt, base, value); |
|
5919 } else { |
|
5920 TODO} |
|
5921 if (ret == 0) { |
|
5922 facet = type->facets; |
|
5923 ret = |
|
5924 xmlSchemaValidateFacets(ctxt, base, facet, value); |
|
5925 } |
|
5926 if ((ret == 0) && (type->attributes != NULL)) { |
|
5927 ret = xmlSchemaValidateAttributes(ctxt, node, |
|
5928 type->attributes); |
|
5929 } |
|
5930 break; |
|
5931 } |
|
5932 case XML_SCHEMA_TYPE_EXTENSION:{ |
|
5933 TODO |
|
5934 break; |
|
5935 } |
|
5936 default: |
|
5937 TODO |
|
5938 } |
|
5939 if (value != NULL) |
|
5940 xmlFree(value); |
|
5941 |
|
5942 return (ret); |
|
5943 } |
|
5944 #endif |
|
5945 |
|
5946 /** |
|
5947 * xmlSchemaValidateCheckNodeList |
|
5948 * @nodelist: the list of nodes |
|
5949 * |
|
5950 * Check the node list is only made of text nodes and entities pointing |
|
5951 * to text nodes |
|
5952 * |
|
5953 * Returns 1 if true, 0 if false and -1 in case of error |
|
5954 */ |
|
5955 static int |
|
5956 xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) |
|
5957 { |
|
5958 while (nodelist != NULL) { |
|
5959 if (nodelist->type == XML_ENTITY_REF_NODE) { |
|
5960 TODO /* implement recursion in the entity content */ |
|
5961 } |
|
5962 if ((nodelist->type != XML_TEXT_NODE) && |
|
5963 (nodelist->type != XML_COMMENT_NODE) && |
|
5964 (nodelist->type != XML_PI_NODE) && |
|
5965 (nodelist->type != XML_CDATA_SECTION_NODE)) { |
|
5966 return (0); |
|
5967 } |
|
5968 nodelist = nodelist->next; |
|
5969 } |
|
5970 return (1); |
|
5971 } |
|
5972 |
|
5973 /** |
|
5974 * xmlSchemaSkipIgnored: |
|
5975 * @ctxt: a schema validation context |
|
5976 * @type: the current type context |
|
5977 * @node: the top node. |
|
5978 * |
|
5979 * Skip ignorable nodes in that context |
|
5980 * |
|
5981 * Returns the new sibling |
|
5982 * number otherwise and -1 in case of internal or API error. |
|
5983 */ |
|
5984 static xmlNodePtr |
|
5985 xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED, |
|
5986 xmlSchemaTypePtr type, xmlNodePtr node) |
|
5987 { |
|
5988 int mixed = 0; |
|
5989 |
|
5990 /* |
|
5991 * TODO complete and handle entities |
|
5992 */ |
|
5993 mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) || |
|
5994 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS)); |
|
5995 while ((node != NULL) && |
|
5996 ((node->type == XML_COMMENT_NODE) || |
|
5997 ((mixed == 1) && (node->type == XML_TEXT_NODE)) || |
|
5998 (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) && |
|
5999 (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) { |
|
6000 node = node->next; |
|
6001 } |
|
6002 return (node); |
|
6003 } |
|
6004 |
|
6005 /** |
|
6006 * xmlSchemaValidateCallback: |
|
6007 * @ctxt: a schema validation context |
|
6008 * @name: the name of the element detected (might be NULL) |
|
6009 * @type: the type |
|
6010 * |
|
6011 * A transition has been made in the automata associated to an element |
|
6012 * content model |
|
6013 */ |
|
6014 static void |
|
6015 xmlSchemaValidateCallback(xmlSchemaValidCtxtPtr ctxt, |
|
6016 const xmlChar * name ATTRIBUTE_UNUSED, |
|
6017 xmlSchemaTypePtr type, xmlNodePtr node) |
|
6018 { |
|
6019 xmlSchemaTypePtr oldtype = ctxt->type; |
|
6020 xmlNodePtr oldnode = ctxt->node; |
|
6021 |
|
6022 #ifdef DEBUG_CONTENT |
|
6023 xmlGenericError(xmlGenericErrorContext, |
|
6024 "xmlSchemaValidateCallback: %s, %s, %s\n", |
|
6025 name, type->name, node->name); |
|
6026 #endif |
|
6027 ctxt->type = type; |
|
6028 ctxt->node = node; |
|
6029 xmlSchemaValidateContent(ctxt, node); |
|
6030 ctxt->type = oldtype; |
|
6031 ctxt->node = oldnode; |
|
6032 } |
|
6033 |
|
6034 |
|
6035 #if 0 |
|
6036 |
|
6037 /** |
|
6038 * xmlSchemaValidateSimpleRestrictionType: |
|
6039 * @ctxt: a schema validation context |
|
6040 * @node: the top node. |
|
6041 * |
|
6042 * Validate the content of a restriction type. |
|
6043 * |
|
6044 * Returns 0 if the element is schemas valid, a positive error code |
|
6045 * number otherwise and -1 in case of internal or API error. |
|
6046 */ |
|
6047 static int |
|
6048 xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt, |
|
6049 xmlNodePtr node) |
|
6050 { |
|
6051 xmlNodePtr child; |
|
6052 xmlSchemaTypePtr type; |
|
6053 int ret; |
|
6054 |
|
6055 child = ctxt->node; |
|
6056 type = ctxt->type; |
|
6057 |
|
6058 if ((ctxt == NULL) || (type == NULL)) { |
|
6059 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6060 "Internal error: xmlSchemaValidateSimpleRestrictionType %s\n", |
|
6061 node->name, NULL); |
|
6062 return (-1); |
|
6063 } |
|
6064 /* |
|
6065 * Only text and text based entities references shall be found there |
|
6066 */ |
|
6067 ret = xmlSchemaValidateCheckNodeList(child); |
|
6068 if (ret < 0) { |
|
6069 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6070 "Internal error: xmlSchemaValidateSimpleType %s content\n", |
|
6071 node->name, NULL); |
|
6072 return (-1); |
|
6073 } else if (ret == 0) { |
|
6074 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, |
|
6075 "Element %s content is not a simple type\n", |
|
6076 node->name, NULL); |
|
6077 return (-1); |
|
6078 } |
|
6079 ctxt->type = type->subtypes; |
|
6080 xmlSchemaValidateContent(ctxt, node); |
|
6081 ctxt->type = type; |
|
6082 return (ret); |
|
6083 } |
|
6084 #endif |
|
6085 |
|
6086 /** |
|
6087 * xmlSchemaValidateSimpleType: |
|
6088 * @ctxt: a schema validation context |
|
6089 * @node: the top node. |
|
6090 * |
|
6091 * Validate the content of an simple type. |
|
6092 * |
|
6093 * Returns 0 if the element is schemas valid, a positive error code |
|
6094 * number otherwise and -1 in case of internal or API error. |
|
6095 */ |
|
6096 static int |
|
6097 xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
6098 { |
|
6099 xmlNodePtr child; |
|
6100 xmlSchemaTypePtr type, base, variety; |
|
6101 xmlAttrPtr attr; |
|
6102 int ret; |
|
6103 xmlChar *value; |
|
6104 |
|
6105 |
|
6106 child = ctxt->node; |
|
6107 type = ctxt->type; |
|
6108 |
|
6109 if ((ctxt == NULL) || (type == NULL)) { |
|
6110 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6111 "Internal error: xmlSchemaValidateSimpleType %s\n", |
|
6112 node->name, NULL); |
|
6113 return (-1); |
|
6114 } |
|
6115 /* |
|
6116 * Only text and text based entities references shall be found there |
|
6117 */ |
|
6118 ret = xmlSchemaValidateCheckNodeList(child); |
|
6119 if (ret < 0) { |
|
6120 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6121 "Internal error: xmlSchemaValidateSimpleType %s content\n", |
|
6122 node->name, NULL); |
|
6123 return (-1); |
|
6124 } else if (ret == 0) { |
|
6125 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTSIMPLE, |
|
6126 "Element %s content is not a simple type\n", |
|
6127 node->name, NULL); |
|
6128 return (-1); |
|
6129 } |
|
6130 /* |
|
6131 * Validation Rule: Element Locally Valid (Type): 3.1.1 |
|
6132 */ |
|
6133 |
|
6134 attr = node->properties; |
|
6135 while (attr != NULL) { |
|
6136 if ((attr->ns == NULL) || |
|
6137 (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) || |
|
6138 ((!xmlStrEqual(attr->name, BAD_CAST "type")) && |
|
6139 (!xmlStrEqual(attr->name, BAD_CAST "nil")) && |
|
6140 (!xmlStrEqual(attr->name, BAD_CAST "schemasLocation")) && |
|
6141 (!xmlStrEqual |
|
6142 (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) { |
|
6143 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDATTR, |
|
6144 "Element %s: attribute %s should not be present\n", |
|
6145 node->name, attr->name); |
|
6146 return (ctxt->err); |
|
6147 } |
|
6148 } |
|
6149 /* TODO: |
|
6150 * If {variety} is ·atomic· then the {variety} of {base type definition} |
|
6151 * must be ·atomic·. |
|
6152 * If {variety} is ·list· then the {variety} of {item type definition} |
|
6153 * must be either ·atomic· or ·union·. |
|
6154 * If {variety} is ·union· then {member type definitions} must be a list |
|
6155 * of datatype definitions. |
|
6156 */ |
|
6157 if (type->subtypes == NULL) { |
|
6158 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6159 "Internal error: xmlSchemaValidateSimpleType; " |
|
6160 "simple type %s does not define a variety\n", |
|
6161 node->name, NULL); |
|
6162 return (ctxt->err); |
|
6163 } |
|
6164 /* Varieties: Restriction or List or Union. */ |
|
6165 variety = type->subtypes; |
|
6166 ctxt->type = variety; |
|
6167 value = xmlNodeGetContent(child); |
|
6168 switch (variety->type) { |
|
6169 case XML_SCHEMA_TYPE_RESTRICTION:{ |
|
6170 xmlSchemaFacetPtr facet; |
|
6171 |
|
6172 base = variety->baseType; |
|
6173 if (base != NULL) { |
|
6174 ret = xmlSchemaValidateSimpleValue(ctxt, base, value); |
|
6175 } else { |
|
6176 TODO} |
|
6177 if (ret == 0) { |
|
6178 facet = variety->facets; |
|
6179 ret = |
|
6180 xmlSchemaValidateFacets(ctxt, base, facet, value); |
|
6181 } |
|
6182 if ((ret == 0) && (variety->attributes != NULL)) { |
|
6183 ret = xmlSchemaValidateAttributes(ctxt, node, |
|
6184 variety->attributes); |
|
6185 } |
|
6186 break; |
|
6187 } |
|
6188 case XML_SCHEMA_TYPE_LIST: |
|
6189 case XML_SCHEMA_TYPE_UNION: { |
|
6190 ret = xmlSchemaValidateSimpleValue(ctxt, variety, value); |
|
6191 break; |
|
6192 } |
|
6193 default:{ |
|
6194 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6195 "Internal error: xmlSchemaValidateSimpleType; " |
|
6196 "simple type %s defines unknown content: %s\n", |
|
6197 variety->name, NULL); |
|
6198 ret = ctxt->err; |
|
6199 } |
|
6200 } |
|
6201 if (value != NULL) |
|
6202 xmlFree(value); |
|
6203 |
|
6204 /* This was removed, since a simple content is not a content of a |
|
6205 * simple type, but of a complex type. |
|
6206 * ret = xmlSchemaValidateSimpleContent(ctxt, node); |
|
6207 */ |
|
6208 ctxt->type = type; |
|
6209 return (ret); |
|
6210 } |
|
6211 |
|
6212 /** |
|
6213 * xmlSchemaValidateElementType: |
|
6214 * @ctxt: a schema validation context |
|
6215 * @node: the top node. |
|
6216 * |
|
6217 * Validate the content of an element type. |
|
6218 * Validation Rule: Element Locally Valid (Complex Type) |
|
6219 * |
|
6220 * Returns 0 if the element is schemas valid, a positive error code |
|
6221 * number otherwise and -1 in case of internal or API error. |
|
6222 */ |
|
6223 static int |
|
6224 xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
6225 { |
|
6226 xmlNodePtr child; |
|
6227 xmlSchemaTypePtr type; |
|
6228 xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */ |
|
6229 xmlSchemaElementPtr decl; |
|
6230 int ret, attrBase; |
|
6231 |
|
6232 oldregexp = ctxt->regexp; |
|
6233 |
|
6234 child = ctxt->node; |
|
6235 type = ctxt->type; |
|
6236 |
|
6237 if ((ctxt == NULL) || (type == NULL)) { |
|
6238 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6239 "Internal error: xmlSchemaValidateElementType\n", |
|
6240 node->name, NULL); |
|
6241 return (-1); |
|
6242 } |
|
6243 if (child == NULL) { |
|
6244 if (type->minOccurs > 0) { |
|
6245 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, |
|
6246 "Element %s: missing child %s\n", |
|
6247 node->name, type->name); |
|
6248 } |
|
6249 return (ctxt->err); |
|
6250 } |
|
6251 |
|
6252 /* |
|
6253 * Verify the element matches |
|
6254 */ |
|
6255 if (!xmlStrEqual(child->name, type->name)) { |
|
6256 xmlSchemaVErr3(ctxt, node, XML_SCHEMAS_ERR_WRONGELEM, |
|
6257 "Element %s: missing child %s found %s\n", |
|
6258 node->name, type->name, child->name); |
|
6259 return (ctxt->err); |
|
6260 } |
|
6261 /* |
|
6262 * Verify the attributes |
|
6263 */ |
|
6264 attrBase = ctxt->attrBase; |
|
6265 ctxt->attrBase = ctxt->attrNr; |
|
6266 xmlSchemaRegisterAttributes(ctxt, child->properties); |
|
6267 xmlSchemaValidateAttributes(ctxt, child, type->attributes); |
|
6268 /* |
|
6269 * Verify the element content recursively |
|
6270 */ |
|
6271 decl = (xmlSchemaElementPtr) type; |
|
6272 oldregexp = ctxt->regexp; |
|
6273 if (decl->contModel != NULL) { |
|
6274 ctxt->regexp = xmlRegNewExecCtxt(decl->contModel, |
|
6275 (xmlRegExecCallbacks) |
|
6276 xmlSchemaValidateCallback, ctxt); |
|
6277 #ifdef DEBUG_AUTOMATA |
|
6278 xmlGenericError(xmlGenericErrorContext, "====> %s\n", node->name); |
|
6279 #endif |
|
6280 } |
|
6281 xmlSchemaValidateType(ctxt, child, (xmlSchemaElementPtr) type, |
|
6282 type->subtypes); |
|
6283 |
|
6284 if (decl->contModel != NULL) { |
|
6285 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL); |
|
6286 #ifdef DEBUG_AUTOMATA |
|
6287 xmlGenericError(xmlGenericErrorContext, |
|
6288 "====> %s : %d\n", node->name, ret); |
|
6289 #endif |
|
6290 if (ret == 0) { |
|
6291 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, |
|
6292 "Element %s content check failed\n", |
|
6293 node->name, NULL); |
|
6294 } else if (ret < 0) { |
|
6295 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ELEMCONT, |
|
6296 "Element %s content check failure\n", |
|
6297 node->name, NULL); |
|
6298 #ifdef DEBUG_CONTENT |
|
6299 } else { |
|
6300 xmlGenericError(xmlGenericErrorContext, |
|
6301 "Element %s content check succeeded\n", |
|
6302 node->name); |
|
6303 |
|
6304 #endif |
|
6305 } |
|
6306 xmlRegFreeExecCtxt(ctxt->regexp); |
|
6307 } |
|
6308 /* |
|
6309 * Verify that all attributes were Schemas-validated |
|
6310 */ |
|
6311 xmlSchemaCheckAttributes(ctxt, node); |
|
6312 ctxt->attrNr = ctxt->attrBase; |
|
6313 ctxt->attrBase = attrBase; |
|
6314 |
|
6315 ctxt->regexp = oldregexp; |
|
6316 |
|
6317 ctxt->node = child; |
|
6318 ctxt->type = type; |
|
6319 return (ctxt->err); |
|
6320 } |
|
6321 |
|
6322 /** |
|
6323 * xmlSchemaValidateBasicType: |
|
6324 * @ctxt: a schema validation context |
|
6325 * @node: the top node. |
|
6326 * |
|
6327 * Validate the content of an element expected to be a basic type type |
|
6328 * |
|
6329 * Returns 0 if the element is schemas valid, a positive error code |
|
6330 * number otherwise and -1 in case of internal or API error. |
|
6331 */ |
|
6332 static int |
|
6333 xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
6334 { |
|
6335 int ret; |
|
6336 xmlNodePtr child, cur; |
|
6337 xmlSchemaTypePtr type; |
|
6338 xmlChar *value; /* lexical representation */ |
|
6339 |
|
6340 child = ctxt->node; |
|
6341 type = ctxt->type; |
|
6342 |
|
6343 if ((ctxt == NULL) || (type == NULL)) { |
|
6344 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6345 "Internal error: xmlSchemaValidateBasicType\n", |
|
6346 node->name, NULL); |
|
6347 return (-1); |
|
6348 } |
|
6349 /* |
|
6350 * First check the content model of the node. |
|
6351 */ |
|
6352 cur = child; |
|
6353 while (cur != NULL) { |
|
6354 switch (cur->type) { |
|
6355 case XML_TEXT_NODE: |
|
6356 case XML_CDATA_SECTION_NODE: |
|
6357 case XML_PI_NODE: |
|
6358 case XML_COMMENT_NODE: |
|
6359 case XML_XINCLUDE_START: |
|
6360 case XML_XINCLUDE_END: |
|
6361 break; |
|
6362 case XML_ENTITY_REF_NODE: |
|
6363 case XML_ENTITY_NODE: |
|
6364 TODO break; |
|
6365 case XML_ELEMENT_NODE: |
|
6366 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, |
|
6367 "Element %s: child %s should not be present\n", |
|
6368 node->name, cur->name); |
|
6369 return (ctxt->err); |
|
6370 case XML_ATTRIBUTE_NODE: |
|
6371 case XML_DOCUMENT_NODE: |
|
6372 case XML_DOCUMENT_TYPE_NODE: |
|
6373 case XML_DOCUMENT_FRAG_NODE: |
|
6374 case XML_NOTATION_NODE: |
|
6375 case XML_HTML_DOCUMENT_NODE: |
|
6376 case XML_DTD_NODE: |
|
6377 case XML_ELEMENT_DECL: |
|
6378 case XML_ATTRIBUTE_DECL: |
|
6379 case XML_ENTITY_DECL: |
|
6380 case XML_NAMESPACE_DECL: |
|
6381 #ifdef LIBXML_DOCB_ENABLED |
|
6382 case XML_DOCB_DOCUMENT_NODE: |
|
6383 #endif |
|
6384 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INVALIDELEM, |
|
6385 "Element %s: node type of node unexpected here\n", |
|
6386 node->name, NULL); |
|
6387 return (ctxt->err); |
|
6388 } |
|
6389 cur = cur->next; |
|
6390 } |
|
6391 if (child == NULL) |
|
6392 value = NULL; |
|
6393 else |
|
6394 value = xmlNodeGetContent(child->parent); |
|
6395 |
|
6396 if (ctxt->value != NULL) { |
|
6397 xmlSchemaFreeValue(ctxt->value); |
|
6398 ctxt->value = NULL; |
|
6399 } |
|
6400 ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value)); |
|
6401 if (value != NULL) |
|
6402 xmlFree(value); |
|
6403 if (ret != 0) { |
|
6404 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_VALUE, |
|
6405 "Element %s: failed to validate basic type %s\n", |
|
6406 node->name, type->name); |
|
6407 } |
|
6408 return (ret); |
|
6409 } |
|
6410 |
|
6411 /** |
|
6412 * xmlSchemaValidateComplexType: |
|
6413 * @ctxt: a schema validation context |
|
6414 * @node: the top node. |
|
6415 * |
|
6416 * Validate the content of an element expected to be a complex type type |
|
6417 * xmlschema-1.html#cvc-complex-type |
|
6418 * Validation Rule: Element Locally Valid (Complex Type) |
|
6419 * |
|
6420 * Returns 0 if the element is schemas valid, a positive error code |
|
6421 * number otherwise and -1 in case of internal or API error. |
|
6422 */ |
|
6423 static int |
|
6424 xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
6425 { |
|
6426 xmlNodePtr child; |
|
6427 xmlSchemaTypePtr type, subtype; |
|
6428 int ret; |
|
6429 |
|
6430 child = ctxt->node; |
|
6431 type = ctxt->type; |
|
6432 ctxt->cur = node; |
|
6433 |
|
6434 switch (type->contentType) { |
|
6435 case XML_SCHEMA_CONTENT_EMPTY: |
|
6436 if (type->baseType != NULL) { |
|
6437 } else if (child != NULL) { |
|
6438 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, |
|
6439 "Element %s is supposed to be empty\n", |
|
6440 node->name, NULL); |
|
6441 } |
|
6442 if (type->attributes != NULL) { |
|
6443 xmlSchemaValidateAttributes(ctxt, node, type->attributes); |
|
6444 } |
|
6445 subtype = type->subtypes; |
|
6446 while (subtype != NULL) { |
|
6447 ctxt->type = subtype; |
|
6448 xmlSchemaValidateComplexType(ctxt, node); |
|
6449 subtype = subtype->next; |
|
6450 } |
|
6451 break; |
|
6452 case XML_SCHEMA_CONTENT_ELEMENTS: |
|
6453 case XML_SCHEMA_CONTENT_MIXED: |
|
6454 case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: |
|
6455 /* |
|
6456 * Skip ignorable nodes in that context |
|
6457 */ |
|
6458 child = xmlSchemaSkipIgnored(ctxt, type, child); |
|
6459 while (child != NULL) { |
|
6460 if (child->type == XML_ELEMENT_NODE) { |
|
6461 ret = xmlRegExecPushString(ctxt->regexp, |
|
6462 child->name, child); |
|
6463 #ifdef DEBUG_AUTOMATA |
|
6464 if (ret < 0) |
|
6465 xmlGenericError(xmlGenericErrorContext, |
|
6466 " --> %s Error\n", child->name); |
|
6467 else |
|
6468 xmlGenericError(xmlGenericErrorContext, |
|
6469 " --> %s\n", child->name); |
|
6470 #endif |
|
6471 } |
|
6472 child = child->next; |
|
6473 /* |
|
6474 * Skip ignorable nodes in that context |
|
6475 */ |
|
6476 child = xmlSchemaSkipIgnored(ctxt, type, child); |
|
6477 } |
|
6478 if (((type->contentType == XML_SCHEMA_CONTENT_MIXED) || |
|
6479 (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS)) && |
|
6480 (type->subtypes != NULL)) { |
|
6481 TODO |
|
6482 } |
|
6483 |
|
6484 |
|
6485 if (type->attributes != NULL) { |
|
6486 xmlSchemaValidateAttributes(ctxt, node, type->attributes); |
|
6487 } |
|
6488 break; |
|
6489 case XML_SCHEMA_CONTENT_BASIC:{ |
|
6490 if (type->subtypes != NULL) { |
|
6491 ctxt->type = type->subtypes; |
|
6492 xmlSchemaValidateComplexType(ctxt, node); |
|
6493 } |
|
6494 if (type->baseType != NULL) { |
|
6495 ctxt->type = type->baseType; |
|
6496 if (type->baseType->type == XML_SCHEMA_TYPE_BASIC) |
|
6497 xmlSchemaValidateBasicType(ctxt, node); |
|
6498 else if (type->baseType->type == XML_SCHEMA_TYPE_COMPLEX) |
|
6499 xmlSchemaValidateComplexType(ctxt, node); |
|
6500 else if (type->baseType->type == XML_SCHEMA_TYPE_SIMPLE) |
|
6501 xmlSchemaValidateSimpleType(ctxt, node); |
|
6502 else |
|
6503 xmlGenericError(xmlGenericErrorContext, |
|
6504 "unexpected content type of base: %d\n", |
|
6505 type->contentType); |
|
6506 |
|
6507 } |
|
6508 if (type->attributes != NULL) { |
|
6509 xmlSchemaValidateAttributes(ctxt, node, |
|
6510 type->attributes); |
|
6511 } |
|
6512 ctxt->type = type; |
|
6513 break; |
|
6514 } |
|
6515 case XML_SCHEMA_CONTENT_SIMPLE:{ |
|
6516 if (type->subtypes != NULL) { |
|
6517 ctxt->type = type->subtypes; |
|
6518 xmlSchemaValidateComplexType(ctxt, node); |
|
6519 } |
|
6520 if (type->baseType != NULL) { |
|
6521 ctxt->type = type->baseType; |
|
6522 xmlSchemaValidateComplexType(ctxt, node); |
|
6523 } |
|
6524 if (type->attributes != NULL) { |
|
6525 xmlSchemaValidateAttributes(ctxt, node, |
|
6526 type->attributes); |
|
6527 } |
|
6528 ctxt->type = type; |
|
6529 break; |
|
6530 } |
|
6531 default: |
|
6532 TODO xmlGenericError(xmlGenericErrorContext, |
|
6533 "unimplemented content type %d\n", |
|
6534 type->contentType); |
|
6535 } |
|
6536 return (ctxt->err); |
|
6537 } |
|
6538 |
|
6539 /** |
|
6540 * xmlSchemaValidateContent: |
|
6541 * @ctxt: a schema validation context |
|
6542 * @elem: an element |
|
6543 * @type: the type declaration |
|
6544 * |
|
6545 * Validate the content of an element against the type. |
|
6546 * |
|
6547 * Returns 0 if the element is schemas valid, a positive error code |
|
6548 * number otherwise and -1 in case of internal or API error. |
|
6549 */ |
|
6550 static int |
|
6551 xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) |
|
6552 { |
|
6553 xmlNodePtr child; |
|
6554 xmlSchemaTypePtr type; |
|
6555 |
|
6556 child = ctxt->node; |
|
6557 type = ctxt->type; |
|
6558 ctxt->cur = node; |
|
6559 |
|
6560 xmlSchemaValidateAttributes(ctxt, node, type->attributes); |
|
6561 ctxt->cur = node; |
|
6562 |
|
6563 switch (type->type) { |
|
6564 case XML_SCHEMA_TYPE_ANY: |
|
6565 /* Any type will do it, fine */ |
|
6566 TODO /* handle recursivity */ |
|
6567 break; |
|
6568 case XML_SCHEMA_TYPE_COMPLEX: |
|
6569 xmlSchemaValidateComplexType(ctxt, node); |
|
6570 break; |
|
6571 case XML_SCHEMA_TYPE_ELEMENT:{ |
|
6572 xmlSchemaElementPtr decl = (xmlSchemaElementPtr) type; |
|
6573 |
|
6574 /* |
|
6575 * Handle element reference here |
|
6576 */ |
|
6577 if (decl->ref != NULL) { |
|
6578 if (decl->refDecl == NULL) { |
|
6579 xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, |
|
6580 "Internal error: element reference %s " |
|
6581 "not resolved\n", decl->ref, NULL); |
|
6582 return (-1); |
|
6583 } |
|
6584 ctxt->type = (xmlSchemaTypePtr) decl->refDecl; |
|
6585 decl = decl->refDecl; |
|
6586 } |
|
6587 /* TODO: Should "xmlSchemaValidateElement" be called instead? */ |
|
6588 xmlSchemaValidateElementType(ctxt, node); |
|
6589 ctxt->type = type; |
|
6590 break; |
|
6591 } |
|
6592 case XML_SCHEMA_TYPE_BASIC: |
|
6593 xmlSchemaValidateBasicType(ctxt, node); |
|
6594 break; |
|
6595 case XML_SCHEMA_TYPE_FACET: |
|
6596 TODO break; |
|
6597 case XML_SCHEMA_TYPE_SIMPLE: |
|
6598 xmlSchemaValidateSimpleType(ctxt, node); |
|
6599 break; |
|
6600 case XML_SCHEMA_TYPE_SEQUENCE: |
|
6601 TODO break; |
|
6602 case XML_SCHEMA_TYPE_CHOICE: |
|
6603 TODO break; |
|
6604 case XML_SCHEMA_TYPE_ALL: |
|
6605 TODO break; |
|
6606 case XML_SCHEMA_TYPE_SIMPLE_CONTENT: |
|
6607 TODO break; |
|
6608 case XML_SCHEMA_TYPE_COMPLEX_CONTENT: |
|
6609 TODO break; |
|
6610 case XML_SCHEMA_TYPE_UR: |
|
6611 TODO break; |
|
6612 case XML_SCHEMA_TYPE_RESTRICTION: |
|
6613 /*xmlSchemaValidateRestrictionType(ctxt, node); */ |
|
6614 TODO break; |
|
6615 case XML_SCHEMA_TYPE_EXTENSION: |
|
6616 TODO break; |
|
6617 case XML_SCHEMA_TYPE_ATTRIBUTE: |
|
6618 TODO break; |
|
6619 case XML_SCHEMA_TYPE_GROUP: |
|
6620 TODO break; |
|
6621 case XML_SCHEMA_TYPE_NOTATION: |
|
6622 TODO break; |
|
6623 case XML_SCHEMA_TYPE_LIST: |
|
6624 TODO break; |
|
6625 case XML_SCHEMA_TYPE_UNION: |
|
6626 TODO break; |
|
6627 case XML_SCHEMA_FACET_MININCLUSIVE: |
|
6628 TODO break; |
|
6629 case XML_SCHEMA_FACET_MINEXCLUSIVE: |
|
6630 TODO break; |
|
6631 case XML_SCHEMA_FACET_MAXINCLUSIVE: |
|
6632 TODO break; |
|
6633 case XML_SCHEMA_FACET_MAXEXCLUSIVE: |
|
6634 TODO break; |
|
6635 case XML_SCHEMA_FACET_TOTALDIGITS: |
|
6636 TODO break; |
|
6637 case XML_SCHEMA_FACET_FRACTIONDIGITS: |
|
6638 TODO break; |
|
6639 case XML_SCHEMA_FACET_PATTERN: |
|
6640 TODO break; |
|
6641 case XML_SCHEMA_FACET_ENUMERATION: |
|
6642 TODO break; |
|
6643 case XML_SCHEMA_FACET_WHITESPACE: |
|
6644 TODO break; |
|
6645 case XML_SCHEMA_FACET_LENGTH: |
|
6646 TODO break; |
|
6647 case XML_SCHEMA_FACET_MAXLENGTH: |
|
6648 TODO break; |
|
6649 case XML_SCHEMA_FACET_MINLENGTH: |
|
6650 TODO break; |
|
6651 case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: |
|
6652 TODO break; |
|
6653 case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: |
|
6654 TODO break; |
|
6655 } |
|
6656 xmlSchemaValidateAttributes(ctxt, node, type->attributes); |
|
6657 |
|
6658 if (ctxt->node == NULL) |
|
6659 return (ctxt->err); |
|
6660 ctxt->node = ctxt->node->next; |
|
6661 ctxt->type = type->next; |
|
6662 return (ctxt->err); |
|
6663 } |
|
6664 |
|
6665 /** |
|
6666 * xmlSchemaValidateType: |
|
6667 * @ctxt: a schema validation context |
|
6668 * @elem: an element |
|
6669 * @type: the list of type declarations |
|
6670 * |
|
6671 * Validate the content of an element against the types. |
|
6672 * |
|
6673 * Returns 0 if the element is schemas valid, a positive error code |
|
6674 * number otherwise and -1 in case of internal or API error. |
|
6675 */ |
|
6676 static int |
|
6677 xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, |
|
6678 xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type) |
|
6679 { |
|
6680 xmlChar *nil; |
|
6681 |
|
6682 if ((elem == NULL) || (type == NULL) || (elemDecl == NULL)) |
|
6683 return (0); |
|
6684 |
|
6685 /* |
|
6686 * 3.3.4 : 2 |
|
6687 */ |
|
6688 if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) { |
|
6689 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, |
|
6690 "Element declaration %s is abstract\n", |
|
6691 elemDecl->name, NULL); |
|
6692 /* Changed, since the element declaration is abstract and not |
|
6693 * the element itself. */ |
|
6694 /* xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ISABSTRACT, |
|
6695 "Element %s is abstract\n", elem->name, NULL); */ |
|
6696 return (ctxt->err); |
|
6697 } |
|
6698 /* |
|
6699 * 3.3.4: 3 |
|
6700 */ |
|
6701 nil = xmlGetNsProp(elem, BAD_CAST "nil", xmlSchemaInstanceNs); |
|
6702 if (elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) { |
|
6703 /* 3.3.4: 3.2 */ |
|
6704 if (xmlStrEqual(nil, BAD_CAST "true")) { |
|
6705 if (elem->children != NULL) { |
|
6706 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTEMPTY, |
|
6707 "Element %s is not empty\n", elem->name, NULL); |
|
6708 return (ctxt->err); |
|
6709 } |
|
6710 if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) && |
|
6711 (elemDecl->value != NULL)) { |
|
6712 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_HAVEDEFAULT, |
|
6713 "Empty element %s cannot get a fixed value\n", |
|
6714 elem->name, NULL); |
|
6715 return (ctxt->err); |
|
6716 } |
|
6717 } |
|
6718 } else { |
|
6719 /* 3.3.4: 3.1 */ |
|
6720 if (nil != NULL) { |
|
6721 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTNILLABLE, |
|
6722 "Element %s with xs:nil but not nillable\n", |
|
6723 elem->name, NULL); |
|
6724 xmlFree(nil); |
|
6725 return (ctxt->err); |
|
6726 } |
|
6727 } |
|
6728 |
|
6729 /* TODO 3.3.4: 4 if the element carries xs:type */ |
|
6730 |
|
6731 ctxt->type = elemDecl->subtypes; |
|
6732 ctxt->node = elem->children; |
|
6733 xmlSchemaValidateContent(ctxt, elem); |
|
6734 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes); |
|
6735 |
|
6736 return (ctxt->err); |
|
6737 } |
|
6738 |
|
6739 |
|
6740 /** |
|
6741 * xmlSchemaValidateAttributes: |
|
6742 * @ctxt: a schema validation context |
|
6743 * @elem: an element |
|
6744 * @attributes: the list of attribute declarations |
|
6745 * |
|
6746 * Validate the attributes of an element. |
|
6747 * |
|
6748 * Returns 0 if the element is schemas valid, a positive error code |
|
6749 * number otherwise and -1 in case of internal or API error. |
|
6750 */ |
|
6751 static int |
|
6752 xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, |
|
6753 xmlSchemaAttributePtr attributes) |
|
6754 { |
|
6755 int i, ret; |
|
6756 xmlAttrPtr attr; |
|
6757 xmlChar *value; |
|
6758 xmlSchemaAttributeGroupPtr group = NULL; |
|
6759 int found; |
|
6760 |
|
6761 if (attributes == NULL) |
|
6762 return (0); |
|
6763 while (attributes != NULL) { |
|
6764 found = 0; |
|
6765 /* |
|
6766 * Handle attribute groups |
|
6767 */ |
|
6768 if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) { |
|
6769 group = (xmlSchemaAttributeGroupPtr) attributes; |
|
6770 xmlSchemaValidateAttributes(ctxt, elem, group->attributes); |
|
6771 attributes = group->next; |
|
6772 continue; |
|
6773 } |
|
6774 for (i = ctxt->attrBase; i < ctxt->attrNr; i++) { |
|
6775 attr = ctxt->attr[i].attr; |
|
6776 if (attr == NULL) |
|
6777 continue; |
|
6778 if (attributes->ref != NULL) { |
|
6779 if (!xmlStrEqual(attr->name, attributes->ref)) |
|
6780 continue; |
|
6781 if (attr->ns != NULL) { |
|
6782 if ((attributes->refNs == NULL) || |
|
6783 (!xmlStrEqual(attr->ns->href, attributes->refNs))) |
|
6784 continue; |
|
6785 } else if (attributes->refNs != NULL) { |
|
6786 continue; |
|
6787 } |
|
6788 } else { |
|
6789 if (!xmlStrEqual(attr->name, attributes->name)) |
|
6790 continue; |
|
6791 /* |
|
6792 * handle the namespaces checks here |
|
6793 */ |
|
6794 if (attr->ns == NULL) { |
|
6795 /* |
|
6796 * accept an unqualified attribute only if the target |
|
6797 * namespace of the declaration is absent. |
|
6798 */ |
|
6799 if (attributes->targetNamespace != NULL) |
|
6800 /* |
|
6801 * This check was removed, since the target namespace |
|
6802 * was evaluated during parsing and already took |
|
6803 * "attributeFormDefault" into account. |
|
6804 */ |
|
6805 /* ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0)) */ |
|
6806 continue; |
|
6807 } else { |
|
6808 if (attributes->targetNamespace == NULL) |
|
6809 continue; |
|
6810 if (!xmlStrEqual(attributes->targetNamespace, |
|
6811 attr->ns->href)) |
|
6812 continue; |
|
6813 } |
|
6814 } |
|
6815 found = 1; |
|
6816 ctxt->cur = (xmlNodePtr) attributes; |
|
6817 |
|
6818 if (attributes->subtypes == NULL) { |
|
6819 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, |
|
6820 "Internal error: attribute %s type not resolved\n", |
|
6821 attr->name, NULL); |
|
6822 continue; |
|
6823 } |
|
6824 |
|
6825 if (attributes->occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) { |
|
6826 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_INVALIDATTR, |
|
6827 "attribute %s on %s is prohibited\n", |
|
6828 attributes->name, elem->name); |
|
6829 /* Setting the state to XML_SCHEMAS_ATTR_CHECKED seems |
|
6830 * not very logical but it suppresses the |
|
6831 * "attribute is unknown" error report. Please change |
|
6832 * this if you know better */ |
|
6833 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED; |
|
6834 break; |
|
6835 } |
|
6836 |
|
6837 value = xmlNodeListGetString(elem->doc, attr->children, 1); |
|
6838 ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes, |
|
6839 value); |
|
6840 if (ret != 0) { |
|
6841 xmlSchemaVErr(ctxt, (xmlNodePtr) attr, |
|
6842 XML_SCHEMAS_ERR_ATTRINVALID, |
|
6843 "attribute %s on %s does not match type\n", |
|
6844 attr->name, elem->name); |
|
6845 } else { |
|
6846 ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED; |
|
6847 } |
|
6848 if (value != NULL) { |
|
6849 xmlFree(value); |
|
6850 } |
|
6851 } |
|
6852 if ((!found) && (attributes->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) { |
|
6853 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_MISSING, |
|
6854 "required attribute %s on %s is missing\n", |
|
6855 attributes->name, elem->name); |
|
6856 } |
|
6857 attributes = attributes->next; |
|
6858 } |
|
6859 return (ctxt->err); |
|
6860 } |
|
6861 |
|
6862 /** |
|
6863 * xmlSchemaValidateElement: |
|
6864 * @ctxt: a schema validation context |
|
6865 * @elem: an element |
|
6866 * |
|
6867 * Validate an element in a tree |
|
6868 * |
|
6869 * Returns 0 if the element is schemas valid, a positive error code |
|
6870 * number otherwise and -1 in case of internal or API error. |
|
6871 */ |
|
6872 static int |
|
6873 xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) |
|
6874 { |
|
6875 xmlSchemaElementPtr elemDecl; |
|
6876 int ret, attrBase; |
|
6877 |
|
6878 if (elem->ns != NULL) { |
|
6879 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
6880 elem->name, elem->ns->href, NULL); |
|
6881 } else { |
|
6882 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
6883 elem->name, NULL, NULL); |
|
6884 } |
|
6885 /* |
|
6886 * special case whe elementFormDefault is unqualified for top-level elem. |
|
6887 */ |
|
6888 /* |
|
6889 * This was removed, since elementFormDefault does not apply to top-level |
|
6890 * element declarations. |
|
6891 */ |
|
6892 /* |
|
6893 if ((elemDecl == NULL) && (elem->ns != NULL) && |
|
6894 (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) && |
|
6895 (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) && |
|
6896 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) { |
|
6897 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
6898 elem->name, NULL, NULL); |
|
6899 } |
|
6900 */ |
|
6901 |
|
6902 /* |
|
6903 * 3.3.4 : 1 |
|
6904 */ |
|
6905 if (elemDecl == NULL) { |
|
6906 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_UNDECLAREDELEM, |
|
6907 "Element %s not declared\n", elem->name, NULL); |
|
6908 return (ctxt->err); |
|
6909 } |
|
6910 if (elemDecl->subtypes == NULL) { |
|
6911 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_NOTYPE, |
|
6912 "Element %s has no type\n", elem->name, NULL); |
|
6913 return (ctxt->err); |
|
6914 } |
|
6915 /* |
|
6916 * Verify the attributes |
|
6917 */ |
|
6918 attrBase = ctxt->attrBase; |
|
6919 ctxt->attrBase = ctxt->attrNr; |
|
6920 xmlSchemaRegisterAttributes(ctxt, elem->properties); |
|
6921 xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes); |
|
6922 /* |
|
6923 * Verify the element content recursively |
|
6924 */ |
|
6925 if (elemDecl->contModel != NULL) { |
|
6926 ctxt->regexp = xmlRegNewExecCtxt(elemDecl->contModel, |
|
6927 (xmlRegExecCallbacks) |
|
6928 xmlSchemaValidateCallback, ctxt); |
|
6929 #ifdef DEBUG_AUTOMATA |
|
6930 xmlGenericError(xmlGenericErrorContext, "====> %s\n", elem->name); |
|
6931 #endif |
|
6932 } |
|
6933 xmlSchemaValidateType(ctxt, elem, elemDecl, elemDecl->subtypes); |
|
6934 if (elemDecl->contModel != NULL) { |
|
6935 ret = xmlRegExecPushString(ctxt->regexp, NULL, NULL); |
|
6936 #ifdef DEBUG_AUTOMATA |
|
6937 xmlGenericError(xmlGenericErrorContext, |
|
6938 "====> %s : %d\n", elem->name, ret); |
|
6939 #endif |
|
6940 if (ret == 0) { |
|
6941 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, |
|
6942 "Element %s content check failed\n", |
|
6943 elem->name, NULL); |
|
6944 } else if (ret < 0) { |
|
6945 xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_ELEMCONT, |
|
6946 "Element %s content check failed\n", |
|
6947 elem->name, NULL); |
|
6948 #ifdef DEBUG_CONTENT |
|
6949 } else { |
|
6950 xmlGenericError(xmlGenericErrorContext, |
|
6951 "Element %s content check succeeded\n", |
|
6952 elem->name); |
|
6953 |
|
6954 #endif |
|
6955 } |
|
6956 xmlRegFreeExecCtxt(ctxt->regexp); |
|
6957 } |
|
6958 /* |
|
6959 * Verify that all attributes were Schemas-validated |
|
6960 */ |
|
6961 xmlSchemaCheckAttributes(ctxt, elem); |
|
6962 ctxt->attrNr = ctxt->attrBase; |
|
6963 ctxt->attrBase = attrBase; |
|
6964 |
|
6965 return (ctxt->err); |
|
6966 } |
|
6967 |
|
6968 /** |
|
6969 * xmlSchemaValidateDocument: |
|
6970 * @ctxt: a schema validation context |
|
6971 * @doc: a parsed document tree |
|
6972 * |
|
6973 * Validate a document tree in memory. |
|
6974 * |
|
6975 * Returns 0 if the document is schemas valid, a positive error code |
|
6976 * number otherwise and -1 in case of internal or API error. |
|
6977 */ |
|
6978 static int |
|
6979 xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) |
|
6980 { |
|
6981 xmlNodePtr root; |
|
6982 xmlSchemaElementPtr elemDecl; |
|
6983 |
|
6984 root = xmlDocGetRootElement(doc); |
|
6985 if (root == NULL) { |
|
6986 xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, |
|
6987 "document has no root\n", NULL, NULL); |
|
6988 return (ctxt->err); |
|
6989 } |
|
6990 |
|
6991 if (root->ns != NULL) |
|
6992 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
6993 root->name, root->ns->href, NULL); |
|
6994 else |
|
6995 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
6996 root->name, NULL, NULL); |
|
6997 /* |
|
6998 * special case whe elementFormDefault is unqualified for top-level elem. |
|
6999 */ |
|
7000 if ((elemDecl == NULL) && (root->ns != NULL) && |
|
7001 (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) && |
|
7002 ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) { |
|
7003 elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, |
|
7004 root->name, NULL, NULL); |
|
7005 } |
|
7006 |
|
7007 if (elemDecl == NULL) { |
|
7008 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, |
|
7009 "Element %s not declared\n", root->name, NULL); |
|
7010 } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) { |
|
7011 xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, |
|
7012 "Root element %s not toplevel\n", root->name, NULL); |
|
7013 } |
|
7014 /* |
|
7015 * Okay, start the recursive validation |
|
7016 */ |
|
7017 xmlSchemaValidateElement(ctxt, root); |
|
7018 |
|
7019 return (ctxt->err); |
|
7020 } |
|
7021 |
|
7022 /************************************************************************ |
|
7023 * * |
|
7024 * SAX Validation code * |
|
7025 * * |
|
7026 ************************************************************************/ |
|
7027 |
|
7028 /************************************************************************ |
|
7029 * * |
|
7030 * Validation interfaces * |
|
7031 * * |
|
7032 ************************************************************************/ |
|
7033 |
|
7034 /** |
|
7035 * xmlSchemaNewValidCtxt: |
|
7036 * @schema: a precompiled XML Schemas |
|
7037 * |
|
7038 * Create an XML Schemas validation context based on the given schema |
|
7039 * |
|
7040 * Returns the validation context or NULL in case of error |
|
7041 */ |
|
7042 xmlSchemaValidCtxtPtr |
|
7043 xmlSchemaNewValidCtxt(xmlSchemaPtr schema) |
|
7044 { |
|
7045 xmlSchemaValidCtxtPtr ret; |
|
7046 |
|
7047 ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt)); |
|
7048 if (ret == NULL) { |
|
7049 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL); |
|
7050 return (NULL); |
|
7051 } |
|
7052 memset(ret, 0, sizeof(xmlSchemaValidCtxt)); |
|
7053 ret->schema = schema; |
|
7054 ret->attrNr = 0; |
|
7055 ret->attrMax = 10; |
|
7056 ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax * |
|
7057 sizeof |
|
7058 (xmlSchemaAttrState)); |
|
7059 if (ret->attr == NULL) { |
|
7060 xmlSchemaVErrMemory(NULL, "allocating validation context", NULL); |
|
7061 free(ret); |
|
7062 return (NULL); |
|
7063 } |
|
7064 memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState)); |
|
7065 return (ret); |
|
7066 } |
|
7067 |
|
7068 /** |
|
7069 * xmlSchemaFreeValidCtxt: |
|
7070 * @ctxt: the schema validation context |
|
7071 * |
|
7072 * Free the resources associated to the schema validation context |
|
7073 */ |
|
7074 void |
|
7075 xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) |
|
7076 { |
|
7077 if (ctxt == NULL) |
|
7078 return; |
|
7079 if (ctxt->attr != NULL) |
|
7080 xmlFree(ctxt->attr); |
|
7081 if (ctxt->value != NULL) |
|
7082 xmlSchemaFreeValue(ctxt->value); |
|
7083 xmlFree(ctxt); |
|
7084 } |
|
7085 |
|
7086 /** |
|
7087 * xmlSchemaSetValidErrors: |
|
7088 * @ctxt: a schema validation context |
|
7089 * @err: the error function |
|
7090 * @warn: the warning function |
|
7091 * @ctx: the functions context |
|
7092 * |
|
7093 * Set the error and warning callback informations |
|
7094 */ |
|
7095 void |
|
7096 xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt, |
|
7097 xmlSchemaValidityErrorFunc err, |
|
7098 xmlSchemaValidityWarningFunc warn, void *ctx) |
|
7099 { |
|
7100 if (ctxt == NULL) |
|
7101 return; |
|
7102 ctxt->error = err; |
|
7103 ctxt->warning = warn; |
|
7104 ctxt->userData = ctx; |
|
7105 } |
|
7106 |
|
7107 /** |
|
7108 * xmlSchemaValidateDoc: |
|
7109 * @ctxt: a schema validation context |
|
7110 * @doc: a parsed document tree |
|
7111 * |
|
7112 * Validate a document tree in memory. |
|
7113 * |
|
7114 * Returns 0 if the document is schemas valid, a positive error code |
|
7115 * number otherwise and -1 in case of internal or API error. |
|
7116 */ |
|
7117 int |
|
7118 xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) |
|
7119 { |
|
7120 int ret; |
|
7121 |
|
7122 if ((ctxt == NULL) || (doc == NULL)) |
|
7123 return (-1); |
|
7124 |
|
7125 ctxt->doc = doc; |
|
7126 ret = xmlSchemaValidateDocument(ctxt, doc); |
|
7127 return (ret); |
|
7128 } |
|
7129 |
|
7130 /** |
|
7131 * xmlSchemaValidateStream: |
|
7132 * @ctxt: a schema validation context |
|
7133 * @input: the input to use for reading the data |
|
7134 * @enc: an optional encoding information |
|
7135 * @sax: a SAX handler for the resulting events |
|
7136 * @user_data: the context to provide to the SAX handler. |
|
7137 * |
|
7138 * Validate a document tree in memory. |
|
7139 * |
|
7140 * Returns 0 if the document is schemas valid, a positive error code |
|
7141 * number otherwise and -1 in case of internal or API error. |
|
7142 */ |
|
7143 int |
|
7144 xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, |
|
7145 xmlParserInputBufferPtr input, xmlCharEncoding enc, |
|
7146 xmlSAXHandlerPtr sax, void *user_data) |
|
7147 { |
|
7148 if ((ctxt == NULL) || (input == NULL)) |
|
7149 return (-1); |
|
7150 ctxt->input = input; |
|
7151 ctxt->enc = enc; |
|
7152 ctxt->sax = sax; |
|
7153 ctxt->user_data = user_data; |
|
7154 TODO return (0); |
|
7155 } |
|
7156 |
|
7157 #endif /* LIBXML_SCHEMAS_ENABLED */ |