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