blob: 81df430583631bd5707192fe88b08a0d5e6ed8bb [file] [log] [blame]
Daniel Veillard6eadf632003-01-23 18:29:16 +00001/*
2 * relaxng.c : implementation of the Relax-NG handling and validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
Daniel Veillardd41f4f42003-01-29 21:07:52 +00009/**
10 * TODO:
Daniel Veillardd41f4f42003-01-29 21:07:52 +000011 * - error reporting
Daniel Veillard1ed7f362003-02-03 10:57:45 +000012 * - handle namespace declarations as attributes.
Daniel Veillardf4b4f982003-02-13 11:02:08 +000013 * - add support for DTD compatibility spec
14 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardd41f4f42003-01-29 21:07:52 +000015 */
16
Daniel Veillard6eadf632003-01-23 18:29:16 +000017#define IN_LIBXML
18#include "libxml.h"
19
20#ifdef LIBXML_SCHEMAS_ENABLED
21
22#include <string.h>
23#include <stdio.h>
24#include <libxml/xmlmemory.h>
25#include <libxml/parser.h>
26#include <libxml/parserInternals.h>
27#include <libxml/hash.h>
28#include <libxml/uri.h>
29
30#include <libxml/relaxng.h>
31
32#include <libxml/xmlschemastypes.h>
33#include <libxml/xmlautomata.h>
34#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000035#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000036
37/*
38 * The Relax-NG namespace
39 */
40static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
41 "http://relaxng.org/ns/structure/1.0";
42
43#define IS_RELAXNG(node, type) \
44 ((node != NULL) && (node->ns != NULL) && \
45 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
46 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
47
48
Daniel Veillard39eb88b2003-03-11 11:21:28 +000049/* #define DEBUG 1 */
Daniel Veillardc482e262003-02-26 14:48:48 +000050/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000051/* #define DEBUG_CONTENT 1 */
52/* #define DEBUG_TYPE 1 */
53/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000054/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000055/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000056/* #define DEBUG_INCLUDE */
Daniel Veillard6eadf632003-01-23 18:29:16 +000057
58#define UNBOUNDED (1 << 30)
59#define TODO \
60 xmlGenericError(xmlGenericErrorContext, \
61 "Unimplemented block at %s:%d\n", \
62 __FILE__, __LINE__);
63
64typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
65typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
66
67typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
68typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
69
Daniel Veillardd41f4f42003-01-29 21:07:52 +000070typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
71typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
72
Daniel Veillarda9d912d2003-02-01 17:43:10 +000073typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
74typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
75
Daniel Veillard6eadf632003-01-23 18:29:16 +000076typedef enum {
77 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
78 XML_RELAXNG_COMBINE_CHOICE, /* choice */
79 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
80} xmlRelaxNGCombine;
81
Daniel Veillard4c5cf702003-02-21 15:40:34 +000082typedef enum {
83 XML_RELAXNG_CONTENT_ERROR = -1,
84 XML_RELAXNG_CONTENT_EMPTY = 0,
85 XML_RELAXNG_CONTENT_SIMPLE,
86 XML_RELAXNG_CONTENT_COMPLEX
87} xmlRelaxNGContentType;
88
Daniel Veillard6eadf632003-01-23 18:29:16 +000089typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
90typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
91
92struct _xmlRelaxNGGrammar {
93 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
94 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
95 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
96 xmlRelaxNGDefinePtr start; /* <start> content */
97 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +000098 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +000099 xmlHashTablePtr defs; /* define* */
100 xmlHashTablePtr refs; /* references */
101};
102
103
Daniel Veillard6eadf632003-01-23 18:29:16 +0000104typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000105 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000106 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
107 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000108 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000109 XML_RELAXNG_TEXT, /* textual content */
110 XML_RELAXNG_ELEMENT, /* an element */
111 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000112 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000113 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
114 XML_RELAXNG_LIST, /* a list of patterns */
115 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
116 XML_RELAXNG_DEF, /* a definition */
117 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000118 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000119 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000120 XML_RELAXNG_OPTIONAL, /* optional patterns */
121 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
122 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
123 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
124 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000125 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
126 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000127} xmlRelaxNGType;
128
129struct _xmlRelaxNGDefine {
130 xmlRelaxNGType type; /* the type of definition */
131 xmlNodePtr node; /* the node in the source */
132 xmlChar *name; /* the element local name if present */
133 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000134 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000135 void *data; /* data lib or specific pointer */
Daniel Veillardd4310742003-02-18 21:12:46 +0000136 int depth; /* used for the cycle detection */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000137 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000138 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000139 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
140 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000141 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000142 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
143};
144
145/**
146 * _xmlRelaxNG:
147 *
148 * A RelaxNGs definition
149 */
150struct _xmlRelaxNG {
151 xmlRelaxNGGrammarPtr topgrammar;
152 xmlDocPtr doc;
153
154 xmlHashTablePtr defs; /* define */
155 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000156 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
157 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000158 int defNr; /* number of defines used */
159 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000160 void *_private; /* unused by the library for users or bindings */
161};
162
Daniel Veillard77648bb2003-02-20 15:03:22 +0000163#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
164#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
165#define XML_RELAXNG_IN_LIST (1 << 2)
166#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
167#define XML_RELAXNG_IN_START (1 << 4)
168#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
169#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
170#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000171#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
172#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000173
174struct _xmlRelaxNGParserCtxt {
175 void *userData; /* user specific data block */
176 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
177 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000178 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000179
180 xmlRelaxNGPtr schema; /* The schema in use */
181 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000182 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000183 int flags; /* parser flags */
184 int nbErrors; /* number of errors at parse time */
185 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000186 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000187 xmlRelaxNGDefinePtr def; /* the current define */
188
189 int nbInterleaves;
190 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000191
Daniel Veillardc482e262003-02-26 14:48:48 +0000192 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
193 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000194 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000195 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000196
Daniel Veillard419a7682003-02-03 23:22:49 +0000197 int defNr; /* number of defines used */
198 int defMax; /* number of defines aloocated */
199 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
200
Daniel Veillard6eadf632003-01-23 18:29:16 +0000201 const char *buffer;
202 int size;
203
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000204 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000205 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000206 int docNr; /* Depth of the parsing stack */
207 int docMax; /* Max depth of the parsing stack */
208 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000209
210 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000211 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000212 int incNr; /* Depth of the include parsing stack */
213 int incMax; /* Max depth of the parsing stack */
214 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000215};
216
217#define FLAGS_IGNORABLE 1
218#define FLAGS_NEGATIVE 2
219
220/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000221 * xmlRelaxNGInterleaveGroup:
222 *
223 * A RelaxNGs partition set associated to lists of definitions
224 */
225typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
226typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
227struct _xmlRelaxNGInterleaveGroup {
228 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
229 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000230 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000231};
232
233/**
234 * xmlRelaxNGPartitions:
235 *
236 * A RelaxNGs partition associated to an interleave group
237 */
238typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
239typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
240struct _xmlRelaxNGPartition {
241 int nbgroups; /* number of groups in the partitions */
242 xmlRelaxNGInterleaveGroupPtr *groups;
243};
244
245/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000246 * xmlRelaxNGValidState:
247 *
248 * A RelaxNGs validation state
249 */
250#define MAX_ATTR 20
251typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
252typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
253struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000254 xmlNodePtr node; /* the current node */
255 xmlNodePtr seq; /* the sequence of children left to validate */
256 int nbAttrs; /* the number of attributes */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000257 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000258 xmlChar *value; /* the value when operating on string */
259 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000260 xmlAttrPtr attrs[1]; /* the array of attributes */
261};
262
263/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000264 * xmlRelaxNGValidError:
265 *
266 * A RelaxNGs validation error
267 */
268typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
269typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
270struct _xmlRelaxNGValidError {
271 xmlRelaxNGValidErr err; /* the error number */
272 xmlNodePtr node; /* the current node */
273 xmlNodePtr seq; /* the current child */
274 const xmlChar * arg1; /* first arg */
275 const xmlChar * arg2; /* second arg */
276};
277
278/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000279 * xmlRelaxNGValidCtxt:
280 *
281 * A RelaxNGs validation context
282 */
283
284struct _xmlRelaxNGValidCtxt {
285 void *userData; /* user specific data block */
286 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
287 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
288
289 xmlRelaxNGPtr schema; /* The schema in use */
290 xmlDocPtr doc; /* the document being validated */
291 xmlRelaxNGValidStatePtr state; /* the current validation state */
292 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000293 int depth; /* validation depth */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000294
295 /*
296 * Errors accumulated in branches may have to be stacked to be
297 * provided back when it's sure they affect validation.
298 */
299 xmlRelaxNGValidErrorPtr err; /* Last error */
300 int errNr; /* Depth of the error stack */
301 int errMax; /* Max depth of the error stack */
302 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000303};
304
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000305/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000306 * xmlRelaxNGInclude:
307 *
308 * Structure associated to a RelaxNGs document element
309 */
310struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000311 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000312 xmlChar *href; /* the normalized href value */
313 xmlDocPtr doc; /* the associated XML document */
314 xmlRelaxNGDefinePtr content;/* the definitions */
315 xmlRelaxNGPtr schema; /* the schema */
316};
317
318/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000319 * xmlRelaxNGDocument:
320 *
321 * Structure associated to a RelaxNGs document element
322 */
323struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000324 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000325 xmlChar *href; /* the normalized href value */
326 xmlDocPtr doc; /* the associated XML document */
327 xmlRelaxNGDefinePtr content;/* the definitions */
328 xmlRelaxNGPtr schema; /* the schema */
329};
330
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000331
Daniel Veillard6eadf632003-01-23 18:29:16 +0000332/************************************************************************
333 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000334 * Preliminary type checking interfaces *
335 * *
336 ************************************************************************/
337/**
338 * xmlRelaxNGTypeHave:
339 * @data: data needed for the library
340 * @type: the type name
341 * @value: the value to check
342 *
343 * Function provided by a type library to check if a type is exported
344 *
345 * Returns 1 if yes, 0 if no and -1 in case of error.
346 */
347typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
348
349/**
350 * xmlRelaxNGTypeCheck:
351 * @data: data needed for the library
352 * @type: the type name
353 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000354 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000355 *
356 * Function provided by a type library to check if a value match a type
357 *
358 * Returns 1 if yes, 0 if no and -1 in case of error.
359 */
360typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000361 const xmlChar *value, void **result);
362
363/**
364 * xmlRelaxNGFacetCheck:
365 * @data: data needed for the library
366 * @type: the type name
367 * @facet: the facet name
368 * @val: the facet value
369 * @strval: the string value
370 * @value: the value to check
371 *
372 * Function provided by a type library to check a value facet
373 *
374 * Returns 1 if yes, 0 if no and -1 in case of error.
375 */
376typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
377 const xmlChar *facet, const xmlChar *val,
378 const xmlChar *strval, void *value);
379
380/**
381 * xmlRelaxNGTypeFree:
382 * @data: data needed for the library
383 * @result: the value to free
384 *
385 * Function provided by a type library to free a returned result
386 */
387typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000388
389/**
390 * xmlRelaxNGTypeCompare:
391 * @data: data needed for the library
392 * @type: the type name
393 * @value1: the first value
394 * @value2: the second value
395 *
396 * Function provided by a type library to compare two values accordingly
397 * to a type.
398 *
399 * Returns 1 if yes, 0 if no and -1 in case of error.
400 */
401typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
402 const xmlChar *value1,
403 const xmlChar *value2);
404typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
405typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
406struct _xmlRelaxNGTypeLibrary {
407 const xmlChar *namespace; /* the datatypeLibrary value */
408 void *data; /* data needed for the library */
409 xmlRelaxNGTypeHave have; /* the export function */
410 xmlRelaxNGTypeCheck check; /* the checking function */
411 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000412 xmlRelaxNGFacetCheck facet; /* the facet check function */
413 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000414};
415
416/************************************************************************
417 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000418 * Allocation functions *
419 * *
420 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000421static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
422static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000423static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000424static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000425
426/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000427 * xmlRelaxNGFreeDocument:
428 * @docu: a document structure
429 *
430 * Deallocate a RelaxNG document structure.
431 */
432static void
433xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
434{
435 if (docu == NULL)
436 return;
437
438 if (docu->href != NULL)
439 xmlFree(docu->href);
440 if (docu->doc != NULL)
441 xmlFreeDoc(docu->doc);
442 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000443 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000444 xmlFree(docu);
445}
446
447/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000448 * xmlRelaxNGFreeDocumentList:
449 * @docu: a list of document structure
450 *
451 * Deallocate a RelaxNG document structures.
452 */
453static void
454xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
455{
456 xmlRelaxNGDocumentPtr next;
457 while (docu != NULL) {
458 next = docu->next;
459 xmlRelaxNGFreeDocument(docu);
460 docu = next;
461 }
462}
463
464/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000465 * xmlRelaxNGFreeInclude:
466 * @incl: a include structure
467 *
468 * Deallocate a RelaxNG include structure.
469 */
470static void
471xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
472{
473 if (incl == NULL)
474 return;
475
476 if (incl->href != NULL)
477 xmlFree(incl->href);
478 if (incl->doc != NULL)
479 xmlFreeDoc(incl->doc);
480 if (incl->schema != NULL)
481 xmlRelaxNGFree(incl->schema);
482 xmlFree(incl);
483}
484
485/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000486 * xmlRelaxNGFreeIncludeList:
487 * @incl: a include structure list
488 *
489 * Deallocate a RelaxNG include structure.
490 */
491static void
492xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
493{
494 xmlRelaxNGIncludePtr next;
495 while (incl != NULL) {
496 next = incl->next;
497 xmlRelaxNGFreeInclude(incl);
498 incl = next;
499 }
500}
501
502/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000503 * xmlRelaxNGNewRelaxNG:
504 * @ctxt: a Relax-NG validation context (optional)
505 *
506 * Allocate a new RelaxNG structure.
507 *
508 * Returns the newly allocated structure or NULL in case or error
509 */
510static xmlRelaxNGPtr
511xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
512{
513 xmlRelaxNGPtr ret;
514
515 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
516 if (ret == NULL) {
517 if ((ctxt != NULL) && (ctxt->error != NULL))
518 ctxt->error(ctxt->userData, "Out of memory\n");
519 ctxt->nbErrors++;
520 return (NULL);
521 }
522 memset(ret, 0, sizeof(xmlRelaxNG));
523
524 return (ret);
525}
526
527/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000528 * xmlRelaxNGFreeInnerSchema:
529 * @schema: a schema structure
530 *
531 * Deallocate a RelaxNG schema structure.
532 */
533static void
534xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
535{
536 if (schema == NULL)
537 return;
538
539 if (schema->doc != NULL)
540 xmlFreeDoc(schema->doc);
541 if (schema->defTab != NULL) {
542 int i;
543
544 for (i = 0;i < schema->defNr;i++)
545 xmlRelaxNGFreeDefine(schema->defTab[i]);
546 xmlFree(schema->defTab);
547 }
548
549 xmlFree(schema);
550}
551
552/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000553 * xmlRelaxNGFree:
554 * @schema: a schema structure
555 *
556 * Deallocate a RelaxNG structure.
557 */
558void
559xmlRelaxNGFree(xmlRelaxNGPtr schema)
560{
561 if (schema == NULL)
562 return;
563
Daniel Veillard6eadf632003-01-23 18:29:16 +0000564 if (schema->topgrammar != NULL)
565 xmlRelaxNGFreeGrammar(schema->topgrammar);
566 if (schema->doc != NULL)
567 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000568 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000569 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000570 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000571 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000572 if (schema->defTab != NULL) {
573 int i;
574
575 for (i = 0;i < schema->defNr;i++)
576 xmlRelaxNGFreeDefine(schema->defTab[i]);
577 xmlFree(schema->defTab);
578 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000579
580 xmlFree(schema);
581}
582
583/**
584 * xmlRelaxNGNewGrammar:
585 * @ctxt: a Relax-NG validation context (optional)
586 *
587 * Allocate a new RelaxNG grammar.
588 *
589 * Returns the newly allocated structure or NULL in case or error
590 */
591static xmlRelaxNGGrammarPtr
592xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
593{
594 xmlRelaxNGGrammarPtr ret;
595
596 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
597 if (ret == NULL) {
598 if ((ctxt != NULL) && (ctxt->error != NULL))
599 ctxt->error(ctxt->userData, "Out of memory\n");
600 ctxt->nbErrors++;
601 return (NULL);
602 }
603 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
604
605 return (ret);
606}
607
608/**
609 * xmlRelaxNGFreeGrammar:
610 * @grammar: a grammar structure
611 *
612 * Deallocate a RelaxNG grammar structure.
613 */
614static void
615xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
616{
617 if (grammar == NULL)
618 return;
619
Daniel Veillardc482e262003-02-26 14:48:48 +0000620 if (grammar->children != NULL) {
621 xmlRelaxNGFreeGrammar(grammar->children);
622 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000623 if (grammar->next != NULL) {
624 xmlRelaxNGFreeGrammar(grammar->next);
625 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000626 if (grammar->refs != NULL) {
627 xmlHashFree(grammar->refs, NULL);
628 }
629 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000630 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000631 }
632
633 xmlFree(grammar);
634}
635
636/**
637 * xmlRelaxNGNewDefine:
638 * @ctxt: a Relax-NG validation context
639 * @node: the node in the input document.
640 *
641 * Allocate a new RelaxNG define.
642 *
643 * Returns the newly allocated structure or NULL in case or error
644 */
645static xmlRelaxNGDefinePtr
646xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
647{
648 xmlRelaxNGDefinePtr ret;
649
Daniel Veillard419a7682003-02-03 23:22:49 +0000650 if (ctxt->defMax == 0) {
651 ctxt->defMax = 16;
652 ctxt->defNr = 0;
653 ctxt->defTab = (xmlRelaxNGDefinePtr *)
654 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
655 if (ctxt->defTab == NULL) {
656 if ((ctxt != NULL) && (ctxt->error != NULL))
657 ctxt->error(ctxt->userData, "Out of memory\n");
658 ctxt->nbErrors++;
659 return (NULL);
660 }
661 } else if (ctxt->defMax <= ctxt->defNr) {
662 xmlRelaxNGDefinePtr *tmp;
663 ctxt->defMax *= 2;
664 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
665 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
666 if (tmp == NULL) {
667 if ((ctxt != NULL) && (ctxt->error != NULL))
668 ctxt->error(ctxt->userData, "Out of memory\n");
669 ctxt->nbErrors++;
670 return (NULL);
671 }
672 ctxt->defTab = tmp;
673 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000674 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
675 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000676 if ((ctxt != NULL) && (ctxt->error != NULL))
677 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000678 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000679 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000680 }
681 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000682 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000683 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000684 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000685 return (ret);
686}
687
688/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000689 * xmlRelaxNGFreePartition:
690 * @partitions: a partition set structure
691 *
692 * Deallocate RelaxNG partition set structures.
693 */
694static void
695xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
696 xmlRelaxNGInterleaveGroupPtr group;
697 int j;
698
699 if (partitions != NULL) {
700 if (partitions->groups != NULL) {
701 for (j = 0;j < partitions->nbgroups;j++) {
702 group = partitions->groups[j];
703 if (group != NULL) {
704 if (group->defs != NULL)
705 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000706 if (group->attrs != NULL)
707 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000708 xmlFree(group);
709 }
710 }
711 xmlFree(partitions->groups);
712 }
713 xmlFree(partitions);
714 }
715}
716/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000717 * xmlRelaxNGFreeDefine:
718 * @define: a define structure
719 *
720 * Deallocate a RelaxNG define structure.
721 */
722static void
723xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
724{
725 if (define == NULL)
726 return;
727
Daniel Veillard419a7682003-02-03 23:22:49 +0000728 if ((define->data != NULL) &&
729 (define->type == XML_RELAXNG_INTERLEAVE))
730 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000731 if (define->name != NULL)
732 xmlFree(define->name);
733 if (define->ns != NULL)
734 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000735 if (define->value != NULL)
736 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000737 xmlFree(define);
738}
739
740/**
741 * xmlRelaxNGNewValidState:
742 * @ctxt: a Relax-NG validation context
743 * @node: the current node or NULL for the document
744 *
745 * Allocate a new RelaxNG validation state
746 *
747 * Returns the newly allocated structure or NULL in case or error
748 */
749static xmlRelaxNGValidStatePtr
750xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
751{
752 xmlRelaxNGValidStatePtr ret;
753 xmlAttrPtr attr;
754 xmlAttrPtr attrs[MAX_ATTR];
755 int nbAttrs = 0;
756 xmlNodePtr root = NULL;
757
758 if (node == NULL) {
759 root = xmlDocGetRootElement(ctxt->doc);
760 if (root == NULL)
761 return(NULL);
762 } else {
763 attr = node->properties;
764 while (attr != NULL) {
765 if (nbAttrs < MAX_ATTR)
766 attrs[nbAttrs++] = attr;
767 else
768 nbAttrs++;
769 attr = attr->next;
770 }
771 }
772
773 if (nbAttrs < MAX_ATTR)
774 attrs[nbAttrs] = NULL;
775 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
776 nbAttrs * sizeof(xmlAttrPtr));
777 if (ret == NULL) {
778 if ((ctxt != NULL) && (ctxt->error != NULL))
779 ctxt->error(ctxt->userData, "Out of memory\n");
780 return (NULL);
781 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000782 ret->value = NULL;
783 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000784 if (node == NULL) {
785 ret->node = (xmlNodePtr) ctxt->doc;
786 ret->seq = root;
787 ret->nbAttrs = 0;
788 } else {
789 ret->node = node;
790 ret->seq = node->children;
791 ret->nbAttrs = nbAttrs;
792 if (nbAttrs > 0) {
793 if (nbAttrs < MAX_ATTR) {
794 memcpy(&(ret->attrs[0]), attrs,
795 sizeof(xmlAttrPtr) * (nbAttrs + 1));
796 } else {
797 attr = node->properties;
798 nbAttrs = 0;
799 while (attr != NULL) {
800 ret->attrs[nbAttrs++] = attr;
801 attr = attr->next;
802 }
803 ret->attrs[nbAttrs] = NULL;
804 }
805 }
806 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000807 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000808 return (ret);
809}
810
811/**
812 * xmlRelaxNGCopyValidState:
813 * @ctxt: a Relax-NG validation context
814 * @state: a validation state
815 *
816 * Copy the validation state
817 *
818 * Returns the newly allocated structure or NULL in case or error
819 */
820static xmlRelaxNGValidStatePtr
821xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
822 xmlRelaxNGValidStatePtr state)
823{
824 xmlRelaxNGValidStatePtr ret;
825 unsigned int size;
826
827 if (state == NULL)
828 return(NULL);
829
830 size = sizeof(xmlRelaxNGValidState) +
831 state->nbAttrs * sizeof(xmlAttrPtr);
832 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size);
833 if (ret == NULL) {
834 if ((ctxt != NULL) && (ctxt->error != NULL))
835 ctxt->error(ctxt->userData, "Out of memory\n");
836 return (NULL);
837 }
838 memcpy(ret, state, size);
839 return(ret);
840}
841
842/**
Daniel Veillardce14fa52003-02-19 17:32:48 +0000843 * xmlRelaxNGEqualValidState:
844 * @ctxt: a Relax-NG validation context
845 * @state1: a validation state
846 * @state2: a validation state
847 *
848 * Compare the validation states for equality
849 *
850 * Returns 1 if equald, 0 otherwise
851 */
852static int
853xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
854 xmlRelaxNGValidStatePtr state1,
855 xmlRelaxNGValidStatePtr state2)
856{
857 int i;
858
859 if ((state1 == NULL) || (state2 == NULL))
860 return(0);
861 if (state1 == state2)
862 return(1);
863 if (state1->node != state2->node)
864 return(0);
865 if (state1->seq != state2->seq)
866 return(0);
867 if (state1->nbAttrLeft != state2->nbAttrLeft)
868 return(0);
869 if (state1->nbAttrs != state2->nbAttrs)
870 return(0);
871 if (state1->endvalue != state2->endvalue)
872 return(0);
873 if ((state1->value != state2->value) &&
874 (!xmlStrEqual(state1->value, state2->value)))
875 return(0);
876 for (i = 0;i < state1->nbAttrs;i++) {
877 if (state1->attrs[i] != state2->attrs[i])
878 return(0);
879 }
880 return(1);
881}
882
883/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000884 * xmlRelaxNGFreeValidState:
885 * @state: a validation state structure
886 *
887 * Deallocate a RelaxNG validation state structure.
888 */
889static void
890xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
891{
892 if (state == NULL)
893 return;
894
895 xmlFree(state);
896}
897
898/************************************************************************
899 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000900 * Document functions *
901 * *
902 ************************************************************************/
903static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
904 xmlDocPtr doc);
905
906/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000907 * xmlRelaxNGIncludePush:
908 * @ctxt: the parser context
909 * @value: the element doc
910 *
911 * Pushes a new include on top of the include stack
912 *
913 * Returns 0 in case of error, the index in the stack otherwise
914 */
915static int
916xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
917 xmlRelaxNGIncludePtr value)
918{
919 if (ctxt->incTab == NULL) {
920 ctxt->incMax = 4;
921 ctxt->incNr = 0;
922 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
923 ctxt->incMax * sizeof(ctxt->incTab[0]));
924 if (ctxt->incTab == NULL) {
925 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
926 return (0);
927 }
928 }
929 if (ctxt->incNr >= ctxt->incMax) {
930 ctxt->incMax *= 2;
931 ctxt->incTab =
932 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
933 ctxt->incMax *
934 sizeof(ctxt->incTab[0]));
935 if (ctxt->incTab == NULL) {
936 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
937 return (0);
938 }
939 }
940 ctxt->incTab[ctxt->incNr] = value;
941 ctxt->inc = value;
942 return (ctxt->incNr++);
943}
944
945/**
946 * xmlRelaxNGIncludePop:
947 * @ctxt: the parser context
948 *
949 * Pops the top include from the include stack
950 *
951 * Returns the include just removed
952 */
953static xmlRelaxNGIncludePtr
954xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
955{
956 xmlRelaxNGIncludePtr ret;
957
958 if (ctxt->incNr <= 0)
959 return (0);
960 ctxt->incNr--;
961 if (ctxt->incNr > 0)
962 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
963 else
964 ctxt->inc = NULL;
965 ret = ctxt->incTab[ctxt->incNr];
966 ctxt->incTab[ctxt->incNr] = 0;
967 return (ret);
968}
969
970/**
Daniel Veillard5add8682003-03-10 13:13:58 +0000971 * xmlRelaxNGRemoveRedefine:
972 * @ctxt: the parser context
973 * @URL: the normalized URL
974 * @target: the included target
975 * @name: the define name to eliminate
976 *
977 * Applies the elimination algorithm of 4.7
978 *
979 * Returns 0 in case of error, 1 in case of success.
980 */
981static int
982xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
983 const xmlChar *URL ATTRIBUTE_UNUSED,
984 xmlNodePtr target, const xmlChar *name) {
985 int found = 0;
986 xmlNodePtr tmp, tmp2;
987 xmlChar *name2;
988
989#ifdef DEBUG_INCLUDE
990 xmlGenericError(xmlGenericErrorContext,
991 "Elimination of <include> %s from %s\n", name, URL);
992#endif
993 tmp = target;
994 while (tmp != NULL) {
995 tmp2 = tmp->next;
996 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
997 found = 1;
998 xmlUnlinkNode(tmp);
999 xmlFreeNode(tmp);
1000 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1001 name2 = xmlGetProp(tmp, BAD_CAST "name");
1002 xmlRelaxNGNormExtSpace(name2);
1003 if (name2 != NULL) {
1004 if (xmlStrEqual(name, name2)) {
1005 found = 1;
1006 xmlUnlinkNode(tmp);
1007 xmlFreeNode(tmp);
1008 }
1009 xmlFree(name2);
1010 }
1011 } else if (IS_RELAXNG(tmp, "include")) {
1012 xmlChar *href = NULL;
1013 xmlRelaxNGDocumentPtr inc = tmp->_private;
1014
1015 if ((inc != NULL) && (inc->doc != NULL) &&
1016 (inc->doc->children != NULL)) {
1017
1018 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1019#ifdef DEBUG_INCLUDE
1020 href = xmlGetProp(tmp, BAD_CAST "href");
1021#endif
1022 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1023 inc->doc->children->children, name) == 1) {
1024 found = 1;
1025 }
1026 if (href != NULL)
1027 xmlFree(href);
1028 }
1029 }
1030 }
1031 tmp = tmp2;
1032 }
1033 return(found);
1034}
1035
1036/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001037 * xmlRelaxNGLoadInclude:
1038 * @ctxt: the parser context
1039 * @URL: the normalized URL
1040 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001041 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001042 *
1043 * First lookup if the document is already loaded into the parser context,
1044 * check against recursion. If not found the resource is loaded and
1045 * the content is preprocessed before being returned back to the caller.
1046 *
1047 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1048 */
1049static xmlRelaxNGIncludePtr
1050xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001051 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001052 xmlRelaxNGIncludePtr ret = NULL;
1053 xmlDocPtr doc;
1054 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001055 xmlNodePtr root, cur;
1056
1057#ifdef DEBUG_INCLUDE
1058 xmlGenericError(xmlGenericErrorContext,
1059 "xmlRelaxNGLoadInclude(%s)\n", URL);
1060#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001061
1062 /*
1063 * check against recursion in the stack
1064 */
1065 for (i = 0;i < ctxt->incNr;i++) {
1066 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1067 if (ctxt->error != NULL)
1068 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001069 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001070 URL);
1071 ctxt->nbErrors++;
1072 return(NULL);
1073 }
1074 }
1075
1076 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001077 * load the document
1078 */
1079 doc = xmlParseFile((const char *) URL);
1080 if (doc == NULL) {
1081 if (ctxt->error != NULL)
1082 ctxt->error(ctxt->userData,
1083 "xmlRelaxNG: could not load %s\n", URL);
1084 ctxt->nbErrors++;
1085 return (NULL);
1086 }
1087
Daniel Veillard5add8682003-03-10 13:13:58 +00001088#ifdef DEBUG_INCLUDE
1089 xmlGenericError(xmlGenericErrorContext,
1090 "Parsed %s Okay\n", URL);
1091#endif
1092
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001093 /*
1094 * Allocate the document structures and register it first.
1095 */
1096 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1097 if (ret == NULL) {
1098 if (ctxt->error != NULL)
1099 ctxt->error(ctxt->userData,
1100 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1101 ctxt->nbErrors++;
1102 xmlFreeDoc(doc);
1103 return (NULL);
1104 }
1105 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1106 ret->doc = doc;
1107 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001108 ret->next = ctxt->includes;
1109 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001110
1111 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001112 * transmit the ns if needed
1113 */
1114 if (ns != NULL) {
1115 root = xmlDocGetRootElement(doc);
1116 if (root != NULL) {
1117 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1118 xmlSetProp(root, BAD_CAST"ns", ns);
1119 }
1120 }
1121 }
1122
1123 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001124 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001125 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001126 xmlRelaxNGIncludePush(ctxt, ret);
1127
1128 /*
1129 * Some preprocessing of the document content, this include recursing
1130 * in the include stack.
1131 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001132#ifdef DEBUG_INCLUDE
1133 xmlGenericError(xmlGenericErrorContext,
1134 "cleanup of %s\n", URL);
1135#endif
1136
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001137 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1138 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001139 ctxt->inc = NULL;
1140 return(NULL);
1141 }
1142
1143 /*
1144 * Pop up the include from the stack
1145 */
1146 xmlRelaxNGIncludePop(ctxt);
1147
Daniel Veillard5add8682003-03-10 13:13:58 +00001148#ifdef DEBUG_INCLUDE
1149 xmlGenericError(xmlGenericErrorContext,
1150 "Checking of %s\n", URL);
1151#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001152 /*
1153 * Check that the top element is a grammar
1154 */
1155 root = xmlDocGetRootElement(doc);
1156 if (root == NULL) {
1157 if (ctxt->error != NULL)
1158 ctxt->error(ctxt->userData,
1159 "xmlRelaxNG: included document is empty %s\n", URL);
1160 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001161 return (NULL);
1162 }
1163 if (!IS_RELAXNG(root, "grammar")) {
1164 if (ctxt->error != NULL)
1165 ctxt->error(ctxt->userData,
1166 "xmlRelaxNG: included document %s root is not a grammar\n",
1167 URL);
1168 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001169 return (NULL);
1170 }
1171
1172 /*
1173 * Elimination of redefined rules in the include.
1174 */
1175 cur = node->children;
1176 while (cur != NULL) {
1177 if (IS_RELAXNG(cur, "start")) {
1178 int found = 0;
1179
Daniel Veillard5add8682003-03-10 13:13:58 +00001180 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001181 if (!found) {
1182 if (ctxt->error != NULL)
1183 ctxt->error(ctxt->userData,
1184 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1185 URL);
1186 ctxt->nbErrors++;
1187 }
1188 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001189 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001190
1191 name = xmlGetProp(cur, BAD_CAST "name");
1192 if (name == NULL) {
1193 if (ctxt->error != NULL)
1194 ctxt->error(ctxt->userData,
1195 "xmlRelaxNG: include %s has define without name\n",
1196 URL);
1197 ctxt->nbErrors++;
1198 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001199 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001200
Daniel Veillardd2298792003-02-14 16:54:11 +00001201 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001202 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1203 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001204 if (!found) {
1205 if (ctxt->error != NULL)
1206 ctxt->error(ctxt->userData,
1207 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1208 URL, name);
1209 ctxt->nbErrors++;
1210 }
1211 xmlFree(name);
1212 }
1213 }
1214 cur = cur->next;
1215 }
1216
1217
1218 return(ret);
1219}
1220
1221/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001222 * xmlRelaxNGValidErrorPush:
1223 * @ctxt: the validation context
1224 * @err: the error code
1225 * @arg1: the first string argument
1226 * @arg2: the second string argument
1227 *
1228 * Pushes a new error on top of the error stack
1229 *
1230 * Returns 0 in case of error, the index in the stack otherwise
1231 */
1232static int
1233xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1234 const xmlChar *arg1, const xmlChar *arg2)
1235{
1236 xmlRelaxNGValidErrorPtr cur;
1237 if (ctxt->errTab == NULL) {
1238 ctxt->errMax = 8;
1239 ctxt->errNr = 0;
1240 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1241 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1242 if (ctxt->errTab == NULL) {
1243 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1244 return (0);
1245 }
1246 }
1247 if (ctxt->errNr >= ctxt->errMax) {
1248 ctxt->errMax *= 2;
1249 ctxt->errTab =
1250 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1251 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1252 if (ctxt->errTab == NULL) {
1253 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1254 return (0);
1255 }
1256 }
1257 cur = &ctxt->errTab[ctxt->errNr];
1258 cur->err = err;
1259 cur->arg1 = arg1;
1260 cur->arg2 = arg2;
1261 if (ctxt->state != NULL) {
1262 cur->node = ctxt->state->node;
1263 cur->seq = ctxt->state->seq;
1264 } else {
1265 cur->node = NULL;
1266 cur->seq = NULL;
1267 }
1268 ctxt->err = cur;
1269 return (ctxt->errNr++);
1270}
1271
1272/**
1273 * xmlRelaxNGValidErrorPop:
1274 * @ctxt: the validation context
1275 *
1276 * Pops the top error from the error stack
1277 *
1278 * Returns the error just removed
1279 */
1280static xmlRelaxNGValidErrorPtr
1281xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1282{
1283 xmlRelaxNGValidErrorPtr ret;
1284
1285 if (ctxt->errNr <= 0)
1286 return (NULL);
1287 ctxt->errNr--;
1288 if (ctxt->errNr > 0)
1289 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1290 else
1291 ctxt->err = NULL;
1292 ret = &ctxt->errTab[ctxt->errNr];
1293 return (ret);
1294}
1295
1296
1297/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001298 * xmlRelaxNGDocumentPush:
1299 * @ctxt: the parser context
1300 * @value: the element doc
1301 *
1302 * Pushes a new doc on top of the doc stack
1303 *
1304 * Returns 0 in case of error, the index in the stack otherwise
1305 */
1306static int
1307xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1308 xmlRelaxNGDocumentPtr value)
1309{
1310 if (ctxt->docTab == NULL) {
1311 ctxt->docMax = 4;
1312 ctxt->docNr = 0;
1313 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1314 ctxt->docMax * sizeof(ctxt->docTab[0]));
1315 if (ctxt->docTab == NULL) {
1316 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1317 return (0);
1318 }
1319 }
1320 if (ctxt->docNr >= ctxt->docMax) {
1321 ctxt->docMax *= 2;
1322 ctxt->docTab =
1323 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1324 ctxt->docMax *
1325 sizeof(ctxt->docTab[0]));
1326 if (ctxt->docTab == NULL) {
1327 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1328 return (0);
1329 }
1330 }
1331 ctxt->docTab[ctxt->docNr] = value;
1332 ctxt->doc = value;
1333 return (ctxt->docNr++);
1334}
1335
1336/**
1337 * xmlRelaxNGDocumentPop:
1338 * @ctxt: the parser context
1339 *
1340 * Pops the top doc from the doc stack
1341 *
1342 * Returns the doc just removed
1343 */
1344static xmlRelaxNGDocumentPtr
1345xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1346{
1347 xmlRelaxNGDocumentPtr ret;
1348
1349 if (ctxt->docNr <= 0)
1350 return (0);
1351 ctxt->docNr--;
1352 if (ctxt->docNr > 0)
1353 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1354 else
1355 ctxt->doc = NULL;
1356 ret = ctxt->docTab[ctxt->docNr];
1357 ctxt->docTab[ctxt->docNr] = 0;
1358 return (ret);
1359}
1360
1361/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001362 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001363 * @ctxt: the parser context
1364 * @URL: the normalized URL
1365 * @ns: the inherited ns if any
1366 *
1367 * First lookup if the document is already loaded into the parser context,
1368 * check against recursion. If not found the resource is loaded and
1369 * the content is preprocessed before being returned back to the caller.
1370 *
1371 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1372 */
1373static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001374xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001375 const xmlChar *ns) {
1376 xmlRelaxNGDocumentPtr ret = NULL;
1377 xmlDocPtr doc;
1378 xmlNodePtr root;
1379 int i;
1380
1381 /*
1382 * check against recursion in the stack
1383 */
1384 for (i = 0;i < ctxt->docNr;i++) {
1385 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1386 if (ctxt->error != NULL)
1387 ctxt->error(ctxt->userData,
1388 "Detected an externalRef recursion for %s\n",
1389 URL);
1390 ctxt->nbErrors++;
1391 return(NULL);
1392 }
1393 }
1394
1395 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001396 * load the document
1397 */
1398 doc = xmlParseFile((const char *) URL);
1399 if (doc == NULL) {
1400 if (ctxt->error != NULL)
1401 ctxt->error(ctxt->userData,
1402 "xmlRelaxNG: could not load %s\n", URL);
1403 ctxt->nbErrors++;
1404 return (NULL);
1405 }
1406
1407 /*
1408 * Allocate the document structures and register it first.
1409 */
1410 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1411 if (ret == NULL) {
1412 if (ctxt->error != NULL)
1413 ctxt->error(ctxt->userData,
1414 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1415 ctxt->nbErrors++;
1416 xmlFreeDoc(doc);
1417 return (NULL);
1418 }
1419 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1420 ret->doc = doc;
1421 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001422 ret->next = ctxt->documents;
1423 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001424
1425 /*
1426 * transmit the ns if needed
1427 */
1428 if (ns != NULL) {
1429 root = xmlDocGetRootElement(doc);
1430 if (root != NULL) {
1431 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1432 xmlSetProp(root, BAD_CAST"ns", ns);
1433 }
1434 }
1435 }
1436
1437 /*
1438 * push it on the stack and register it in the hash table
1439 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001440 xmlRelaxNGDocumentPush(ctxt, ret);
1441
1442 /*
1443 * Some preprocessing of the document content
1444 */
1445 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1446 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001447 ctxt->doc = NULL;
1448 return(NULL);
1449 }
1450
1451 xmlRelaxNGDocumentPop(ctxt);
1452
1453 return(ret);
1454}
1455
1456/************************************************************************
1457 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001458 * Error functions *
1459 * *
1460 ************************************************************************/
1461
Daniel Veillard42f12e92003-03-07 18:32:59 +00001462#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL);
1463#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL);
1464#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001465
Daniel Veillardd2298792003-02-14 16:54:11 +00001466#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001467static const char *
1468xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1469 if (def == NULL)
1470 return("none");
1471 switch(def->type) {
1472 case XML_RELAXNG_EMPTY: return("empty");
1473 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1474 case XML_RELAXNG_EXCEPT: return("except");
1475 case XML_RELAXNG_TEXT: return("text");
1476 case XML_RELAXNG_ELEMENT: return("element");
1477 case XML_RELAXNG_DATATYPE: return("datatype");
1478 case XML_RELAXNG_VALUE: return("value");
1479 case XML_RELAXNG_LIST: return("list");
1480 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1481 case XML_RELAXNG_DEF: return("def");
1482 case XML_RELAXNG_REF: return("ref");
1483 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1484 case XML_RELAXNG_PARENTREF: return("parentRef");
1485 case XML_RELAXNG_OPTIONAL: return("optional");
1486 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
1487 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1488 case XML_RELAXNG_CHOICE: return("choice");
1489 case XML_RELAXNG_GROUP: return("group");
1490 case XML_RELAXNG_INTERLEAVE: return("interleave");
1491 case XML_RELAXNG_START: return("start");
1492 }
1493 return("unknown");
1494}
Daniel Veillardd2298792003-02-14 16:54:11 +00001495#endif
1496
Daniel Veillard6eadf632003-01-23 18:29:16 +00001497/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001498 * xmlRelaxNGGetErrorString:
1499 * @err: the error code
1500 * @arg1: the first string argument
1501 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001502 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001503 * computes a formatted error string for the given error code and args
1504 *
1505 * Returns the error string, it must be deallocated by the caller
1506 */
1507static xmlChar *
1508xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1509 const xmlChar *arg2) {
1510 char msg[1000];
1511
1512 if (arg1 == NULL)
1513 arg1 = BAD_CAST "";
1514 if (arg2 == NULL)
1515 arg2 = BAD_CAST "";
1516
1517 msg[0] = 0;
1518 switch (err) {
1519 case XML_RELAXNG_OK:
1520 return(NULL);
1521 case XML_RELAXNG_ERR_MEMORY:
1522 return(xmlCharStrdup("out of memory"));
1523 case XML_RELAXNG_ERR_TYPE:
1524 snprintf(msg, 1000, "failed to validate type %s", arg1);
1525 break;
1526 case XML_RELAXNG_ERR_TYPEVAL:
1527 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1528 break;
1529 case XML_RELAXNG_ERR_TYPECMP:
1530 snprintf(msg, 1000, "failed to compare type %s", arg1);
1531 break;
1532 case XML_RELAXNG_ERR_NOSTATE:
1533 return(xmlCharStrdup("Internal error: no state"));
1534 case XML_RELAXNG_ERR_NODEFINE:
1535 return(xmlCharStrdup("Internal error: no define"));
1536 case XML_RELAXNG_ERR_LISTEXTRA:
1537 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1538 break;
1539 case XML_RELAXNG_ERR_INTERNODATA:
1540 return(xmlCharStrdup("Internal: interleave block has no data"));
1541 case XML_RELAXNG_ERR_INTERSEQ:
1542 return(xmlCharStrdup("Invalid sequence in interleave"));
1543 case XML_RELAXNG_ERR_INTEREXTRA:
1544 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1545 break;
1546 case XML_RELAXNG_ERR_ELEMNAME:
1547 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1548 break;
1549 case XML_RELAXNG_ERR_ELEMNONS:
1550 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1551 break;
1552 case XML_RELAXNG_ERR_ELEMWRONGNS:
1553 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1554 arg1, arg2);
1555 break;
1556 case XML_RELAXNG_ERR_ELEMEXTRANS:
1557 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1558 break;
1559 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1560 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1561 break;
1562 case XML_RELAXNG_ERR_NOELEM:
1563 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1564 break;
1565 case XML_RELAXNG_ERR_NOTELEM:
1566 return(xmlCharStrdup("Expecting an element got text"));
1567 case XML_RELAXNG_ERR_ATTRVALID:
1568 snprintf(msg, 1000, "Element %s failed to validate attributes",
1569 arg1);
1570 break;
1571 case XML_RELAXNG_ERR_CONTENTVALID:
1572 snprintf(msg, 1000, "Element %s failed to validate content",
1573 arg1);
1574 break;
1575 case XML_RELAXNG_ERR_EXTRACONTENT:
1576 snprintf(msg, 1000, "Element %s has extra content: %s",
1577 arg1, arg2);
1578 break;
1579 case XML_RELAXNG_ERR_INVALIDATTR:
1580 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1581 arg1, arg2);
1582 break;
1583 case XML_RELAXNG_ERR_DATAELEM:
1584 snprintf(msg, 1000, "Datatype element %s has child elements",
1585 arg1);
1586 break;
1587 case XML_RELAXNG_ERR_VALELEM:
1588 snprintf(msg, 1000, "Value element %s has child elements",
1589 arg1);
1590 break;
1591 case XML_RELAXNG_ERR_LISTELEM:
1592 snprintf(msg, 1000, "List element %s has child elements",
1593 arg1);
1594 break;
1595 case XML_RELAXNG_ERR_DATATYPE:
1596 snprintf(msg, 1000, "Error validating datatype %s",
1597 arg1);
1598 break;
1599 case XML_RELAXNG_ERR_VALUE:
1600 snprintf(msg, 1000, "Error validating value %s",
1601 arg1);
1602 break;
1603 case XML_RELAXNG_ERR_LIST:
1604 return(xmlCharStrdup("Error validating list"));
1605 case XML_RELAXNG_ERR_NOGRAMMAR:
1606 return(xmlCharStrdup("No top grammar defined"));
1607 case XML_RELAXNG_ERR_EXTRADATA:
1608 return(xmlCharStrdup("Extra data in the document"));
1609 }
1610 if (msg[0] == 0) {
1611 snprintf(msg, 1000, "Unknown error code %d", err);
1612 }
1613 msg[1000] = 0;
1614 return(xmlStrdup((xmlChar *) msg));
1615}
1616
1617/**
1618 * xmlRelaxNGValidErrorContext:
1619 * @ctxt: the validation context
1620 * @node: the node
1621 * @child: the node child generating the problem.
1622 *
1623 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001624 */
1625static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001626xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1627 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001628{
1629 int line = 0;
1630 const xmlChar *file = NULL;
1631 const xmlChar *name = NULL;
1632 const char *type = "error";
1633
1634 if ((ctxt == NULL) || (ctxt->error == NULL))
1635 return;
1636
1637 if (child != NULL)
1638 node = child;
1639
1640 if (node != NULL) {
1641 if ((node->type == XML_DOCUMENT_NODE) ||
1642 (node->type == XML_HTML_DOCUMENT_NODE)) {
1643 xmlDocPtr doc = (xmlDocPtr) node;
1644
1645 file = doc->URL;
1646 } else {
1647 /*
1648 * Try to find contextual informations to report
1649 */
1650 if (node->type == XML_ELEMENT_NODE) {
1651 line = (int) node->content;
1652 } else if ((node->prev != NULL) &&
1653 (node->prev->type == XML_ELEMENT_NODE)) {
1654 line = (int) node->prev->content;
1655 } else if ((node->parent != NULL) &&
1656 (node->parent->type == XML_ELEMENT_NODE)) {
1657 line = (int) node->parent->content;
1658 }
1659 if ((node->doc != NULL) && (node->doc->URL != NULL))
1660 file = node->doc->URL;
1661 if (node->name != NULL)
1662 name = node->name;
1663 }
1664 }
1665
Daniel Veillard42f12e92003-03-07 18:32:59 +00001666 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001667
1668 if ((file != NULL) && (line != 0) && (name != NULL))
1669 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1670 type, file, line, name);
1671 else if ((file != NULL) && (name != NULL))
1672 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1673 type, file, name);
1674 else if ((file != NULL) && (line != 0))
1675 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1676 else if (file != NULL)
1677 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1678 else if (name != NULL)
1679 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1680 else
1681 ctxt->error(ctxt->userData, "%s\n", type);
1682}
Daniel Veillard42f12e92003-03-07 18:32:59 +00001683
1684/**
1685 * xmlRelaxNGShowValidError:
1686 * @ctxt: the validation context
1687 * @err: the error number
1688 * @node: the node
1689 * @child: the node child generating the problem.
1690 * @arg1: the first argument
1691 * @arg2: the second argument
1692 *
1693 * Show a validation error.
1694 */
1695static void
1696xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1697 xmlNodePtr node, xmlNodePtr child,
1698 const xmlChar *arg1, const xmlChar *arg2)
1699{
1700 xmlChar *msg;
1701
1702 if (ctxt->error == NULL)
1703 return;
1704
1705 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
1706 if (msg == NULL)
1707 return;
1708
1709 xmlRelaxNGValidErrorContext(ctxt, node, child);
1710 ctxt->error(ctxt->userData, "%s\n", msg);
1711 xmlFree(msg);
1712}
1713
1714/**
1715 * xmlRelaxNGDumpValidError:
1716 * @ctxt: the validation context
1717 *
1718 * Show all validation error over a given index.
1719 */
1720static void
1721xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
1722 int i;
1723 xmlRelaxNGValidErrorPtr err;
1724
1725 for (i = 0;i < ctxt->errNr;i++) {
1726 err = &ctxt->errTab[i];
1727 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
1728 err->arg1, err->arg2);
1729 }
1730 ctxt->errNr = 0;
1731}
1732/**
1733 * xmlRelaxNGAddValidError:
1734 * @ctxt: the validation context
1735 * @err: the error number
1736 * @arg1: the first argument
1737 * @arg2: the second argument
1738 *
1739 * Register a validation error, either generating it if it's sure
1740 * or stacking it for later handling if unsure.
1741 */
1742static void
1743xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1744 const xmlChar *arg1, const xmlChar *arg2)
1745{
1746 if ((ctxt == NULL) || (ctxt->error == NULL))
1747 return;
1748
1749 /*
1750 * generate the error directly
1751 */
1752 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
1753 xmlNodePtr node, seq;
1754 /*
1755 * Flush first any stacked error which might be the
1756 * real cause of the problem.
1757 */
1758 if (ctxt->errNr != 0)
1759 xmlRelaxNGDumpValidError(ctxt);
1760 if (ctxt->state != NULL) {
1761 node = ctxt->state->node;
1762 seq = ctxt->state->seq;
1763 } else {
1764 node = seq = NULL;
1765 }
1766 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
1767 }
1768 /*
1769 * Stack the error for later processing if needed
1770 */
1771 else {
1772 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2);
1773 }
1774}
1775
Daniel Veillard6eadf632003-01-23 18:29:16 +00001776
1777/************************************************************************
1778 * *
1779 * Type library hooks *
1780 * *
1781 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00001782static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1783 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001784
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001785/**
1786 * xmlRelaxNGSchemaTypeHave:
1787 * @data: data needed for the library
1788 * @type: the type name
1789 *
1790 * Check if the given type is provided by
1791 * the W3C XMLSchema Datatype library.
1792 *
1793 * Returns 1 if yes, 0 if no and -1 in case of error.
1794 */
1795static int
1796xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001797 const xmlChar *type) {
1798 xmlSchemaTypePtr typ;
1799
1800 if (type == NULL)
1801 return(-1);
1802 typ = xmlSchemaGetPredefinedType(type,
1803 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1804 if (typ == NULL)
1805 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001806 return(1);
1807}
1808
1809/**
1810 * xmlRelaxNGSchemaTypeCheck:
1811 * @data: data needed for the library
1812 * @type: the type name
1813 * @value: the value to check
1814 *
1815 * Check if the given type and value are validated by
1816 * the W3C XMLSchema Datatype library.
1817 *
1818 * Returns 1 if yes, 0 if no and -1 in case of error.
1819 */
1820static int
1821xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001822 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001823 const xmlChar *value,
1824 void **result) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001825 xmlSchemaTypePtr typ;
1826 int ret;
1827
1828 /*
1829 * TODO: the type should be cached ab provided back, interface subject
1830 * to changes.
1831 * TODO: handle facets, may require an additional interface and keep
1832 * the value returned from the validation.
1833 */
1834 if ((type == NULL) || (value == NULL))
1835 return(-1);
1836 typ = xmlSchemaGetPredefinedType(type,
1837 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1838 if (typ == NULL)
1839 return(-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001840 ret = xmlSchemaValidatePredefinedType(typ, value,
1841 (xmlSchemaValPtr *) result);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001842 if (ret == 0)
1843 return(1);
1844 if (ret > 0)
1845 return(0);
1846 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001847}
1848
1849/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001850 * xmlRelaxNGSchemaFacetCheck:
1851 * @data: data needed for the library
1852 * @type: the type name
1853 * @facet: the facet name
1854 * @val: the facet value
1855 * @strval: the string value
1856 * @value: the value to check
1857 *
1858 * Function provided by a type library to check a value facet
1859 *
1860 * Returns 1 if yes, 0 if no and -1 in case of error.
1861 */
1862static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00001863xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001864 const xmlChar *facetname, const xmlChar *val,
1865 const xmlChar *strval, void *value) {
1866 xmlSchemaFacetPtr facet;
1867 xmlSchemaTypePtr typ;
1868 int ret;
1869
1870 if ((type == NULL) || (strval == NULL))
1871 return(-1);
1872 typ = xmlSchemaGetPredefinedType(type,
1873 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1874 if (typ == NULL)
1875 return(-1);
1876
1877 facet = xmlSchemaNewFacet();
1878 if (facet == NULL)
1879 return(-1);
1880
1881 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
1882 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1883 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
1884 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1885 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
1886 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1887 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
1888 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1889 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
1890 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1891 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
1892 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1893 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
1894 facet->type = XML_SCHEMA_FACET_PATTERN;
1895 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
1896 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1897 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
1898 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1899 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
1900 facet->type = XML_SCHEMA_FACET_LENGTH;
1901 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
1902 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1903 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
1904 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1905 } else {
1906 xmlSchemaFreeFacet(facet);
1907 return(-1);
1908 }
1909 facet->value = xmlStrdup(val);
1910 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
1911 if (ret != 0) {
1912 xmlSchemaFreeFacet(facet);
1913 return(-1);
1914 }
1915 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
1916 xmlSchemaFreeFacet(facet);
1917 if (ret != 0)
1918 return(-1);
1919 return(0);
1920}
1921
1922/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001923 * xmlRelaxNGSchemaTypeCompare:
1924 * @data: data needed for the library
1925 * @type: the type name
1926 * @value1: the first value
1927 * @value2: the second value
1928 *
1929 * Compare two values accordingly a type from the W3C XMLSchema
1930 * Datatype library.
1931 *
1932 * Returns 1 if yes, 0 if no and -1 in case of error.
1933 */
1934static int
1935xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
1936 const xmlChar *type ATTRIBUTE_UNUSED,
1937 const xmlChar *value1 ATTRIBUTE_UNUSED,
1938 const xmlChar *value2 ATTRIBUTE_UNUSED) {
1939 TODO
1940 return(1);
1941}
1942
1943/**
1944 * xmlRelaxNGDefaultTypeHave:
1945 * @data: data needed for the library
1946 * @type: the type name
1947 *
1948 * Check if the given type is provided by
1949 * the default datatype library.
1950 *
1951 * Returns 1 if yes, 0 if no and -1 in case of error.
1952 */
1953static int
1954xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
1955 if (type == NULL)
1956 return(-1);
1957 if (xmlStrEqual(type, BAD_CAST "string"))
1958 return(1);
1959 if (xmlStrEqual(type, BAD_CAST "token"))
1960 return(1);
1961 return(0);
1962}
1963
1964/**
1965 * xmlRelaxNGDefaultTypeCheck:
1966 * @data: data needed for the library
1967 * @type: the type name
1968 * @value: the value to check
1969 *
1970 * Check if the given type and value are validated by
1971 * the default datatype library.
1972 *
1973 * Returns 1 if yes, 0 if no and -1 in case of error.
1974 */
1975static int
1976xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
1977 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001978 const xmlChar *value ATTRIBUTE_UNUSED,
1979 void **result ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00001980 if (value == NULL)
1981 return(-1);
1982 if (xmlStrEqual(type, BAD_CAST "string"))
1983 return(1);
1984 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00001985 return(1);
1986 }
1987
1988 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001989}
1990
1991/**
1992 * xmlRelaxNGDefaultTypeCompare:
1993 * @data: data needed for the library
1994 * @type: the type name
1995 * @value1: the first value
1996 * @value2: the second value
1997 *
1998 * Compare two values accordingly a type from the default
1999 * datatype library.
2000 *
2001 * Returns 1 if yes, 0 if no and -1 in case of error.
2002 */
2003static int
2004xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2005 const xmlChar *type ATTRIBUTE_UNUSED,
2006 const xmlChar *value1 ATTRIBUTE_UNUSED,
2007 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002008 int ret = -1;
2009
2010 if (xmlStrEqual(type, BAD_CAST "string")) {
2011 ret = xmlStrEqual(value1, value2);
2012 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2013 if (!xmlStrEqual(value1, value2)) {
2014 xmlChar *nval, *nvalue;
2015
2016 /*
2017 * TODO: trivial optimizations are possible by
2018 * computing at compile-time
2019 */
2020 nval = xmlRelaxNGNormalize(NULL, value1);
2021 nvalue = xmlRelaxNGNormalize(NULL, value2);
2022
Daniel Veillardd4310742003-02-18 21:12:46 +00002023 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002024 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002025 else if (xmlStrEqual(nval, nvalue))
2026 ret = 1;
2027 else
2028 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002029 if (nval != NULL)
2030 xmlFree(nval);
2031 if (nvalue != NULL)
2032 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002033 } else
2034 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002035 }
2036 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002037}
2038
2039static int xmlRelaxNGTypeInitialized = 0;
2040static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2041
2042/**
2043 * xmlRelaxNGFreeTypeLibrary:
2044 * @lib: the type library structure
2045 * @namespace: the URI bound to the library
2046 *
2047 * Free the structure associated to the type library
2048 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002049static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002050xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2051 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2052 if (lib == NULL)
2053 return;
2054 if (lib->namespace != NULL)
2055 xmlFree((xmlChar *)lib->namespace);
2056 xmlFree(lib);
2057}
2058
2059/**
2060 * xmlRelaxNGRegisterTypeLibrary:
2061 * @namespace: the URI bound to the library
2062 * @data: data associated to the library
2063 * @have: the provide function
2064 * @check: the checking function
2065 * @comp: the comparison function
2066 *
2067 * Register a new type library
2068 *
2069 * Returns 0 in case of success and -1 in case of error.
2070 */
2071static int
2072xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2073 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002074 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2075 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002076 xmlRelaxNGTypeLibraryPtr lib;
2077 int ret;
2078
2079 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2080 (check == NULL) || (comp == NULL))
2081 return(-1);
2082 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2083 xmlGenericError(xmlGenericErrorContext,
2084 "Relax-NG types library '%s' already registered\n",
2085 namespace);
2086 return(-1);
2087 }
2088 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2089 if (lib == NULL) {
2090 xmlGenericError(xmlGenericErrorContext,
2091 "Relax-NG types library '%s' malloc() failed\n",
2092 namespace);
2093 return (-1);
2094 }
2095 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2096 lib->namespace = xmlStrdup(namespace);
2097 lib->data = data;
2098 lib->have = have;
2099 lib->comp = comp;
2100 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002101 lib->facet = facet;
2102 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002103 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2104 if (ret < 0) {
2105 xmlGenericError(xmlGenericErrorContext,
2106 "Relax-NG types library failed to register '%s'\n",
2107 namespace);
2108 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2109 return(-1);
2110 }
2111 return(0);
2112}
2113
2114/**
2115 * xmlRelaxNGInitTypes:
2116 *
2117 * Initilize the default type libraries.
2118 *
2119 * Returns 0 in case of success and -1 in case of error.
2120 */
2121static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002122xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002123 if (xmlRelaxNGTypeInitialized != 0)
2124 return(0);
2125 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2126 if (xmlRelaxNGRegisteredTypes == NULL) {
2127 xmlGenericError(xmlGenericErrorContext,
2128 "Failed to allocate sh table for Relax-NG types\n");
2129 return(-1);
2130 }
2131 xmlRelaxNGRegisterTypeLibrary(
2132 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2133 NULL,
2134 xmlRelaxNGSchemaTypeHave,
2135 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002136 xmlRelaxNGSchemaTypeCompare,
2137 xmlRelaxNGSchemaFacetCheck,
2138 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002139 xmlRelaxNGRegisterTypeLibrary(
2140 xmlRelaxNGNs,
2141 NULL,
2142 xmlRelaxNGDefaultTypeHave,
2143 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002144 xmlRelaxNGDefaultTypeCompare,
2145 NULL,
2146 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002147 xmlRelaxNGTypeInitialized = 1;
2148 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002149}
2150
2151/**
2152 * xmlRelaxNGCleanupTypes:
2153 *
2154 * Cleanup the default Schemas type library associated to RelaxNG
2155 */
2156void
2157xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002158 if (xmlRelaxNGTypeInitialized == 0)
2159 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002160 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002161 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2162 xmlRelaxNGFreeTypeLibrary);
2163 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002164}
2165
2166/************************************************************************
2167 * *
2168 * Parsing functions *
2169 * *
2170 ************************************************************************/
2171
2172static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2173 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2174static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2175 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2176static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002177 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002178static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2179 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002180static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2181 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002182static int xmlRelaxNGParseGrammarContent(
2183 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002184static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2185 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2186 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002187static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2188 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard17bed982003-02-24 20:11:43 +00002189static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2190 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002191
2192
2193#define IS_BLANK_NODE(n) \
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002194 ((((n)->type == XML_TEXT_NODE) || \
2195 ((n)->type == XML_CDATA_SECTION_NODE)) && \
2196 (xmlRelaxNGIsBlank((n)->content)))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002197
2198/**
2199 * xmlRelaxNGIsBlank:
2200 * @str: a string
2201 *
2202 * Check if a string is ignorable c.f. 4.2. Whitespace
2203 *
2204 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2205 */
2206static int
2207xmlRelaxNGIsBlank(xmlChar *str) {
2208 if (str == NULL)
2209 return(1);
2210 while (*str != 0) {
2211 if (!(IS_BLANK(*str))) return(0);
2212 str++;
2213 }
2214 return(1);
2215}
2216
Daniel Veillard6eadf632003-01-23 18:29:16 +00002217/**
2218 * xmlRelaxNGGetDataTypeLibrary:
2219 * @ctxt: a Relax-NG parser context
2220 * @node: the current data or value element
2221 *
2222 * Applies algorithm from 4.3. datatypeLibrary attribute
2223 *
2224 * Returns the datatypeLibary value or NULL if not found
2225 */
2226static xmlChar *
2227xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2228 xmlNodePtr node) {
2229 xmlChar *ret, *escape;
2230
Daniel Veillard6eadf632003-01-23 18:29:16 +00002231 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2232 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2233 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002234 if (ret[0] == 0) {
2235 xmlFree(ret);
2236 return(NULL);
2237 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002238 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002239 if (escape == NULL) {
2240 return(ret);
2241 }
2242 xmlFree(ret);
2243 return(escape);
2244 }
2245 }
2246 node = node->parent;
2247 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002248 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2249 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002250 if (ret[0] == 0) {
2251 xmlFree(ret);
2252 return(NULL);
2253 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002254 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2255 if (escape == NULL) {
2256 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002257 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002258 xmlFree(ret);
2259 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002260 }
2261 node = node->parent;
2262 }
2263 return(NULL);
2264}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002265
2266/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002267 * xmlRelaxNGParseValue:
2268 * @ctxt: a Relax-NG parser context
2269 * @node: the data node.
2270 *
2271 * parse the content of a RelaxNG value node.
2272 *
2273 * Returns the definition pointer or NULL in case of error
2274 */
2275static xmlRelaxNGDefinePtr
2276xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2277 xmlRelaxNGDefinePtr def = NULL;
2278 xmlRelaxNGTypeLibraryPtr lib;
2279 xmlChar *type;
2280 xmlChar *library;
2281 int tmp;
2282
2283 def = xmlRelaxNGNewDefine(ctxt, node);
2284 if (def == NULL)
2285 return(NULL);
2286 def->type = XML_RELAXNG_VALUE;
2287
2288 type = xmlGetProp(node, BAD_CAST "type");
2289 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002290 xmlRelaxNGNormExtSpace(type);
2291 if (xmlValidateNCName(type, 0)) {
2292 if (ctxt->error != NULL)
2293 ctxt->error(ctxt->userData,
2294 "value type '%s' is not an NCName\n",
2295 type);
2296 ctxt->nbErrors++;
2297 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002298 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2299 if (library == NULL)
2300 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2301
2302 def->name = type;
2303 def->ns = library;
2304
2305 lib = (xmlRelaxNGTypeLibraryPtr)
2306 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2307 if (lib == NULL) {
2308 if (ctxt->error != NULL)
2309 ctxt->error(ctxt->userData,
2310 "Use of unregistered type library '%s'\n",
2311 library);
2312 ctxt->nbErrors++;
2313 def->data = NULL;
2314 } else {
2315 def->data = lib;
2316 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002317 if (ctxt->error != NULL)
2318 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002319 "Internal error with type library '%s': no 'have'\n",
2320 library);
2321 ctxt->nbErrors++;
2322 } else {
2323 tmp = lib->have(lib->data, def->name);
2324 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002325 if (ctxt->error != NULL)
2326 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002327 "Error type '%s' is not exported by type library '%s'\n",
2328 def->name, library);
2329 ctxt->nbErrors++;
2330 }
2331 }
2332 }
2333 }
2334 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002335 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002336 } else if (((node->children->type != XML_TEXT_NODE) &&
2337 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002338 (node->children->next != NULL)) {
2339 if (ctxt->error != NULL)
2340 ctxt->error(ctxt->userData,
2341 "Expecting a single text value for <value>content\n");
2342 ctxt->nbErrors++;
2343 } else {
2344 def->value = xmlNodeGetContent(node);
2345 if (def->value == NULL) {
2346 if (ctxt->error != NULL)
2347 ctxt->error(ctxt->userData,
2348 "Element <value> has no content\n");
2349 ctxt->nbErrors++;
2350 }
2351 }
2352 /* TODO check ahead of time that the value is okay per the type */
2353 return(def);
2354}
2355
2356/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002357 * xmlRelaxNGParseData:
2358 * @ctxt: a Relax-NG parser context
2359 * @node: the data node.
2360 *
2361 * parse the content of a RelaxNG data node.
2362 *
2363 * Returns the definition pointer or NULL in case of error
2364 */
2365static xmlRelaxNGDefinePtr
2366xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002367 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002368 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002369 xmlRelaxNGTypeLibraryPtr lib;
2370 xmlChar *type;
2371 xmlChar *library;
2372 xmlNodePtr content;
2373 int tmp;
2374
2375 type = xmlGetProp(node, BAD_CAST "type");
2376 if (type == NULL) {
2377 if (ctxt->error != NULL)
2378 ctxt->error(ctxt->userData,
2379 "data has no type\n");
2380 ctxt->nbErrors++;
2381 return(NULL);
2382 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002383 xmlRelaxNGNormExtSpace(type);
2384 if (xmlValidateNCName(type, 0)) {
2385 if (ctxt->error != NULL)
2386 ctxt->error(ctxt->userData,
2387 "data type '%s' is not an NCName\n",
2388 type);
2389 ctxt->nbErrors++;
2390 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002391 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2392 if (library == NULL)
2393 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2394
2395 def = xmlRelaxNGNewDefine(ctxt, node);
2396 if (def == NULL) {
2397 xmlFree(type);
2398 return(NULL);
2399 }
2400 def->type = XML_RELAXNG_DATATYPE;
2401 def->name = type;
2402 def->ns = library;
2403
2404 lib = (xmlRelaxNGTypeLibraryPtr)
2405 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2406 if (lib == NULL) {
2407 if (ctxt->error != NULL)
2408 ctxt->error(ctxt->userData,
2409 "Use of unregistered type library '%s'\n",
2410 library);
2411 ctxt->nbErrors++;
2412 def->data = NULL;
2413 } else {
2414 def->data = lib;
2415 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002416 if (ctxt->error != NULL)
2417 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002418 "Internal error with type library '%s': no 'have'\n",
2419 library);
2420 ctxt->nbErrors++;
2421 } else {
2422 tmp = lib->have(lib->data, def->name);
2423 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002424 if (ctxt->error != NULL)
2425 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002426 "Error type '%s' is not exported by type library '%s'\n",
2427 def->name, library);
2428 ctxt->nbErrors++;
2429 }
2430 }
2431 }
2432 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002433
2434 /*
2435 * Handle optional params
2436 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002437 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002438 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2439 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002440 if (xmlStrEqual(library,
2441 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2442 if (ctxt->error != NULL)
2443 ctxt->error(ctxt->userData,
2444 "Type library '%s' does not allow type parameters\n",
2445 library);
2446 ctxt->nbErrors++;
2447 content = content->next;
2448 while ((content != NULL) &&
2449 (xmlStrEqual(content->name, BAD_CAST "param")))
2450 content = content->next;
2451 } else {
2452 param = xmlRelaxNGNewDefine(ctxt, node);
2453 if (param != NULL) {
2454 param->type = XML_RELAXNG_PARAM;
2455 param->name = xmlGetProp(content, BAD_CAST "name");
2456 if (param->name == NULL) {
2457 if (ctxt->error != NULL)
2458 ctxt->error(ctxt->userData,
2459 "param has no name\n");
2460 ctxt->nbErrors++;
2461 }
2462 param->value = xmlNodeGetContent(content);
2463 if (lastparam == NULL) {
2464 def->attrs = lastparam = param;
2465 } else {
2466 lastparam->next = param;
2467 lastparam = param;
2468 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002469 if (lib != NULL) {
2470 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002471 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002472 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002473 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002474 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002475 /*
2476 * Handle optional except
2477 */
2478 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2479 xmlNodePtr child;
2480 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2481
2482 except = xmlRelaxNGNewDefine(ctxt, node);
2483 if (except == NULL) {
2484 return(def);
2485 }
2486 except->type = XML_RELAXNG_EXCEPT;
2487 child = content->children;
2488 if (last == NULL) {
2489 def->content = except;
2490 } else {
2491 last->next = except;
2492 }
2493 if (child == NULL) {
2494 if (ctxt->error != NULL)
2495 ctxt->error(ctxt->userData,
2496 "except has no content\n");
2497 ctxt->nbErrors++;
2498 }
2499 while (child != NULL) {
2500 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2501 if (tmp2 != NULL) {
2502 if (last2 == NULL) {
2503 except->content = last2 = tmp2;
2504 } else {
2505 last2->next = tmp2;
2506 last2 = tmp2;
2507 }
2508 }
2509 child = child->next;
2510 }
2511 content = content->next;
2512 }
2513 /*
2514 * Check there is no unhandled data
2515 */
2516 if (content != NULL) {
2517 if (ctxt->error != NULL)
2518 ctxt->error(ctxt->userData,
2519 "Element data has unexpected content %s\n", content->name);
2520 ctxt->nbErrors++;
2521 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002522
2523 return(def);
2524}
2525
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002526static const xmlChar *invalidName = BAD_CAST "\1";
2527
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002528/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002529 * xmlRelaxNGCompareNameClasses:
2530 * @defs1: the first element/attribute defs
2531 * @defs2: the second element/attribute defs
2532 * @name: the restriction on the name
2533 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002534 *
2535 * Compare the 2 lists of element definitions. The comparison is
2536 * that if both lists do not accept the same QNames, it returns 1
2537 * If the 2 lists can accept the same QName the comparison returns 0
2538 *
2539 * Returns 1 disttinct, 0 if equal
2540 */
2541static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002542xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2543 xmlRelaxNGDefinePtr def2) {
2544 int ret = 1;
2545 xmlNode node;
2546 xmlNs ns;
2547 xmlRelaxNGValidCtxt ctxt;
2548 ctxt.flags = FLAGS_IGNORABLE;
2549
Daniel Veillard42f12e92003-03-07 18:32:59 +00002550 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
2551
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002552 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2553 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2554 if (def2->type == XML_RELAXNG_TEXT)
2555 return(1);
2556 if (def1->name != NULL) {
2557 node.name = def1->name;
2558 } else {
2559 node.name = invalidName;
2560 }
2561 node.ns = &ns;
2562 if (def1->ns != NULL) {
2563 if (def1->ns[0] == 0) {
2564 node.ns = NULL;
2565 } else {
2566 ns.href = def1->ns;
2567 }
2568 } else {
2569 ns.href = invalidName;
2570 }
2571 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
2572 if (def1->nameClass != NULL) {
2573 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2574 } else {
2575 ret = 0;
2576 }
2577 } else {
2578 ret = 1;
2579 }
2580 } else if (def1->type == XML_RELAXNG_TEXT) {
2581 if (def2->type == XML_RELAXNG_TEXT)
2582 return(0);
2583 return(1);
2584 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002585 TODO
2586 ret = 0;
2587 } else {
2588 TODO
2589 ret = 0;
2590 }
2591 if (ret == 0)
2592 return(ret);
2593 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2594 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2595 if (def2->name != NULL) {
2596 node.name = def2->name;
2597 } else {
2598 node.name = invalidName;
2599 }
2600 node.ns = &ns;
2601 if (def2->ns != NULL) {
2602 if (def2->ns[0] == 0) {
2603 node.ns = NULL;
2604 } else {
2605 ns.href = def2->ns;
2606 }
2607 } else {
2608 ns.href = invalidName;
2609 }
2610 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
2611 if (def2->nameClass != NULL) {
2612 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2613 } else {
2614 ret = 0;
2615 }
2616 } else {
2617 ret = 1;
2618 }
2619 } else {
2620 TODO
2621 ret = 0;
2622 }
2623
2624 return(ret);
2625}
2626
2627/**
2628 * xmlRelaxNGCompareElemDefLists:
2629 * @ctxt: a Relax-NG parser context
2630 * @defs1: the first list of element/attribute defs
2631 * @defs2: the second list of element/attribute defs
2632 *
2633 * Compare the 2 lists of element or attribute definitions. The comparison
2634 * is that if both lists do not accept the same QNames, it returns 1
2635 * If the 2 lists can accept the same QName the comparison returns 0
2636 *
2637 * Returns 1 disttinct, 0 if equal
2638 */
2639static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002640xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2641 xmlRelaxNGDefinePtr *def1,
2642 xmlRelaxNGDefinePtr *def2) {
2643 xmlRelaxNGDefinePtr *basedef2 = def2;
2644
Daniel Veillard154877e2003-01-30 12:17:05 +00002645 if ((def1 == NULL) || (def2 == NULL))
2646 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002647 if ((*def1 == NULL) || (*def2 == NULL))
2648 return(1);
2649 while (*def1 != NULL) {
2650 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002651 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2652 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002653 def2++;
2654 }
2655 def2 = basedef2;
2656 def1++;
2657 }
2658 return(1);
2659}
2660
2661/**
2662 * xmlRelaxNGGetElements:
2663 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002664 * @def: the definition definition
2665 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002666 *
2667 * Compute the list of top elements a definition can generate
2668 *
2669 * Returns a list of elements or NULL if none was found.
2670 */
2671static xmlRelaxNGDefinePtr *
2672xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002673 xmlRelaxNGDefinePtr def,
2674 int eora) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002675 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
2676 int len = 0;
2677 int max = 0;
2678
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002679 /*
2680 * Don't run that check in case of error. Infinite recursion
2681 * becomes possible.
2682 */
2683 if (ctxt->nbErrors != 0)
2684 return(NULL);
2685
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002686 parent = NULL;
2687 cur = def;
2688 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002689 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
2690 (cur->type == XML_RELAXNG_TEXT))) ||
2691 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002692 if (ret == NULL) {
2693 max = 10;
2694 ret = (xmlRelaxNGDefinePtr *)
2695 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
2696 if (ret == NULL) {
2697 if (ctxt->error != NULL)
2698 ctxt->error(ctxt->userData,
2699 "Out of memory in element search\n");
2700 ctxt->nbErrors++;
2701 return(NULL);
2702 }
2703 } else if (max <= len) {
2704 max *= 2;
2705 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
2706 if (ret == NULL) {
2707 if (ctxt->error != NULL)
2708 ctxt->error(ctxt->userData,
2709 "Out of memory in element search\n");
2710 ctxt->nbErrors++;
2711 return(NULL);
2712 }
2713 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00002714 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002715 ret[len] = NULL;
2716 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
2717 (cur->type == XML_RELAXNG_INTERLEAVE) ||
2718 (cur->type == XML_RELAXNG_GROUP) ||
2719 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00002720 (cur->type == XML_RELAXNG_ZEROORMORE) ||
2721 (cur->type == XML_RELAXNG_OPTIONAL) ||
2722 (cur->type == XML_RELAXNG_REF) ||
2723 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002724 /*
2725 * Don't go within elements or attributes or string values.
2726 * Just gather the element top list
2727 */
2728 if (cur->content != NULL) {
2729 parent = cur;
2730 cur = cur->content;
2731 tmp = cur;
2732 while (tmp != NULL) {
2733 tmp->parent = parent;
2734 tmp = tmp->next;
2735 }
2736 continue;
2737 }
2738 }
Daniel Veillard154877e2003-01-30 12:17:05 +00002739 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002740 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002741 if (cur->next != NULL) {
2742 cur = cur->next;
2743 continue;
2744 }
2745 do {
2746 cur = cur->parent;
2747 if (cur == NULL) break;
2748 if (cur == def) return(ret);
2749 if (cur->next != NULL) {
2750 cur = cur->next;
2751 break;
2752 }
2753 } while (cur != NULL);
2754 }
2755 return(ret);
2756}
2757
2758/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002759 * xmlRelaxNGCheckGroupAttrs:
2760 * @ctxt: a Relax-NG parser context
2761 * @def: the group definition
2762 *
2763 * Detects violations of rule 7.3
2764 */
2765static void
2766xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
2767 xmlRelaxNGDefinePtr def) {
2768 xmlRelaxNGDefinePtr **list;
2769 xmlRelaxNGDefinePtr cur;
2770 int nbchild = 0, i, j, ret;
2771
2772 if ((def == NULL) ||
2773 ((def->type != XML_RELAXNG_GROUP) &&
2774 (def->type != XML_RELAXNG_ELEMENT)))
2775 return;
2776
2777 /*
2778 * Don't run that check in case of error. Infinite recursion
2779 * becomes possible.
2780 */
2781 if (ctxt->nbErrors != 0)
2782 return;
2783
2784 cur = def->attrs;
2785 while (cur != NULL) {
2786 nbchild++;
2787 cur = cur->next;
2788 }
2789 cur = def->content;
2790 while (cur != NULL) {
2791 nbchild++;
2792 cur = cur->next;
2793 }
2794
2795 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
2796 sizeof(xmlRelaxNGDefinePtr *));
2797 if (list == NULL) {
2798 if (ctxt->error != NULL)
2799 ctxt->error(ctxt->userData,
2800 "Out of memory in group computation\n");
2801 ctxt->nbErrors++;
2802 return;
2803 }
2804 i = 0;
2805 cur = def->attrs;
2806 while (cur != NULL) {
2807 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2808 i++;
2809 cur = cur->next;
2810 }
2811 cur = def->content;
2812 while (cur != NULL) {
2813 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2814 i++;
2815 cur = cur->next;
2816 }
2817
2818 for (i = 0;i < nbchild;i++) {
2819 if (list[i] == NULL)
2820 continue;
2821 for (j = 0;j < i;j++) {
2822 if (list[j] == NULL)
2823 continue;
2824 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
2825 if (ret == 0) {
2826 if (ctxt->error != NULL)
2827 ctxt->error(ctxt->userData,
2828 "Attributes conflicts in group\n");
2829 ctxt->nbErrors++;
2830 }
2831 }
2832 }
2833 for (i = 0;i < nbchild;i++) {
2834 if (list[i] != NULL)
2835 xmlFree(list[i]);
2836 }
2837 xmlFree(list);
2838}
2839
2840/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002841 * xmlRelaxNGComputeInterleaves:
2842 * @def: the interleave definition
2843 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002844 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002845 *
2846 * A lot of work for preprocessing interleave definitions
2847 * is potentially needed to get a decent execution speed at runtime
2848 * - trying to get a total order on the element nodes generated
2849 * by the interleaves, order the list of interleave definitions
2850 * following that order.
2851 * - if <text/> is used to handle mixed content, it is better to
2852 * flag this in the define and simplify the runtime checking
2853 * algorithm
2854 */
2855static void
2856xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
2857 xmlRelaxNGParserCtxtPtr ctxt,
2858 xmlChar *name ATTRIBUTE_UNUSED) {
2859 xmlRelaxNGDefinePtr cur;
2860
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002861 xmlRelaxNGPartitionPtr partitions = NULL;
2862 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
2863 xmlRelaxNGInterleaveGroupPtr group;
2864 int i,j,ret;
2865 int nbgroups = 0;
2866 int nbchild = 0;
2867
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002868 /*
2869 * Don't run that check in case of error. Infinite recursion
2870 * becomes possible.
2871 */
2872 if (ctxt->nbErrors != 0)
2873 return;
2874
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002875#ifdef DEBUG_INTERLEAVE
2876 xmlGenericError(xmlGenericErrorContext,
2877 "xmlRelaxNGComputeInterleaves(%s)\n",
2878 name);
2879#endif
2880 cur = def->content;
2881 while (cur != NULL) {
2882 nbchild++;
2883 cur = cur->next;
2884 }
2885
2886#ifdef DEBUG_INTERLEAVE
2887 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
2888#endif
2889 groups = (xmlRelaxNGInterleaveGroupPtr *)
2890 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
2891 if (groups == NULL)
2892 goto error;
2893 cur = def->content;
2894 while (cur != NULL) {
Daniel Veillard154877e2003-01-30 12:17:05 +00002895 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
2896 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
2897 if (groups[nbgroups] == NULL)
2898 goto error;
2899 groups[nbgroups]->rule = cur;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002900 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
2901 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
Daniel Veillard154877e2003-01-30 12:17:05 +00002902 nbgroups++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002903 cur = cur->next;
2904 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002905#ifdef DEBUG_INTERLEAVE
2906 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
2907#endif
2908
2909 /*
2910 * Let's check that all rules makes a partitions according to 7.4
2911 */
2912 partitions = (xmlRelaxNGPartitionPtr)
2913 xmlMalloc(sizeof(xmlRelaxNGPartition));
2914 if (partitions == NULL)
2915 goto error;
2916 partitions->nbgroups = nbgroups;
2917 for (i = 0;i < nbgroups;i++) {
2918 group = groups[i];
2919 for (j = i+1;j < nbgroups;j++) {
2920 if (groups[j] == NULL)
2921 continue;
2922 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
2923 groups[j]->defs);
2924 if (ret == 0) {
2925 if (ctxt->error != NULL)
2926 ctxt->error(ctxt->userData,
2927 "Element or text conflicts in interleave\n");
2928 ctxt->nbErrors++;
2929 }
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002930 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
2931 groups[j]->attrs);
2932 if (ret == 0) {
2933 if (ctxt->error != NULL)
2934 ctxt->error(ctxt->userData,
2935 "Attributes conflicts in interleave\n");
2936 ctxt->nbErrors++;
2937 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002938 }
2939 }
2940 partitions->groups = groups;
2941
2942 /*
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002943 * and save the partition list back in the def
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002944 */
2945 def->data = partitions;
2946 return;
2947
2948error:
2949 if (ctxt->error != NULL)
2950 ctxt->error(ctxt->userData,
2951 "Out of memory in interleave computation\n");
2952 ctxt->nbErrors++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002953 if (groups != NULL) {
2954 for (i = 0;i < nbgroups;i++)
2955 if (groups[i] != NULL) {
2956 if (groups[i]->defs != NULL)
2957 xmlFree(groups[i]->defs);
2958 xmlFree(groups[i]);
2959 }
2960 xmlFree(groups);
2961 }
2962 xmlRelaxNGFreePartition(partitions);
2963}
2964
2965/**
2966 * xmlRelaxNGParseInterleave:
2967 * @ctxt: a Relax-NG parser context
2968 * @node: the data node.
2969 *
2970 * parse the content of a RelaxNG interleave node.
2971 *
2972 * Returns the definition pointer or NULL in case of error
2973 */
2974static xmlRelaxNGDefinePtr
2975xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2976 xmlRelaxNGDefinePtr def = NULL;
2977 xmlRelaxNGDefinePtr last = NULL, cur;
2978 xmlNodePtr child;
2979
2980 def = xmlRelaxNGNewDefine(ctxt, node);
2981 if (def == NULL) {
2982 return(NULL);
2983 }
2984 def->type = XML_RELAXNG_INTERLEAVE;
2985
2986 if (ctxt->interleaves == NULL)
2987 ctxt->interleaves = xmlHashCreate(10);
2988 if (ctxt->interleaves == NULL) {
2989 if (ctxt->error != NULL)
2990 ctxt->error(ctxt->userData,
2991 "Failed to create interleaves hash table\n");
2992 ctxt->nbErrors++;
2993 } else {
2994 char name[32];
2995
2996 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
2997 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
2998 if (ctxt->error != NULL)
2999 ctxt->error(ctxt->userData,
3000 "Failed to add %s to hash table\n", name);
3001 ctxt->nbErrors++;
3002 }
3003 }
3004 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003005 if (child == NULL) {
3006 if (ctxt->error != NULL)
3007 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3008 ctxt->nbErrors++;
3009 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003010 while (child != NULL) {
3011 if (IS_RELAXNG(child, "element")) {
3012 cur = xmlRelaxNGParseElement(ctxt, child);
3013 } else {
3014 cur = xmlRelaxNGParsePattern(ctxt, child);
3015 }
3016 if (cur != NULL) {
3017 cur->parent = def;
3018 if (last == NULL) {
3019 def->content = last = cur;
3020 } else {
3021 last->next = cur;
3022 last = cur;
3023 }
3024 }
3025 child = child->next;
3026 }
3027
3028 return(def);
3029}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003030
3031/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003032 * xmlRelaxNGParseInclude:
3033 * @ctxt: a Relax-NG parser context
3034 * @node: the include node
3035 *
3036 * Integrate the content of an include node in the current grammar
3037 *
3038 * Returns 0 in case of success or -1 in case of error
3039 */
3040static int
3041xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3042 xmlRelaxNGIncludePtr incl;
3043 xmlNodePtr root;
3044 int ret = 0, tmp;
3045
3046 incl = node->_private;
3047 if (incl == NULL) {
3048 if (ctxt->error != NULL)
3049 ctxt->error(ctxt->userData,
3050 "Include node has no data\n");
3051 ctxt->nbErrors++;
3052 return(-1);
3053 }
3054 root = xmlDocGetRootElement(incl->doc);
3055 if (root == NULL) {
3056 if (ctxt->error != NULL)
3057 ctxt->error(ctxt->userData,
3058 "Include document is empty\n");
3059 ctxt->nbErrors++;
3060 return(-1);
3061 }
3062 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3063 if (ctxt->error != NULL)
3064 ctxt->error(ctxt->userData,
3065 "Include document root is not a grammar\n");
3066 ctxt->nbErrors++;
3067 return(-1);
3068 }
3069
3070 /*
3071 * Merge the definition from both the include and the internal list
3072 */
3073 if (root->children != NULL) {
3074 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3075 if (tmp != 0)
3076 ret = -1;
3077 }
3078 if (node->children != NULL) {
3079 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3080 if (tmp != 0)
3081 ret = -1;
3082 }
3083 return(ret);
3084}
3085
3086/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003087 * xmlRelaxNGParseDefine:
3088 * @ctxt: a Relax-NG parser context
3089 * @node: the define node
3090 *
3091 * parse the content of a RelaxNG define element node.
3092 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003093 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003094 */
3095static int
3096xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3097 xmlChar *name;
3098 int ret = 0, tmp;
3099 xmlRelaxNGDefinePtr def;
3100 const xmlChar *olddefine;
3101
3102 name = xmlGetProp(node, BAD_CAST "name");
3103 if (name == NULL) {
3104 if (ctxt->error != NULL)
3105 ctxt->error(ctxt->userData,
3106 "define has no name\n");
3107 ctxt->nbErrors++;
3108 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003109 xmlRelaxNGNormExtSpace(name);
3110 if (xmlValidateNCName(name, 0)) {
3111 if (ctxt->error != NULL)
3112 ctxt->error(ctxt->userData,
3113 "define name '%s' is not an NCName\n",
3114 name);
3115 ctxt->nbErrors++;
3116 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003117 def = xmlRelaxNGNewDefine(ctxt, node);
3118 if (def == NULL) {
3119 xmlFree(name);
3120 return(-1);
3121 }
3122 def->type = XML_RELAXNG_DEF;
3123 def->name = name;
3124 if (node->children == NULL) {
3125 if (ctxt->error != NULL)
3126 ctxt->error(ctxt->userData,
3127 "define has no children\n");
3128 ctxt->nbErrors++;
3129 } else {
3130 olddefine = ctxt->define;
3131 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003132 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003133 ctxt->define = olddefine;
3134 }
3135 if (ctxt->grammar->defs == NULL)
3136 ctxt->grammar->defs = xmlHashCreate(10);
3137 if (ctxt->grammar->defs == NULL) {
3138 if (ctxt->error != NULL)
3139 ctxt->error(ctxt->userData,
3140 "Could not create definition hash\n");
3141 ctxt->nbErrors++;
3142 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003143 } else {
3144 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3145 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003146 xmlRelaxNGDefinePtr prev;
3147
3148 prev = xmlHashLookup(ctxt->grammar->defs, name);
3149 if (prev == NULL) {
3150 if (ctxt->error != NULL)
3151 ctxt->error(ctxt->userData,
3152 "Internal error on define aggregation of %s\n",
3153 name);
3154 ctxt->nbErrors++;
3155 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003156 } else {
3157 while (prev->nextHash != NULL)
3158 prev = prev->nextHash;
3159 prev->nextHash = def;
3160 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003161 }
3162 }
3163 }
3164 return(ret);
3165}
3166
3167/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003168 * xmlRelaxNGProcessExternalRef:
3169 * @ctxt: the parser context
3170 * @node: the externlRef node
3171 *
3172 * Process and compile an externlRef node
3173 *
3174 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3175 */
3176static xmlRelaxNGDefinePtr
3177xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3178 xmlRelaxNGDocumentPtr docu;
3179 xmlNodePtr root, tmp;
3180 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003181 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003182 xmlRelaxNGDefinePtr def;
3183
3184 docu = node->_private;
3185 if (docu != NULL) {
3186 def = xmlRelaxNGNewDefine(ctxt, node);
3187 if (def == NULL)
3188 return(NULL);
3189 def->type = XML_RELAXNG_EXTERNALREF;
3190
3191 if (docu->content == NULL) {
3192 /*
3193 * Then do the parsing for good
3194 */
3195 root = xmlDocGetRootElement(docu->doc);
3196 if (root == NULL) {
3197 if (ctxt->error != NULL)
3198 ctxt->error(ctxt->userData,
3199 "xmlRelaxNGParse: %s is empty\n",
3200 ctxt->URL);
3201 ctxt->nbErrors++;
3202 return (NULL);
3203 }
3204 /*
3205 * ns transmission rules
3206 */
3207 ns = xmlGetProp(root, BAD_CAST "ns");
3208 if (ns == NULL) {
3209 tmp = node;
3210 while ((tmp != NULL) &&
3211 (tmp->type == XML_ELEMENT_NODE)) {
3212 ns = xmlGetProp(tmp, BAD_CAST "ns");
3213 if (ns != NULL) {
3214 break;
3215 }
3216 tmp = tmp->parent;
3217 }
3218 if (ns != NULL) {
3219 xmlSetProp(root, BAD_CAST "ns", ns);
3220 newNs = 1;
3221 xmlFree(ns);
3222 }
3223 } else {
3224 xmlFree(ns);
3225 }
3226
3227 /*
3228 * Parsing to get a precompiled schemas.
3229 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003230 oldflags = ctxt->flags;
3231 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003232 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003233 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003234 if ((docu->schema != NULL) &&
3235 (docu->schema->topgrammar != NULL)) {
3236 docu->content = docu->schema->topgrammar->start;
3237 }
3238
3239 /*
3240 * the externalRef may be reused in a different ns context
3241 */
3242 if (newNs == 1) {
3243 xmlUnsetProp(root, BAD_CAST "ns");
3244 }
3245 }
3246 def->content = docu->content;
3247 } else {
3248 def = NULL;
3249 }
3250 return(def);
3251}
3252
3253/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003254 * xmlRelaxNGParsePattern:
3255 * @ctxt: a Relax-NG parser context
3256 * @node: the pattern node.
3257 *
3258 * parse the content of a RelaxNG pattern node.
3259 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003260 * Returns the definition pointer or NULL in case of error or if no
3261 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003262 */
3263static xmlRelaxNGDefinePtr
3264xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3265 xmlRelaxNGDefinePtr def = NULL;
3266
Daniel Veillardd2298792003-02-14 16:54:11 +00003267 if (node == NULL) {
3268 return(NULL);
3269 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003270 if (IS_RELAXNG(node, "element")) {
3271 def = xmlRelaxNGParseElement(ctxt, node);
3272 } else if (IS_RELAXNG(node, "attribute")) {
3273 def = xmlRelaxNGParseAttribute(ctxt, node);
3274 } else if (IS_RELAXNG(node, "empty")) {
3275 def = xmlRelaxNGNewDefine(ctxt, node);
3276 if (def == NULL)
3277 return(NULL);
3278 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003279 if (node->children != NULL) {
3280 if (ctxt->error != NULL)
3281 ctxt->error(ctxt->userData, "empty: had a child node\n");
3282 ctxt->nbErrors++;
3283 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003284 } else if (IS_RELAXNG(node, "text")) {
3285 def = xmlRelaxNGNewDefine(ctxt, node);
3286 if (def == NULL)
3287 return(NULL);
3288 def->type = XML_RELAXNG_TEXT;
3289 if (node->children != NULL) {
3290 if (ctxt->error != NULL)
3291 ctxt->error(ctxt->userData, "text: had a child node\n");
3292 ctxt->nbErrors++;
3293 }
3294 } else if (IS_RELAXNG(node, "zeroOrMore")) {
3295 def = xmlRelaxNGNewDefine(ctxt, node);
3296 if (def == NULL)
3297 return(NULL);
3298 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003299 if (node->children == NULL) {
3300 if (ctxt->error != NULL)
3301 ctxt->error(ctxt->userData,
3302 "Element %s is empty\n", node->name);
3303 ctxt->nbErrors++;
3304 } else {
3305 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3306 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003307 } else if (IS_RELAXNG(node, "oneOrMore")) {
3308 def = xmlRelaxNGNewDefine(ctxt, node);
3309 if (def == NULL)
3310 return(NULL);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003311 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003312 if (node->children == NULL) {
3313 if (ctxt->error != NULL)
3314 ctxt->error(ctxt->userData,
3315 "Element %s is empty\n", node->name);
3316 ctxt->nbErrors++;
3317 } else {
3318 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3319 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003320 } else if (IS_RELAXNG(node, "optional")) {
3321 def = xmlRelaxNGNewDefine(ctxt, node);
3322 if (def == NULL)
3323 return(NULL);
3324 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003325 if (node->children == NULL) {
3326 if (ctxt->error != NULL)
3327 ctxt->error(ctxt->userData,
3328 "Element %s is empty\n", node->name);
3329 ctxt->nbErrors++;
3330 } else {
3331 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3332 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003333 } else if (IS_RELAXNG(node, "choice")) {
3334 def = xmlRelaxNGNewDefine(ctxt, node);
3335 if (def == NULL)
3336 return(NULL);
3337 def->type = XML_RELAXNG_CHOICE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003338 if (node->children == NULL) {
3339 if (ctxt->error != NULL)
3340 ctxt->error(ctxt->userData,
3341 "Element %s is empty\n", node->name);
3342 ctxt->nbErrors++;
3343 } else {
3344 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3345 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003346 } else if (IS_RELAXNG(node, "group")) {
3347 def = xmlRelaxNGNewDefine(ctxt, node);
3348 if (def == NULL)
3349 return(NULL);
3350 def->type = XML_RELAXNG_GROUP;
Daniel Veillardd2298792003-02-14 16:54:11 +00003351 if (node->children == NULL) {
3352 if (ctxt->error != NULL)
3353 ctxt->error(ctxt->userData,
3354 "Element %s is empty\n", node->name);
3355 ctxt->nbErrors++;
3356 } else {
3357 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3358 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003359 } else if (IS_RELAXNG(node, "ref")) {
3360 def = xmlRelaxNGNewDefine(ctxt, node);
3361 if (def == NULL)
3362 return(NULL);
3363 def->type = XML_RELAXNG_REF;
3364 def->name = xmlGetProp(node, BAD_CAST "name");
3365 if (def->name == NULL) {
3366 if (ctxt->error != NULL)
3367 ctxt->error(ctxt->userData,
3368 "ref has no name\n");
3369 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003370 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003371 xmlRelaxNGNormExtSpace(def->name);
3372 if (xmlValidateNCName(def->name, 0)) {
3373 if (ctxt->error != NULL)
3374 ctxt->error(ctxt->userData,
3375 "ref name '%s' is not an NCName\n",
3376 def->name);
3377 ctxt->nbErrors++;
3378 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003379 }
3380 if (node->children != NULL) {
3381 if (ctxt->error != NULL)
3382 ctxt->error(ctxt->userData,
3383 "ref is not empty\n");
3384 ctxt->nbErrors++;
3385 }
3386 if (ctxt->grammar->refs == NULL)
3387 ctxt->grammar->refs = xmlHashCreate(10);
3388 if (ctxt->grammar->refs == NULL) {
3389 if (ctxt->error != NULL)
3390 ctxt->error(ctxt->userData,
3391 "Could not create references hash\n");
3392 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003393 def = NULL;
3394 } else {
3395 int tmp;
3396
3397 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
3398 if (tmp < 0) {
3399 xmlRelaxNGDefinePtr prev;
3400
3401 prev = (xmlRelaxNGDefinePtr)
3402 xmlHashLookup(ctxt->grammar->refs, def->name);
3403 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003404 if (def->name != NULL) {
3405 if (ctxt->error != NULL)
3406 ctxt->error(ctxt->userData,
3407 "Error refs definitions '%s'\n",
3408 def->name);
3409 } else {
3410 if (ctxt->error != NULL)
3411 ctxt->error(ctxt->userData,
3412 "Error refs definitions\n");
3413 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003414 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003415 def = NULL;
3416 } else {
3417 def->nextHash = prev->nextHash;
3418 prev->nextHash = def;
3419 }
3420 }
3421 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003422 } else if (IS_RELAXNG(node, "data")) {
3423 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003424 } else if (IS_RELAXNG(node, "value")) {
3425 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003426 } else if (IS_RELAXNG(node, "list")) {
3427 def = xmlRelaxNGNewDefine(ctxt, node);
3428 if (def == NULL)
3429 return(NULL);
3430 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00003431 if (node->children == NULL) {
3432 if (ctxt->error != NULL)
3433 ctxt->error(ctxt->userData,
3434 "Element %s is empty\n", node->name);
3435 ctxt->nbErrors++;
3436 } else {
3437 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3438 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003439 } else if (IS_RELAXNG(node, "interleave")) {
3440 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003441 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003442 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003443 } else if (IS_RELAXNG(node, "notAllowed")) {
3444 def = xmlRelaxNGNewDefine(ctxt, node);
3445 if (def == NULL)
3446 return(NULL);
3447 def->type = XML_RELAXNG_NOT_ALLOWED;
3448 if (node->children != NULL) {
3449 if (ctxt->error != NULL)
3450 ctxt->error(ctxt->userData,
3451 "xmlRelaxNGParse: notAllowed element is not empty\n");
3452 ctxt->nbErrors++;
3453 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003454 } else if (IS_RELAXNG(node, "grammar")) {
3455 xmlRelaxNGGrammarPtr grammar, old;
3456 xmlRelaxNGGrammarPtr oldparent;
3457
Daniel Veillardc482e262003-02-26 14:48:48 +00003458#ifdef DEBUG_GRAMMAR
3459 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
3460#endif
3461
Daniel Veillard419a7682003-02-03 23:22:49 +00003462 oldparent = ctxt->parentgrammar;
3463 old = ctxt->grammar;
3464 ctxt->parentgrammar = old;
3465 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
3466 if (old != NULL) {
3467 ctxt->grammar = old;
3468 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00003469#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00003470 if (grammar != NULL) {
3471 grammar->next = old->next;
3472 old->next = grammar;
3473 }
Daniel Veillardc482e262003-02-26 14:48:48 +00003474#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00003475 }
3476 if (grammar != NULL)
3477 def = grammar->start;
3478 else
3479 def = NULL;
3480 } else if (IS_RELAXNG(node, "parentRef")) {
3481 if (ctxt->parentgrammar == NULL) {
3482 if (ctxt->error != NULL)
3483 ctxt->error(ctxt->userData,
3484 "Use of parentRef without a parent grammar\n");
3485 ctxt->nbErrors++;
3486 return(NULL);
3487 }
3488 def = xmlRelaxNGNewDefine(ctxt, node);
3489 if (def == NULL)
3490 return(NULL);
3491 def->type = XML_RELAXNG_PARENTREF;
3492 def->name = xmlGetProp(node, BAD_CAST "name");
3493 if (def->name == NULL) {
3494 if (ctxt->error != NULL)
3495 ctxt->error(ctxt->userData,
3496 "parentRef has no name\n");
3497 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00003498 } else {
3499 xmlRelaxNGNormExtSpace(def->name);
3500 if (xmlValidateNCName(def->name, 0)) {
3501 if (ctxt->error != NULL)
3502 ctxt->error(ctxt->userData,
3503 "parentRef name '%s' is not an NCName\n",
3504 def->name);
3505 ctxt->nbErrors++;
3506 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003507 }
3508 if (node->children != NULL) {
3509 if (ctxt->error != NULL)
3510 ctxt->error(ctxt->userData,
3511 "parentRef is not empty\n");
3512 ctxt->nbErrors++;
3513 }
3514 if (ctxt->parentgrammar->refs == NULL)
3515 ctxt->parentgrammar->refs = xmlHashCreate(10);
3516 if (ctxt->parentgrammar->refs == NULL) {
3517 if (ctxt->error != NULL)
3518 ctxt->error(ctxt->userData,
3519 "Could not create references hash\n");
3520 ctxt->nbErrors++;
3521 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003522 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00003523 int tmp;
3524
3525 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3526 if (tmp < 0) {
3527 xmlRelaxNGDefinePtr prev;
3528
3529 prev = (xmlRelaxNGDefinePtr)
3530 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3531 if (prev == NULL) {
3532 if (ctxt->error != NULL)
3533 ctxt->error(ctxt->userData,
3534 "Internal error parentRef definitions '%s'\n",
3535 def->name);
3536 ctxt->nbErrors++;
3537 def = NULL;
3538 } else {
3539 def->nextHash = prev->nextHash;
3540 prev->nextHash = def;
3541 }
3542 }
3543 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003544 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003545 if (node->children == NULL) {
3546 if (ctxt->error != NULL)
3547 ctxt->error(ctxt->userData,
3548 "Mixed is empty\n");
3549 ctxt->nbErrors++;
3550 def = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003551 } else {
3552 def = xmlRelaxNGParseInterleave(ctxt, node);
3553 if (def != NULL) {
3554 xmlRelaxNGDefinePtr tmp;
Daniel Veillard2df2de22003-02-17 23:34:33 +00003555
3556 if ((def->content != NULL) && (def->content->next != NULL)) {
3557 tmp = xmlRelaxNGNewDefine(ctxt, node);
3558 if (tmp != NULL) {
3559 tmp->type = XML_RELAXNG_GROUP;
3560 tmp->content = def->content;
3561 def->content = tmp;
3562 }
3563 }
3564
Daniel Veillard416589a2003-02-17 17:25:42 +00003565 tmp = xmlRelaxNGNewDefine(ctxt, node);
3566 if (tmp == NULL)
3567 return(def);
3568 tmp->type = XML_RELAXNG_TEXT;
3569 tmp->next = def->content;
3570 def->content = tmp;
3571 }
3572 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003573 } else {
3574 if (ctxt->error != NULL)
3575 ctxt->error(ctxt->userData,
3576 "Unexpected node %s is not a pattern\n",
3577 node->name);
3578 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003579 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003580 }
3581 return(def);
3582}
3583
3584/**
3585 * xmlRelaxNGParseAttribute:
3586 * @ctxt: a Relax-NG parser context
3587 * @node: the element node
3588 *
3589 * parse the content of a RelaxNG attribute node.
3590 *
3591 * Returns the definition pointer or NULL in case of error.
3592 */
3593static xmlRelaxNGDefinePtr
3594xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003595 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003596 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003597 int old_flags;
3598
3599 ret = xmlRelaxNGNewDefine(ctxt, node);
3600 if (ret == NULL)
3601 return(NULL);
3602 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003603 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003604 child = node->children;
3605 if (child == NULL) {
3606 if (ctxt->error != NULL)
3607 ctxt->error(ctxt->userData,
3608 "xmlRelaxNGParseattribute: attribute has no children\n");
3609 ctxt->nbErrors++;
3610 return(ret);
3611 }
3612 old_flags = ctxt->flags;
3613 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003614 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3615 if (cur != NULL)
3616 child = child->next;
3617
Daniel Veillardd2298792003-02-14 16:54:11 +00003618 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00003619 cur = xmlRelaxNGParsePattern(ctxt, child);
3620 if (cur != NULL) {
3621 switch (cur->type) {
3622 case XML_RELAXNG_EMPTY:
3623 case XML_RELAXNG_NOT_ALLOWED:
3624 case XML_RELAXNG_TEXT:
3625 case XML_RELAXNG_ELEMENT:
3626 case XML_RELAXNG_DATATYPE:
3627 case XML_RELAXNG_VALUE:
3628 case XML_RELAXNG_LIST:
3629 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00003630 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003631 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003632 case XML_RELAXNG_DEF:
3633 case XML_RELAXNG_ONEORMORE:
3634 case XML_RELAXNG_ZEROORMORE:
3635 case XML_RELAXNG_OPTIONAL:
3636 case XML_RELAXNG_CHOICE:
3637 case XML_RELAXNG_GROUP:
3638 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00003639 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00003640 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003641 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003642 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003643 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00003644 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00003645 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00003646 if (ctxt->error != NULL)
3647 ctxt->error(ctxt->userData,
3648 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003649 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003650 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003651 case XML_RELAXNG_NOOP:
3652 TODO
3653 if (ctxt->error != NULL)
3654 ctxt->error(ctxt->userData,
3655 "Internal error, noop found\n");
3656 ctxt->nbErrors++;
3657 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003658 }
3659 }
3660 child = child->next;
3661 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003662 if (child != NULL) {
3663 if (ctxt->error != NULL)
3664 ctxt->error(ctxt->userData, "attribute has multiple children\n");
3665 ctxt->nbErrors++;
3666 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003667 ctxt->flags = old_flags;
3668 return(ret);
3669}
3670
3671/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003672 * xmlRelaxNGParseExceptNameClass:
3673 * @ctxt: a Relax-NG parser context
3674 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00003675 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003676 *
3677 * parse the content of a RelaxNG nameClass node.
3678 *
3679 * Returns the definition pointer or NULL in case of error.
3680 */
3681static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00003682xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
3683 xmlNodePtr node, int attr) {
3684 xmlRelaxNGDefinePtr ret, cur, last = NULL;
3685 xmlNodePtr child;
3686
Daniel Veillardd2298792003-02-14 16:54:11 +00003687 if (!IS_RELAXNG(node, "except")) {
3688 if (ctxt->error != NULL)
3689 ctxt->error(ctxt->userData,
3690 "Expecting an except node\n");
3691 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00003692 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003693 }
3694 if (node->next != NULL) {
3695 if (ctxt->error != NULL)
3696 ctxt->error(ctxt->userData,
3697 "exceptNameClass allows only a single except node\n");
3698 ctxt->nbErrors++;
3699 }
Daniel Veillard144fae12003-02-03 13:17:57 +00003700 if (node->children == NULL) {
3701 if (ctxt->error != NULL)
3702 ctxt->error(ctxt->userData,
3703 "except has no content\n");
3704 ctxt->nbErrors++;
3705 return(NULL);
3706 }
3707
3708 ret = xmlRelaxNGNewDefine(ctxt, node);
3709 if (ret == NULL)
3710 return(NULL);
3711 ret->type = XML_RELAXNG_EXCEPT;
3712 child = node->children;
3713 while (child != NULL) {
3714 cur = xmlRelaxNGNewDefine(ctxt, child);
3715 if (cur == NULL)
3716 break;
3717 if (attr)
3718 cur->type = XML_RELAXNG_ATTRIBUTE;
3719 else
3720 cur->type = XML_RELAXNG_ELEMENT;
3721
Daniel Veillard419a7682003-02-03 23:22:49 +00003722 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00003723 if (last == NULL) {
3724 ret->content = cur;
3725 } else {
3726 last->next = cur;
3727 }
3728 last = cur;
3729 }
3730 child = child->next;
3731 }
3732
3733 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003734}
3735
3736/**
3737 * xmlRelaxNGParseNameClass:
3738 * @ctxt: a Relax-NG parser context
3739 * @node: the nameClass node
3740 * @def: the current definition
3741 *
3742 * parse the content of a RelaxNG nameClass node.
3743 *
3744 * Returns the definition pointer or NULL in case of error.
3745 */
3746static xmlRelaxNGDefinePtr
3747xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3748 xmlRelaxNGDefinePtr def) {
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003749 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003750 xmlChar *val;
3751
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003752 ret = def;
3753 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
3754 (IS_RELAXNG(node, "nsName"))) {
3755 if ((def->type != XML_RELAXNG_ELEMENT) &&
3756 (def->type != XML_RELAXNG_ATTRIBUTE)) {
3757 ret = xmlRelaxNGNewDefine(ctxt, node);
3758 if (ret == NULL)
3759 return(NULL);
3760 ret->parent = def;
3761 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
3762 ret->type = XML_RELAXNG_ATTRIBUTE;
3763 else
3764 ret->type = XML_RELAXNG_ELEMENT;
3765 }
3766 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003767 if (IS_RELAXNG(node, "name")) {
3768 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00003769 xmlRelaxNGNormExtSpace(val);
3770 if (xmlValidateNCName(val, 0)) {
3771 if (ctxt->error != NULL) {
3772 if (node->parent != NULL)
3773 ctxt->error(ctxt->userData,
3774 "Element %s name '%s' is not an NCName\n",
3775 node->parent->name, val);
3776 else
3777 ctxt->error(ctxt->userData,
3778 "name '%s' is not an NCName\n",
3779 val);
3780 }
3781 ctxt->nbErrors++;
3782 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003783 ret->name = val;
3784 val = xmlGetProp(node, BAD_CAST "ns");
3785 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00003786 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3787 (val != NULL) &&
3788 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3789 ctxt->error(ctxt->userData,
3790 "Attribute with namespace '%s' is not allowed\n",
3791 val);
3792 ctxt->nbErrors++;
3793 }
3794 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3795 (val != NULL) &&
3796 (val[0] == 0) &&
3797 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
3798 ctxt->error(ctxt->userData,
3799 "Attribute with QName 'xmlns' is not allowed\n",
3800 val);
3801 ctxt->nbErrors++;
3802 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003803 } else if (IS_RELAXNG(node, "anyName")) {
3804 ret->name = NULL;
3805 ret->ns = NULL;
3806 if (node->children != NULL) {
3807 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00003808 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3809 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003810 }
3811 } else if (IS_RELAXNG(node, "nsName")) {
3812 ret->name = NULL;
3813 ret->ns = xmlGetProp(node, BAD_CAST "ns");
3814 if (ret->ns == NULL) {
3815 if (ctxt->error != NULL)
3816 ctxt->error(ctxt->userData,
3817 "nsName has no ns attribute\n");
3818 ctxt->nbErrors++;
3819 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003820 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3821 (ret->ns != NULL) &&
3822 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3823 ctxt->error(ctxt->userData,
3824 "Attribute with namespace '%s' is not allowed\n",
3825 ret->ns);
3826 ctxt->nbErrors++;
3827 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003828 if (node->children != NULL) {
3829 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00003830 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3831 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003832 }
3833 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003834 xmlNodePtr child;
3835 xmlRelaxNGDefinePtr last = NULL;
3836
Daniel Veillardd4310742003-02-18 21:12:46 +00003837 ret = xmlRelaxNGNewDefine(ctxt, node);
3838 if (ret == NULL)
3839 return(NULL);
3840 ret->parent = def;
3841 ret->type = XML_RELAXNG_CHOICE;
3842
Daniel Veillardd2298792003-02-14 16:54:11 +00003843 if (node->children == NULL) {
3844 if (ctxt->error != NULL)
3845 ctxt->error(ctxt->userData,
3846 "Element choice is empty\n");
3847 ctxt->nbErrors++;
3848 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003849
3850 child = node->children;
3851 while (child != NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003852 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
Daniel Veillardd2298792003-02-14 16:54:11 +00003853 if (tmp != NULL) {
3854 if (last == NULL) {
3855 last = ret->nameClass = tmp;
3856 } else {
3857 last->next = tmp;
3858 last = tmp;
3859 }
3860 }
3861 child = child->next;
3862 }
3863 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003864 } else {
3865 if (ctxt->error != NULL)
3866 ctxt->error(ctxt->userData,
3867 "expecting name, anyName, nsName or choice : got %s\n",
3868 node->name);
3869 ctxt->nbErrors++;
3870 return(NULL);
3871 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003872 if (ret != def) {
3873 if (def->nameClass == NULL) {
3874 def->nameClass = ret;
3875 } else {
3876 tmp = def->nameClass;
3877 while (tmp->next != NULL) {
3878 tmp = tmp->next;
3879 }
3880 tmp->next = ret;
3881 }
3882 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003883 return(ret);
3884}
3885
3886/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003887 * xmlRelaxNGParseElement:
3888 * @ctxt: a Relax-NG parser context
3889 * @node: the element node
3890 *
3891 * parse the content of a RelaxNG element node.
3892 *
3893 * Returns the definition pointer or NULL in case of error.
3894 */
3895static xmlRelaxNGDefinePtr
3896xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3897 xmlRelaxNGDefinePtr ret, cur, last;
3898 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003899 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003900
3901 ret = xmlRelaxNGNewDefine(ctxt, node);
3902 if (ret == NULL)
3903 return(NULL);
3904 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003905 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003906 child = node->children;
3907 if (child == NULL) {
3908 if (ctxt->error != NULL)
3909 ctxt->error(ctxt->userData,
3910 "xmlRelaxNGParseElement: element has no children\n");
3911 ctxt->nbErrors++;
3912 return(ret);
3913 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003914 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3915 if (cur != NULL)
3916 child = child->next;
3917
Daniel Veillard6eadf632003-01-23 18:29:16 +00003918 if (child == NULL) {
3919 if (ctxt->error != NULL)
3920 ctxt->error(ctxt->userData,
3921 "xmlRelaxNGParseElement: element has no content\n");
3922 ctxt->nbErrors++;
3923 return(ret);
3924 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003925 olddefine = ctxt->define;
3926 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003927 last = NULL;
3928 while (child != NULL) {
3929 cur = xmlRelaxNGParsePattern(ctxt, child);
3930 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003931 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003932 switch (cur->type) {
3933 case XML_RELAXNG_EMPTY:
3934 case XML_RELAXNG_NOT_ALLOWED:
3935 case XML_RELAXNG_TEXT:
3936 case XML_RELAXNG_ELEMENT:
3937 case XML_RELAXNG_DATATYPE:
3938 case XML_RELAXNG_VALUE:
3939 case XML_RELAXNG_LIST:
3940 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00003941 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003942 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003943 case XML_RELAXNG_DEF:
3944 case XML_RELAXNG_ZEROORMORE:
3945 case XML_RELAXNG_ONEORMORE:
3946 case XML_RELAXNG_OPTIONAL:
3947 case XML_RELAXNG_CHOICE:
3948 case XML_RELAXNG_GROUP:
3949 case XML_RELAXNG_INTERLEAVE:
3950 if (last == NULL) {
3951 ret->content = last = cur;
3952 } else {
3953 if ((last->type == XML_RELAXNG_ELEMENT) &&
3954 (ret->content == last)) {
3955 ret->content = xmlRelaxNGNewDefine(ctxt, node);
3956 if (ret->content != NULL) {
3957 ret->content->type = XML_RELAXNG_GROUP;
3958 ret->content->content = last;
3959 } else {
3960 ret->content = last;
3961 }
3962 }
3963 last->next = cur;
3964 last = cur;
3965 }
3966 break;
3967 case XML_RELAXNG_ATTRIBUTE:
3968 cur->next = ret->attrs;
3969 ret->attrs = cur;
3970 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003971 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00003972 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00003973 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003974 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003975 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003976 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003977 case XML_RELAXNG_NOOP:
3978 TODO
3979 if (ctxt->error != NULL)
3980 ctxt->error(ctxt->userData,
3981 "Internal error, noop found\n");
3982 ctxt->nbErrors++;
3983 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003984 }
3985 }
3986 child = child->next;
3987 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003988 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003989 return(ret);
3990}
3991
3992/**
3993 * xmlRelaxNGParsePatterns:
3994 * @ctxt: a Relax-NG parser context
3995 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00003996 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00003997 *
3998 * parse the content of a RelaxNG start node.
3999 *
4000 * Returns the definition pointer or NULL in case of error.
4001 */
4002static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004003xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4004 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004005 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004006
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004007 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004008 while (nodes != NULL) {
4009 if (IS_RELAXNG(nodes, "element")) {
4010 cur = xmlRelaxNGParseElement(ctxt, nodes);
4011 if (def == NULL) {
4012 def = last = cur;
4013 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004014 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4015 (def == last)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004016 def = xmlRelaxNGNewDefine(ctxt, nodes);
4017 def->type = XML_RELAXNG_GROUP;
4018 def->content = last;
4019 }
4020 last->next = cur;
4021 last = cur;
4022 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004023 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004024 } else {
4025 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004026 if (cur != NULL) {
4027 if (def == NULL) {
4028 def = last = cur;
4029 } else {
4030 last->next = cur;
4031 last = cur;
4032 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004033 }
4034 }
4035 nodes = nodes->next;
4036 }
4037 return(def);
4038}
4039
4040/**
4041 * xmlRelaxNGParseStart:
4042 * @ctxt: a Relax-NG parser context
4043 * @nodes: start children nodes
4044 *
4045 * parse the content of a RelaxNG start node.
4046 *
4047 * Returns 0 in case of success, -1 in case of error
4048 */
4049static int
4050xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4051 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004052 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004053
Daniel Veillardd2298792003-02-14 16:54:11 +00004054 if (nodes == NULL) {
4055 if (ctxt->error != NULL)
4056 ctxt->error(ctxt->userData,
4057 "start has no children\n");
4058 ctxt->nbErrors++;
4059 return(-1);
4060 }
4061 if (IS_RELAXNG(nodes, "empty")) {
4062 def = xmlRelaxNGNewDefine(ctxt, nodes);
4063 if (def == NULL)
4064 return(-1);
4065 def->type = XML_RELAXNG_EMPTY;
4066 if (nodes->children != NULL) {
4067 if (ctxt->error != NULL)
4068 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004069 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004070 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004071 } else if (IS_RELAXNG(nodes, "notAllowed")) {
4072 def = xmlRelaxNGNewDefine(ctxt, nodes);
4073 if (def == NULL)
4074 return(-1);
4075 def->type = XML_RELAXNG_NOT_ALLOWED;
4076 if (nodes->children != NULL) {
4077 if (ctxt->error != NULL)
4078 ctxt->error(ctxt->userData,
4079 "element notAllowed is not empty\n");
4080 ctxt->nbErrors++;
4081 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004082 } else {
4083 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004084 }
4085 if (ctxt->grammar->start != NULL) {
4086 last = ctxt->grammar->start;
4087 while (last->next != NULL)
4088 last = last->next;
4089 last->next = def;
4090 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004091 ctxt->grammar->start = def;
4092 }
4093 nodes = nodes->next;
4094 if (nodes != NULL) {
4095 if (ctxt->error != NULL)
4096 ctxt->error(ctxt->userData,
4097 "start more than one children\n");
4098 ctxt->nbErrors++;
4099 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004100 }
4101 return(ret);
4102}
4103
4104/**
4105 * xmlRelaxNGParseGrammarContent:
4106 * @ctxt: a Relax-NG parser context
4107 * @nodes: grammar children nodes
4108 *
4109 * parse the content of a RelaxNG grammar node.
4110 *
4111 * Returns 0 in case of success, -1 in case of error
4112 */
4113static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004114xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004115{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004116 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004117
4118 if (nodes == NULL) {
4119 if (ctxt->error != NULL)
4120 ctxt->error(ctxt->userData,
4121 "grammar has no children\n");
4122 ctxt->nbErrors++;
4123 return(-1);
4124 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004125 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004126 if (IS_RELAXNG(nodes, "start")) {
4127 if (nodes->children == NULL) {
4128 if (ctxt->error != NULL)
4129 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004130 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004131 ctxt->nbErrors++;
4132 } else {
4133 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4134 if (tmp != 0)
4135 ret = -1;
4136 }
4137 } else if (IS_RELAXNG(nodes, "define")) {
4138 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4139 if (tmp != 0)
4140 ret = -1;
4141 } else if (IS_RELAXNG(nodes, "include")) {
4142 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4143 if (tmp != 0)
4144 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004145 } else {
4146 if (ctxt->error != NULL)
4147 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004148 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004149 ctxt->nbErrors++;
4150 ret = -1;
4151 }
4152 nodes = nodes->next;
4153 }
4154 return (ret);
4155}
4156
4157/**
4158 * xmlRelaxNGCheckReference:
4159 * @ref: the ref
4160 * @ctxt: a Relax-NG parser context
4161 * @name: the name associated to the defines
4162 *
4163 * Applies the 4.17. combine attribute rule for all the define
4164 * element of a given grammar using the same name.
4165 */
4166static void
4167xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4168 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4169 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004170 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004171
4172 grammar = ctxt->grammar;
4173 if (grammar == NULL) {
4174 if (ctxt->error != NULL)
4175 ctxt->error(ctxt->userData,
4176 "Internal error: no grammar in CheckReference %s\n",
4177 name);
4178 ctxt->nbErrors++;
4179 return;
4180 }
4181 if (ref->content != NULL) {
4182 if (ctxt->error != NULL)
4183 ctxt->error(ctxt->userData,
4184 "Internal error: reference has content in CheckReference %s\n",
4185 name);
4186 ctxt->nbErrors++;
4187 return;
4188 }
4189 if (grammar->defs != NULL) {
4190 def = xmlHashLookup(grammar->defs, name);
4191 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004192 cur = ref;
4193 while (cur != NULL) {
4194 cur->content = def;
4195 cur = cur->nextHash;
4196 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004197 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004198 if (ctxt->error != NULL)
4199 ctxt->error(ctxt->userData,
4200 "Reference %s has no matching definition\n",
4201 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004202 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004203 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004204 } else {
4205 if (ctxt->error != NULL)
4206 ctxt->error(ctxt->userData,
4207 "Reference %s has no matching definition\n",
4208 name);
4209 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004210 }
4211 /*
4212 * TODO: make a closure and verify there is no loop !
4213 */
4214}
4215
4216/**
4217 * xmlRelaxNGCheckCombine:
4218 * @define: the define(s) list
4219 * @ctxt: a Relax-NG parser context
4220 * @name: the name associated to the defines
4221 *
4222 * Applies the 4.17. combine attribute rule for all the define
4223 * element of a given grammar using the same name.
4224 */
4225static void
4226xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4227 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4228 xmlChar *combine;
4229 int choiceOrInterleave = -1;
4230 int missing = 0;
4231 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4232
4233 if (define->nextHash == NULL)
4234 return;
4235 cur = define;
4236 while (cur != NULL) {
4237 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4238 if (combine != NULL) {
4239 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4240 if (choiceOrInterleave == -1)
4241 choiceOrInterleave = 1;
4242 else if (choiceOrInterleave == 0) {
4243 if (ctxt->error != NULL)
4244 ctxt->error(ctxt->userData,
4245 "Defines for %s use both 'choice' and 'interleave'\n",
4246 name);
4247 ctxt->nbErrors++;
4248 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004249 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004250 if (choiceOrInterleave == -1)
4251 choiceOrInterleave = 0;
4252 else if (choiceOrInterleave == 1) {
4253 if (ctxt->error != NULL)
4254 ctxt->error(ctxt->userData,
4255 "Defines for %s use both 'choice' and 'interleave'\n",
4256 name);
4257 ctxt->nbErrors++;
4258 }
4259 } else {
4260 if (ctxt->error != NULL)
4261 ctxt->error(ctxt->userData,
4262 "Defines for %s use unknown combine value '%s''\n",
4263 name, combine);
4264 ctxt->nbErrors++;
4265 }
4266 xmlFree(combine);
4267 } else {
4268 if (missing == 0)
4269 missing = 1;
4270 else {
4271 if (ctxt->error != NULL)
4272 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004273 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004274 name);
4275 ctxt->nbErrors++;
4276 }
4277 }
4278
4279 cur = cur->nextHash;
4280 }
4281#ifdef DEBUG
4282 xmlGenericError(xmlGenericErrorContext,
4283 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4284 name, choiceOrInterleave);
4285#endif
4286 if (choiceOrInterleave == -1)
4287 choiceOrInterleave = 0;
4288 cur = xmlRelaxNGNewDefine(ctxt, define->node);
4289 if (cur == NULL)
4290 return;
4291 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004292 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillard154877e2003-01-30 12:17:05 +00004293 else
4294 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004295 tmp = define;
4296 last = NULL;
4297 while (tmp != NULL) {
4298 if (tmp->content != NULL) {
4299 if (tmp->content->next != NULL) {
4300 /*
4301 * we need first to create a wrapper.
4302 */
4303 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
4304 if (tmp2 == NULL)
4305 break;
4306 tmp2->type = XML_RELAXNG_GROUP;
4307 tmp2->content = tmp->content;
4308 } else {
4309 tmp2 = tmp->content;
4310 }
4311 if (last == NULL) {
4312 cur->content = tmp2;
4313 } else {
4314 last->next = tmp2;
4315 }
4316 last = tmp2;
4317 tmp->content = NULL;
4318 }
4319 tmp = tmp->nextHash;
4320 }
4321 define->content = cur;
Daniel Veillard154877e2003-01-30 12:17:05 +00004322 if (choiceOrInterleave == 0) {
4323 if (ctxt->interleaves == NULL)
4324 ctxt->interleaves = xmlHashCreate(10);
4325 if (ctxt->interleaves == NULL) {
4326 if (ctxt->error != NULL)
4327 ctxt->error(ctxt->userData,
4328 "Failed to create interleaves hash table\n");
4329 ctxt->nbErrors++;
4330 } else {
4331 char tmpname[32];
4332
4333 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4334 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4335 if (ctxt->error != NULL)
4336 ctxt->error(ctxt->userData,
4337 "Failed to add %s to hash table\n", tmpname);
4338 ctxt->nbErrors++;
4339 }
4340 }
4341 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004342}
4343
4344/**
4345 * xmlRelaxNGCombineStart:
4346 * @ctxt: a Relax-NG parser context
4347 * @grammar: the grammar
4348 *
4349 * Applies the 4.17. combine rule for all the start
4350 * element of a given grammar.
4351 */
4352static void
4353xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
4354 xmlRelaxNGGrammarPtr grammar) {
4355 xmlRelaxNGDefinePtr starts;
4356 xmlChar *combine;
4357 int choiceOrInterleave = -1;
4358 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004359 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004360
Daniel Veillard2df2de22003-02-17 23:34:33 +00004361 starts = grammar->start;
4362 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00004363 return;
4364 cur = starts;
4365 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00004366 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
4367 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
4368 combine = NULL;
4369 if (ctxt->error != NULL)
4370 ctxt->error(ctxt->userData,
4371 "Internal error: start element not found\n");
4372 ctxt->nbErrors++;
4373 } else {
4374 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
4375 }
4376
Daniel Veillard6eadf632003-01-23 18:29:16 +00004377 if (combine != NULL) {
4378 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4379 if (choiceOrInterleave == -1)
4380 choiceOrInterleave = 1;
4381 else if (choiceOrInterleave == 0) {
4382 if (ctxt->error != NULL)
4383 ctxt->error(ctxt->userData,
4384 "<start> use both 'choice' and 'interleave'\n");
4385 ctxt->nbErrors++;
4386 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00004387 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004388 if (choiceOrInterleave == -1)
4389 choiceOrInterleave = 0;
4390 else if (choiceOrInterleave == 1) {
4391 if (ctxt->error != NULL)
4392 ctxt->error(ctxt->userData,
4393 "<start> use both 'choice' and 'interleave'\n");
4394 ctxt->nbErrors++;
4395 }
4396 } else {
4397 if (ctxt->error != NULL)
4398 ctxt->error(ctxt->userData,
4399 "<start> uses unknown combine value '%s''\n", combine);
4400 ctxt->nbErrors++;
4401 }
4402 xmlFree(combine);
4403 } else {
4404 if (missing == 0)
4405 missing = 1;
4406 else {
4407 if (ctxt->error != NULL)
4408 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004409 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00004410 ctxt->nbErrors++;
4411 }
4412 }
4413
Daniel Veillard2df2de22003-02-17 23:34:33 +00004414 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004415 }
4416#ifdef DEBUG
4417 xmlGenericError(xmlGenericErrorContext,
4418 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
4419 choiceOrInterleave);
4420#endif
4421 if (choiceOrInterleave == -1)
4422 choiceOrInterleave = 0;
4423 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
4424 if (cur == NULL)
4425 return;
4426 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004427 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004428 else
4429 cur->type = XML_RELAXNG_CHOICE;
4430 cur->content = grammar->start;
4431 grammar->start = cur;
4432 if (choiceOrInterleave == 0) {
4433 if (ctxt->interleaves == NULL)
4434 ctxt->interleaves = xmlHashCreate(10);
4435 if (ctxt->interleaves == NULL) {
4436 if (ctxt->error != NULL)
4437 ctxt->error(ctxt->userData,
4438 "Failed to create interleaves hash table\n");
4439 ctxt->nbErrors++;
4440 } else {
4441 char tmpname[32];
4442
4443 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4444 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4445 if (ctxt->error != NULL)
4446 ctxt->error(ctxt->userData,
4447 "Failed to add %s to hash table\n", tmpname);
4448 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004449 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004450 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004451 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004452}
4453
4454/**
Daniel Veillardd4310742003-02-18 21:12:46 +00004455 * xmlRelaxNGCheckCycles:
4456 * @ctxt: a Relax-NG parser context
4457 * @nodes: grammar children nodes
4458 * @depth: the counter
4459 *
4460 * Check for cycles.
4461 *
4462 * Returns 0 if check passed, and -1 in case of error
4463 */
4464static int
4465xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
4466 xmlRelaxNGDefinePtr cur, int depth) {
4467 int ret = 0;
4468
4469 while ((ret == 0) && (cur != NULL)) {
4470 if ((cur->type == XML_RELAXNG_REF) ||
4471 (cur->type == XML_RELAXNG_PARENTREF)) {
4472 if (cur->depth == -1) {
4473 cur->depth = depth;
4474 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4475 cur->depth = -2;
4476 } else if (depth == cur->depth) {
4477 if (ctxt->error != NULL)
4478 ctxt->error(ctxt->userData,
4479 "Detected a cycle in %s references\n", cur->name);
4480 ctxt->nbErrors++;
4481 return(-1);
4482 }
4483 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4484 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4485 } else {
4486 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4487 }
4488 cur = cur->next;
4489 }
4490 return(ret);
4491}
4492
4493/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00004494 * xmlRelaxNGTryUnlink:
4495 * @ctxt: a Relax-NG parser context
4496 * @cur: the definition to unlink
4497 * @parent: the parent definition
4498 * @prev: the previous sibling definition
4499 *
4500 * Try to unlink a definition. If not possble make it a NOOP
4501 *
4502 * Returns the new prev definition
4503 */
4504static xmlRelaxNGDefinePtr
4505xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4506 xmlRelaxNGDefinePtr cur,
4507 xmlRelaxNGDefinePtr parent,
4508 xmlRelaxNGDefinePtr prev) {
4509 if (prev != NULL) {
4510 prev->next = cur->next;
4511 } else {
4512 if (parent != NULL) {
4513 if (parent->content == cur)
4514 parent->content = cur->next;
4515 else if (parent->attrs == cur)
4516 parent->attrs = cur->next;
4517 else if (parent->nameClass == cur)
4518 parent->nameClass = cur->next;
4519 } else {
4520 cur->type = XML_RELAXNG_NOOP;
4521 prev = cur;
4522 }
4523 }
4524 return(prev);
4525}
4526
4527/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004528 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004529 * @ctxt: a Relax-NG parser context
4530 * @nodes: grammar children nodes
4531 *
4532 * Check for simplification of empty and notAllowed
4533 */
4534static void
4535xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4536 xmlRelaxNGDefinePtr cur,
4537 xmlRelaxNGDefinePtr parent) {
4538 xmlRelaxNGDefinePtr prev = NULL;
4539
4540 while (cur != NULL) {
4541 if ((cur->type == XML_RELAXNG_REF) ||
4542 (cur->type == XML_RELAXNG_PARENTREF)) {
4543 if (cur->depth != -3) {
4544 cur->depth = -3;
4545 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4546 }
4547 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004548 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004549 if ((parent != NULL) &&
4550 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4551 (parent->type == XML_RELAXNG_LIST) ||
4552 (parent->type == XML_RELAXNG_GROUP) ||
4553 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4554 (parent->type == XML_RELAXNG_ONEORMORE) ||
4555 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4556 parent->type = XML_RELAXNG_NOT_ALLOWED;
4557 break;
4558 }
4559 if ((parent != NULL) &&
4560 (parent->type == XML_RELAXNG_CHOICE)) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004561 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004562 } else
4563 prev = cur;
4564 } else if (cur->type == XML_RELAXNG_EMPTY){
Daniel Veillard77648bb2003-02-20 15:03:22 +00004565 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004566 if ((parent != NULL) &&
4567 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4568 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4569 parent->type = XML_RELAXNG_EMPTY;
4570 break;
4571 }
4572 if ((parent != NULL) &&
4573 ((parent->type == XML_RELAXNG_GROUP) ||
4574 (parent->type == XML_RELAXNG_INTERLEAVE))) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004575 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004576 } else
4577 prev = cur;
4578 } else {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004579 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004580 if (cur->content != NULL)
4581 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004582 if (cur->attrs != NULL)
4583 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
4584 if (cur->nameClass != NULL)
4585 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004586 /*
4587 * This may result in a simplification
4588 */
4589 if ((cur->type == XML_RELAXNG_GROUP) ||
4590 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4591 if (cur->content == NULL)
4592 cur->type = XML_RELAXNG_EMPTY;
4593 else if (cur->content->next == NULL) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004594 if ((parent == NULL) && (prev == NULL)) {
4595 cur->type = XML_RELAXNG_NOOP;
4596 } else if (prev == NULL) {
4597 parent->content = cur->content;
4598 cur->content->next = cur->next;
4599 cur = cur->content;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004600 } else {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004601 cur->content->next = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004602 prev->next = cur->content;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004603 cur = cur->content;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004604 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004605 }
4606 }
4607 /*
4608 * the current node may have been transformed back
4609 */
4610 if ((cur->type == XML_RELAXNG_EXCEPT) &&
4611 (cur->content != NULL) &&
4612 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004613 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004614 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4615 if ((parent != NULL) &&
4616 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4617 (parent->type == XML_RELAXNG_LIST) ||
4618 (parent->type == XML_RELAXNG_GROUP) ||
4619 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4620 (parent->type == XML_RELAXNG_ONEORMORE) ||
4621 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4622 parent->type = XML_RELAXNG_NOT_ALLOWED;
4623 break;
4624 }
4625 if ((parent != NULL) &&
4626 (parent->type == XML_RELAXNG_CHOICE)) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004627 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004628 } else
4629 prev = cur;
4630 } else if (cur->type == XML_RELAXNG_EMPTY){
4631 if ((parent != NULL) &&
4632 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4633 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4634 parent->type = XML_RELAXNG_EMPTY;
4635 break;
4636 }
4637 if ((parent != NULL) &&
4638 ((parent->type == XML_RELAXNG_GROUP) ||
4639 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4640 (parent->type == XML_RELAXNG_CHOICE))) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004641 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004642 } else
4643 prev = cur;
4644 } else {
4645 prev = cur;
4646 }
4647 }
4648 cur = cur->next;
4649 }
4650}
4651
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004652/**
4653 * xmlRelaxNGGroupContentType:
4654 * @ct1: the first content type
4655 * @ct2: the second content type
4656 *
4657 * Try to group 2 content types
4658 *
4659 * Returns the content type
4660 */
4661static xmlRelaxNGContentType
4662xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
4663 xmlRelaxNGContentType ct2) {
4664 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4665 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4666 return(XML_RELAXNG_CONTENT_ERROR);
4667 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
4668 return(ct2);
4669 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
4670 return(ct1);
4671 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
4672 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4673 return(XML_RELAXNG_CONTENT_COMPLEX);
4674 return(XML_RELAXNG_CONTENT_ERROR);
4675}
4676
4677/**
4678 * xmlRelaxNGMaxContentType:
4679 * @ct1: the first content type
4680 * @ct2: the second content type
4681 *
4682 * Compute the max content-type
4683 *
4684 * Returns the content type
4685 */
4686static xmlRelaxNGContentType
4687xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
4688 xmlRelaxNGContentType ct2) {
4689 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4690 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4691 return(XML_RELAXNG_CONTENT_ERROR);
4692 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
4693 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
4694 return(XML_RELAXNG_CONTENT_SIMPLE);
4695 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
4696 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4697 return(XML_RELAXNG_CONTENT_COMPLEX);
4698 return(XML_RELAXNG_CONTENT_EMPTY);
4699}
Daniel Veillard77648bb2003-02-20 15:03:22 +00004700
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004701/**
4702 * xmlRelaxNGCheckRules:
4703 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004704 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00004705 * @flags: some accumulated flags
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004706 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004707 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004708 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004709 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004710 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004711 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004712static xmlRelaxNGContentType
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004713xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004714 xmlRelaxNGDefinePtr cur, int flags,
4715 xmlRelaxNGType ptype) {
4716 int nflags = flags;
4717 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004718
Daniel Veillard77648bb2003-02-20 15:03:22 +00004719 while (cur != NULL) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004720 ret = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004721 if ((cur->type == XML_RELAXNG_REF) ||
4722 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004723 if (flags & XML_RELAXNG_IN_LIST) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004724 if (ctxt->error != NULL)
4725 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004726 "Found forbidden pattern list//ref\n");
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004727 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004728 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00004729 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4730 if (ctxt->error != NULL)
4731 ctxt->error(ctxt->userData,
4732 "Found forbidden pattern data/except//ref\n");
4733 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004734 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00004735 if (cur->depth > -4) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004736 cur->depth = -4;
Daniel Veillardc5312d72003-02-21 17:14:10 +00004737 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
4738 flags, cur->type);
4739 cur->depth = ret - 15 ;
4740 } else if (cur->depth == -4) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004741 ret = XML_RELAXNG_CONTENT_COMPLEX;
Daniel Veillardc5312d72003-02-21 17:14:10 +00004742 } else {
4743 ret = (xmlRelaxNGContentType) cur->depth + 15;
4744 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004745 } else if (cur->type == XML_RELAXNG_ELEMENT) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004746 /*
4747 * The 7.3 Attribute derivation rule for groups is plugged there
4748 */
4749 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004750 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4751 if (ctxt->error != NULL)
4752 ctxt->error(ctxt->userData,
4753 "Found forbidden pattern data/except//element(ref)\n");
4754 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004755 }
4756 if (flags & XML_RELAXNG_IN_LIST) {
4757 if (ctxt->error != NULL)
4758 ctxt->error(ctxt->userData,
4759 "Found forbidden pattern list//element(ref)\n");
4760 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004761 }
4762 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4763 if (ctxt->error != NULL)
4764 ctxt->error(ctxt->userData,
4765 "Found forbidden pattern attribute//element(ref)\n");
4766 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004767 }
Daniel Veillard463a5472003-02-27 21:30:32 +00004768 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4769 if (ctxt->error != NULL)
4770 ctxt->error(ctxt->userData,
4771 "Found forbidden pattern attribute//element(ref)\n");
4772 ctxt->nbErrors++;
4773 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00004774 /*
4775 * reset since in the simple form elements are only child
4776 * of grammar/define
4777 */
4778 nflags = 0;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004779 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
4780 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
4781 if (ctxt->error != NULL)
4782 ctxt->error(ctxt->userData,
4783 "Element %s attributes have a content type error\n",
4784 cur->name);
4785 ctxt->nbErrors++;
4786 }
4787 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4788 if (ret == XML_RELAXNG_CONTENT_ERROR) {
4789 if (ctxt->error != NULL)
4790 ctxt->error(ctxt->userData,
4791 "Element %s has a content type error\n",
4792 cur->name);
4793 ctxt->nbErrors++;
4794 } else {
4795 ret = XML_RELAXNG_CONTENT_COMPLEX;
4796 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00004797 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
4798 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4799 if (ctxt->error != NULL)
4800 ctxt->error(ctxt->userData,
4801 "Found forbidden pattern attribute//attribute\n");
4802 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004803 }
4804 if (flags & XML_RELAXNG_IN_LIST) {
4805 if (ctxt->error != NULL)
4806 ctxt->error(ctxt->userData,
4807 "Found forbidden pattern list//attribute\n");
4808 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004809 }
4810 if (flags & XML_RELAXNG_IN_OOMGROUP) {
4811 if (ctxt->error != NULL)
4812 ctxt->error(ctxt->userData,
4813 "Found forbidden pattern oneOrMore//group//attribute\n");
4814 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004815 }
4816 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
4817 if (ctxt->error != NULL)
4818 ctxt->error(ctxt->userData,
4819 "Found forbidden pattern oneOrMore//interleave//attribute\n");
4820 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004821 }
4822 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4823 if (ctxt->error != NULL)
4824 ctxt->error(ctxt->userData,
4825 "Found forbidden pattern data/except//attribute\n");
4826 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004827 }
4828 if (flags & XML_RELAXNG_IN_START) {
4829 if (ctxt->error != NULL)
4830 ctxt->error(ctxt->userData,
4831 "Found forbidden pattern start//attribute\n");
4832 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004833 }
4834 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004835 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4836 ret = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004837 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
4838 (cur->type == XML_RELAXNG_ZEROORMORE)) {
4839 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4840 if (ctxt->error != NULL)
4841 ctxt->error(ctxt->userData,
4842 "Found forbidden pattern data/except//oneOrMore\n");
4843 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004844 }
4845 if (flags & XML_RELAXNG_IN_START) {
4846 if (ctxt->error != NULL)
4847 ctxt->error(ctxt->userData,
4848 "Found forbidden pattern start//oneOrMore\n");
4849 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004850 }
4851 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004852 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4853 ret = xmlRelaxNGGroupContentType(ret, ret);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004854 } else if (cur->type == XML_RELAXNG_LIST) {
4855 if (flags & XML_RELAXNG_IN_LIST) {
4856 if (ctxt->error != NULL)
4857 ctxt->error(ctxt->userData,
4858 "Found forbidden pattern list//list\n");
4859 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004860 }
4861 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4862 if (ctxt->error != NULL)
4863 ctxt->error(ctxt->userData,
4864 "Found forbidden pattern data/except//list\n");
4865 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004866 }
4867 if (flags & XML_RELAXNG_IN_START) {
4868 if (ctxt->error != NULL)
4869 ctxt->error(ctxt->userData,
4870 "Found forbidden pattern start//list\n");
4871 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004872 }
4873 nflags = flags | XML_RELAXNG_IN_LIST;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004874 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004875 } else if (cur->type == XML_RELAXNG_GROUP) {
4876 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4877 if (ctxt->error != NULL)
4878 ctxt->error(ctxt->userData,
4879 "Found forbidden pattern data/except//group\n");
4880 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004881 }
4882 if (flags & XML_RELAXNG_IN_START) {
4883 if (ctxt->error != NULL)
4884 ctxt->error(ctxt->userData,
4885 "Found forbidden pattern start//group\n");
4886 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004887 }
4888 if (flags & XML_RELAXNG_IN_ONEORMORE)
4889 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
4890 else
4891 nflags = flags;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004892 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004893 /*
4894 * The 7.3 Attribute derivation rule for groups is plugged there
4895 */
4896 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004897 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
4898 if (flags & XML_RELAXNG_IN_LIST) {
4899 if (ctxt->error != NULL)
4900 ctxt->error(ctxt->userData,
4901 "Found forbidden pattern list//interleave\n");
4902 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004903 }
4904 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4905 if (ctxt->error != NULL)
4906 ctxt->error(ctxt->userData,
4907 "Found forbidden pattern data/except//interleave\n");
4908 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004909 }
4910 if (flags & XML_RELAXNG_IN_START) {
4911 if (ctxt->error != NULL)
4912 ctxt->error(ctxt->userData,
4913 "Found forbidden pattern start//interleave\n");
4914 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004915 }
4916 if (flags & XML_RELAXNG_IN_ONEORMORE)
4917 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
4918 else
4919 nflags = flags;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004920 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004921 } else if (cur->type == XML_RELAXNG_EXCEPT) {
4922 if ((cur->parent != NULL) &&
4923 (cur->parent->type == XML_RELAXNG_DATATYPE))
4924 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
4925 else
4926 nflags = flags;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004927 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004928 } else if (cur->type == XML_RELAXNG_DATATYPE) {
4929 if (flags & XML_RELAXNG_IN_START) {
4930 if (ctxt->error != NULL)
4931 ctxt->error(ctxt->userData,
4932 "Found forbidden pattern start//data\n");
4933 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004934 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004935 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4936 ret = XML_RELAXNG_CONTENT_SIMPLE;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004937 } else if (cur->type == XML_RELAXNG_VALUE) {
4938 if (flags & XML_RELAXNG_IN_START) {
4939 if (ctxt->error != NULL)
4940 ctxt->error(ctxt->userData,
4941 "Found forbidden pattern start//value\n");
4942 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004943 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004944 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4945 ret = XML_RELAXNG_CONTENT_SIMPLE;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004946 } else if (cur->type == XML_RELAXNG_TEXT) {
4947 if (flags & XML_RELAXNG_IN_LIST) {
4948 if (ctxt->error != NULL)
4949 ctxt->error(ctxt->userData,
4950 "Found forbidden pattern list//text\n");
4951 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004952 }
4953 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4954 if (ctxt->error != NULL)
4955 ctxt->error(ctxt->userData,
4956 "Found forbidden pattern data/except//text\n");
4957 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004958 }
4959 if (flags & XML_RELAXNG_IN_START) {
4960 if (ctxt->error != NULL)
4961 ctxt->error(ctxt->userData,
4962 "Found forbidden pattern start//text\n");
4963 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004964 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004965 ret = XML_RELAXNG_CONTENT_COMPLEX;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004966 } else if (cur->type == XML_RELAXNG_EMPTY) {
4967 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4968 if (ctxt->error != NULL)
4969 ctxt->error(ctxt->userData,
4970 "Found forbidden pattern data/except//empty\n");
4971 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004972 }
4973 if (flags & XML_RELAXNG_IN_START) {
4974 if (ctxt->error != NULL)
4975 ctxt->error(ctxt->userData,
4976 "Found forbidden pattern start//empty\n");
4977 ctxt->nbErrors++;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004978 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004979 ret = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004980 } else {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004981 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004982 }
4983 cur = cur->next;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004984 if (ptype == XML_RELAXNG_GROUP) {
4985 val = xmlRelaxNGGroupContentType(val, ret);
4986 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
4987 tmp = xmlRelaxNGGroupContentType(val, ret);
4988 if (tmp != XML_RELAXNG_CONTENT_ERROR)
4989 tmp = xmlRelaxNGMaxContentType(val, ret);
4990 } else if (ptype == XML_RELAXNG_CHOICE) {
4991 val = xmlRelaxNGMaxContentType(val, ret);
4992 } else if (ptype == XML_RELAXNG_LIST) {
4993 val = XML_RELAXNG_CONTENT_SIMPLE;
4994 } else if (ptype == XML_RELAXNG_EXCEPT) {
4995 if (ret == XML_RELAXNG_CONTENT_ERROR)
4996 val = XML_RELAXNG_CONTENT_ERROR;
4997 else
4998 val = XML_RELAXNG_CONTENT_SIMPLE;
4999 } else {
5000 val = xmlRelaxNGGroupContentType(val, ret);
5001 }
5002
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005003 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005004 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005005}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005006
5007/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005008 * xmlRelaxNGParseGrammar:
5009 * @ctxt: a Relax-NG parser context
5010 * @nodes: grammar children nodes
5011 *
5012 * parse a Relax-NG <grammar> node
5013 *
5014 * Returns the internal xmlRelaxNGGrammarPtr built or
5015 * NULL in case of error
5016 */
5017static xmlRelaxNGGrammarPtr
5018xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5019 xmlRelaxNGGrammarPtr ret, tmp, old;
5020
Daniel Veillardc482e262003-02-26 14:48:48 +00005021#ifdef DEBUG_GRAMMAR
5022 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5023#endif
5024
Daniel Veillard6eadf632003-01-23 18:29:16 +00005025 ret = xmlRelaxNGNewGrammar(ctxt);
5026 if (ret == NULL)
5027 return(NULL);
5028
5029 /*
5030 * Link the new grammar in the tree
5031 */
5032 ret->parent = ctxt->grammar;
5033 if (ctxt->grammar != NULL) {
5034 tmp = ctxt->grammar->children;
5035 if (tmp == NULL) {
5036 ctxt->grammar->children = ret;
5037 } else {
5038 while (tmp->next != NULL)
5039 tmp = tmp->next;
5040 tmp->next = ret;
5041 }
5042 }
5043
5044 old = ctxt->grammar;
5045 ctxt->grammar = ret;
5046 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5047 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005048 if (ctxt->grammar == NULL) {
5049 if (ctxt->error != NULL)
5050 ctxt->error(ctxt->userData,
5051 "Failed to parse <grammar> content\n");
5052 ctxt->nbErrors++;
5053 } else if (ctxt->grammar->start == NULL) {
5054 if (ctxt->error != NULL)
5055 ctxt->error(ctxt->userData,
5056 "Element <grammar> has no <start>\n");
5057 ctxt->nbErrors++;
5058 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005059
5060 /*
5061 * Apply 4.17 mergingd rules to defines and starts
5062 */
5063 xmlRelaxNGCombineStart(ctxt, ret);
5064 if (ret->defs != NULL) {
5065 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5066 ctxt);
5067 }
5068
5069 /*
5070 * link together defines and refs in this grammar
5071 */
5072 if (ret->refs != NULL) {
5073 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5074 ctxt);
5075 }
5076 ctxt->grammar = old;
5077 return(ret);
5078}
5079
5080/**
5081 * xmlRelaxNGParseDocument:
5082 * @ctxt: a Relax-NG parser context
5083 * @node: the root node of the RelaxNG schema
5084 *
5085 * parse a Relax-NG definition resource and build an internal
5086 * xmlRelaxNG struture which can be used to validate instances.
5087 *
5088 * Returns the internal XML RelaxNG structure built or
5089 * NULL in case of error
5090 */
5091static xmlRelaxNGPtr
5092xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5093 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005094 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005095 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005096
5097 if ((ctxt == NULL) || (node == NULL))
5098 return (NULL);
5099
5100 schema = xmlRelaxNGNewRelaxNG(ctxt);
5101 if (schema == NULL)
5102 return(NULL);
5103
Daniel Veillard276be4a2003-01-24 01:03:34 +00005104 olddefine = ctxt->define;
5105 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005106 if (IS_RELAXNG(node, "grammar")) {
5107 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5108 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005109 xmlRelaxNGGrammarPtr tmp, ret;
5110
5111 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005112 if (schema->topgrammar == NULL) {
5113 return(schema);
5114 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005115 /*
5116 * Link the new grammar in the tree
5117 */
5118 ret->parent = ctxt->grammar;
5119 if (ctxt->grammar != NULL) {
5120 tmp = ctxt->grammar->children;
5121 if (tmp == NULL) {
5122 ctxt->grammar->children = ret;
5123 } else {
5124 while (tmp->next != NULL)
5125 tmp = tmp->next;
5126 tmp->next = ret;
5127 }
5128 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005129 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005130 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005131 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005132 if (old != NULL)
5133 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005134 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005135 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005136 if (schema->topgrammar->start != NULL) {
5137 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005138 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
5139 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5140 while ((schema->topgrammar->start != NULL) &&
5141 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5142 (schema->topgrammar->start->next != NULL))
5143 schema->topgrammar->start = schema->topgrammar->start->content;
5144 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005145 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005146 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005147 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005148
5149#ifdef DEBUG
5150 if (schema == NULL)
5151 xmlGenericError(xmlGenericErrorContext,
5152 "xmlRelaxNGParseDocument() failed\n");
5153#endif
5154
5155 return (schema);
5156}
5157
5158/************************************************************************
5159 * *
5160 * Reading RelaxNGs *
5161 * *
5162 ************************************************************************/
5163
5164/**
5165 * xmlRelaxNGNewParserCtxt:
5166 * @URL: the location of the schema
5167 *
5168 * Create an XML RelaxNGs parse context for that file/resource expected
5169 * to contain an XML RelaxNGs file.
5170 *
5171 * Returns the parser context or NULL in case of error
5172 */
5173xmlRelaxNGParserCtxtPtr
5174xmlRelaxNGNewParserCtxt(const char *URL) {
5175 xmlRelaxNGParserCtxtPtr ret;
5176
5177 if (URL == NULL)
5178 return(NULL);
5179
5180 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5181 if (ret == NULL) {
5182 xmlGenericError(xmlGenericErrorContext,
5183 "Failed to allocate new schama parser context for %s\n", URL);
5184 return (NULL);
5185 }
5186 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5187 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005188 ret->error = xmlGenericError;
5189 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005190 return (ret);
5191}
5192
5193/**
5194 * xmlRelaxNGNewMemParserCtxt:
5195 * @buffer: a pointer to a char array containing the schemas
5196 * @size: the size of the array
5197 *
5198 * Create an XML RelaxNGs parse context for that memory buffer expected
5199 * to contain an XML RelaxNGs file.
5200 *
5201 * Returns the parser context or NULL in case of error
5202 */
5203xmlRelaxNGParserCtxtPtr
5204xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5205 xmlRelaxNGParserCtxtPtr ret;
5206
5207 if ((buffer == NULL) || (size <= 0))
5208 return(NULL);
5209
5210 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5211 if (ret == NULL) {
5212 xmlGenericError(xmlGenericErrorContext,
5213 "Failed to allocate new schama parser context\n");
5214 return (NULL);
5215 }
5216 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5217 ret->buffer = buffer;
5218 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005219 ret->error = xmlGenericError;
5220 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005221 return (ret);
5222}
5223
5224/**
5225 * xmlRelaxNGFreeParserCtxt:
5226 * @ctxt: the schema parser context
5227 *
5228 * Free the resources associated to the schema parser context
5229 */
5230void
5231xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5232 if (ctxt == NULL)
5233 return;
5234 if (ctxt->URL != NULL)
5235 xmlFree(ctxt->URL);
5236 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005237 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005238 if (ctxt->interleaves != NULL)
5239 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005240 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005241 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005242 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005243 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005244 if (ctxt->docTab != NULL)
5245 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005246 if (ctxt->incTab != NULL)
5247 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005248 if (ctxt->defTab != NULL) {
5249 int i;
5250
5251 for (i = 0;i < ctxt->defNr;i++)
5252 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5253 xmlFree(ctxt->defTab);
5254 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005255 xmlFree(ctxt);
5256}
5257
Daniel Veillard6eadf632003-01-23 18:29:16 +00005258/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005259 * xmlRelaxNGNormExtSpace:
5260 * @value: a value
5261 *
5262 * Removes the leading and ending spaces of the value
5263 * The string is modified "in situ"
5264 */
5265static void
5266xmlRelaxNGNormExtSpace(xmlChar *value) {
5267 xmlChar *start = value;
5268 xmlChar *cur = value;
5269 if (value == NULL)
5270 return;
5271
5272 while (IS_BLANK(*cur)) cur++;
5273 if (cur == start) {
5274 do {
5275 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5276 if (*cur == 0)
5277 return;
5278 start = cur;
5279 while (IS_BLANK(*cur)) cur++;
5280 if (*cur == 0) {
5281 *start = 0;
5282 return;
5283 }
5284 } while (1);
5285 } else {
5286 do {
5287 while ((*cur != 0) && (!IS_BLANK(*cur)))
5288 *start++ = *cur++;
5289 if (*cur == 0) {
5290 *start = 0;
5291 return;
5292 }
5293 /* don't try to normalize the inner spaces */
5294 while (IS_BLANK(*cur)) cur++;
5295 *start++ = *cur++;
5296 if (*cur == 0) {
5297 *start = 0;
5298 return;
5299 }
5300 } while (1);
5301 }
5302}
5303
5304/**
5305 * xmlRelaxNGCheckAttributes:
5306 * @ctxt: a Relax-NG parser context
5307 * @node: a Relax-NG node
5308 *
5309 * Check all the attributes on the given node
5310 */
5311static void
5312xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5313 xmlAttrPtr cur, next;
5314
5315 cur = node->properties;
5316 while (cur != NULL) {
5317 next = cur->next;
5318 if ((cur->ns == NULL) ||
5319 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5320 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5321 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5322 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5323 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5324 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005325 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005326 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5327 if (ctxt->error != NULL)
5328 ctxt->error(ctxt->userData,
5329 "Attribute %s is not allowed on %s\n",
5330 cur->name, node->name);
5331 ctxt->nbErrors++;
5332 }
5333 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5334 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5335 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5336 if (ctxt->error != NULL)
5337 ctxt->error(ctxt->userData,
5338 "Attribute %s is not allowed on %s\n",
5339 cur->name, node->name);
5340 ctxt->nbErrors++;
5341 }
5342 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
5343 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
5344 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
5345 if (ctxt->error != NULL)
5346 ctxt->error(ctxt->userData,
5347 "Attribute %s is not allowed on %s\n",
5348 cur->name, node->name);
5349 ctxt->nbErrors++;
5350 }
5351 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
5352 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
5353 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5354 if (ctxt->error != NULL)
5355 ctxt->error(ctxt->userData,
5356 "Attribute %s is not allowed on %s\n",
5357 cur->name, node->name);
5358 ctxt->nbErrors++;
5359 }
5360 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
5361 xmlChar *val;
5362 xmlURIPtr uri;
5363
5364 val = xmlNodeListGetString(node->doc, cur->children, 1);
5365 if (val != NULL) {
5366 if (val[0] != 0) {
5367 uri = xmlParseURI((const char *) val);
5368 if (uri == NULL) {
5369 if (ctxt->error != NULL)
5370 ctxt->error(ctxt->userData,
5371 "Attribute %s contains invalid URI %s\n",
5372 cur->name, val);
5373 ctxt->nbErrors++;
5374 } else {
5375 if (uri->scheme == NULL) {
5376 if (ctxt->error != NULL)
5377 ctxt->error(ctxt->userData,
5378 "Attribute %s URI %s is not absolute\n",
5379 cur->name, val);
5380 ctxt->nbErrors++;
5381 }
5382 if (uri->fragment != NULL) {
5383 if (ctxt->error != NULL)
5384 ctxt->error(ctxt->userData,
5385 "Attribute %s URI %s has a fragment ID\n",
5386 cur->name, val);
5387 ctxt->nbErrors++;
5388 }
5389 xmlFreeURI(uri);
5390 }
5391 }
5392 xmlFree(val);
5393 }
5394 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
5395 if (ctxt->error != NULL)
5396 ctxt->error(ctxt->userData,
5397 "Unknown attribute %s on %s\n",
5398 cur->name, node->name);
5399 ctxt->nbErrors++;
5400 }
5401 }
5402 cur = next;
5403 }
5404}
5405
5406/**
Daniel Veillardc5312d72003-02-21 17:14:10 +00005407 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005408 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00005409 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00005410 *
Daniel Veillardc5312d72003-02-21 17:14:10 +00005411 * Cleanup the subtree from unwanted nodes for parsing, resolve
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005412 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00005413 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005414static void
5415xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
5416 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005417
Daniel Veillard6eadf632003-01-23 18:29:16 +00005418 delete = NULL;
5419 cur = root;
5420 while (cur != NULL) {
5421 if (delete != NULL) {
5422 xmlUnlinkNode(delete);
5423 xmlFreeNode(delete);
5424 delete = NULL;
5425 }
5426 if (cur->type == XML_ELEMENT_NODE) {
5427 /*
5428 * Simplification 4.1. Annotations
5429 */
5430 if ((cur->ns == NULL) ||
5431 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00005432 if ((cur->parent != NULL) &&
5433 (cur->parent->type == XML_ELEMENT_NODE) &&
5434 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
5435 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
5436 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
5437 if (ctxt->error != NULL)
5438 ctxt->error(ctxt->userData,
5439 "element %s doesn't allow foreign elements\n",
5440 cur->parent->name);
5441 ctxt->nbErrors++;
5442 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005443 delete = cur;
5444 goto skip_children;
5445 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005446 xmlRelaxNGCleanupAttributes(ctxt, cur);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005447 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005448 xmlChar *href, *ns, *base, *URL;
5449 xmlRelaxNGDocumentPtr docu;
Daniel Veillard416589a2003-02-17 17:25:42 +00005450 xmlNodePtr tmp;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005451
5452 ns = xmlGetProp(cur, BAD_CAST "ns");
Daniel Veillard416589a2003-02-17 17:25:42 +00005453 if (ns == NULL) {
5454 tmp = cur->parent;
5455 while ((tmp != NULL) &&
5456 (tmp->type == XML_ELEMENT_NODE)) {
5457 ns = xmlGetProp(tmp, BAD_CAST "ns");
5458 if (ns != NULL)
5459 break;
5460 tmp = tmp->parent;
5461 }
5462 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005463 href = xmlGetProp(cur, BAD_CAST "href");
5464 if (href == NULL) {
5465 if (ctxt->error != NULL)
5466 ctxt->error(ctxt->userData,
5467 "xmlRelaxNGParse: externalRef has no href attribute\n");
5468 ctxt->nbErrors++;
5469 delete = cur;
5470 goto skip_children;
5471 }
5472 base = xmlNodeGetBase(cur->doc, cur);
5473 URL = xmlBuildURI(href, base);
5474 if (URL == NULL) {
5475 if (ctxt->error != NULL)
5476 ctxt->error(ctxt->userData,
5477 "Failed to compute URL for externalRef %s\n", href);
5478 ctxt->nbErrors++;
5479 if (href != NULL)
5480 xmlFree(href);
5481 if (base != NULL)
5482 xmlFree(base);
5483 delete = cur;
5484 goto skip_children;
5485 }
5486 if (href != NULL)
5487 xmlFree(href);
5488 if (base != NULL)
5489 xmlFree(base);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005490 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005491 if (docu == NULL) {
5492 if (ctxt->error != NULL)
5493 ctxt->error(ctxt->userData,
5494 "Failed to load externalRef %s\n", URL);
5495 ctxt->nbErrors++;
5496 xmlFree(URL);
5497 delete = cur;
5498 goto skip_children;
5499 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005500 if (ns != NULL)
5501 xmlFree(ns);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005502 xmlFree(URL);
5503 cur->_private = docu;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005504 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
Daniel Veillard416589a2003-02-17 17:25:42 +00005505 xmlChar *href, *ns, *base, *URL;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005506 xmlRelaxNGIncludePtr incl;
Daniel Veillard416589a2003-02-17 17:25:42 +00005507 xmlNodePtr tmp;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005508
5509 href = xmlGetProp(cur, BAD_CAST "href");
5510 if (href == NULL) {
5511 if (ctxt->error != NULL)
5512 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005513 "xmlRelaxNGParse: include has no href attribute\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005514 ctxt->nbErrors++;
5515 delete = cur;
5516 goto skip_children;
5517 }
5518 base = xmlNodeGetBase(cur->doc, cur);
5519 URL = xmlBuildURI(href, base);
5520 if (URL == NULL) {
5521 if (ctxt->error != NULL)
5522 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005523 "Failed to compute URL for include %s\n", href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005524 ctxt->nbErrors++;
5525 if (href != NULL)
5526 xmlFree(href);
5527 if (base != NULL)
5528 xmlFree(base);
5529 delete = cur;
5530 goto skip_children;
5531 }
5532 if (href != NULL)
5533 xmlFree(href);
5534 if (base != NULL)
5535 xmlFree(base);
Daniel Veillard416589a2003-02-17 17:25:42 +00005536 ns = xmlGetProp(cur, BAD_CAST "ns");
5537 if (ns == NULL) {
5538 tmp = cur->parent;
5539 while ((tmp != NULL) &&
5540 (tmp->type == XML_ELEMENT_NODE)) {
5541 ns = xmlGetProp(tmp, BAD_CAST "ns");
5542 if (ns != NULL)
5543 break;
5544 tmp = tmp->parent;
5545 }
5546 }
5547 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5548 if (ns != NULL)
5549 xmlFree(ns);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005550 if (incl == NULL) {
5551 if (ctxt->error != NULL)
5552 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005553 "Failed to load include %s\n", URL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005554 ctxt->nbErrors++;
5555 xmlFree(URL);
5556 delete = cur;
5557 goto skip_children;
5558 }
5559 xmlFree(URL);
5560 cur->_private = incl;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005561 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5562 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00005563 xmlChar *name, *ns;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005564 xmlNodePtr text = NULL;
5565
5566 /*
5567 * Simplification 4.8. name attribute of element
5568 * and attribute elements
5569 */
5570 name = xmlGetProp(cur, BAD_CAST "name");
5571 if (name != NULL) {
5572 if (cur->children == NULL) {
5573 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5574 name);
5575 } else {
5576 xmlNodePtr node;
5577 node = xmlNewNode(cur->ns, BAD_CAST "name");
5578 if (node != NULL) {
5579 xmlAddPrevSibling(cur->children, node);
5580 text = xmlNewText(name);
5581 xmlAddChild(node, text);
5582 text = node;
5583 }
5584 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00005585 if (text == NULL) {
5586 if (ctxt->error != NULL)
5587 ctxt->error(ctxt->userData,
5588 "Failed to create a name %s element\n", name);
5589 ctxt->nbErrors++;
5590 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005591 xmlUnsetProp(cur, BAD_CAST "name");
5592 xmlFree(name);
Daniel Veillardfebcca42003-02-16 15:44:18 +00005593 ns = xmlGetProp(cur, BAD_CAST "ns");
5594 if (ns != NULL) {
5595 if (text != NULL) {
5596 xmlSetProp(text, BAD_CAST "ns", ns);
5597 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
Daniel Veillard6eadf632003-01-23 18:29:16 +00005598 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00005599 xmlFree(ns);
5600 } else if (xmlStrEqual(cur->name,
5601 BAD_CAST "attribute")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005602 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
5603 }
5604 }
5605 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
5606 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
5607 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
5608 /*
5609 * Simplification 4.8. name attribute of element
5610 * and attribute elements
5611 */
5612 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
5613 xmlNodePtr node;
5614 xmlChar *ns = NULL;
5615
5616 node = cur->parent;
5617 while ((node != NULL) &&
5618 (node->type == XML_ELEMENT_NODE)) {
5619 ns = xmlGetProp(node, BAD_CAST "ns");
5620 if (ns != NULL) {
5621 break;
5622 }
5623 node = node->parent;
5624 }
5625 if (ns == NULL) {
5626 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
5627 } else {
5628 xmlSetProp(cur, BAD_CAST "ns", ns);
5629 xmlFree(ns);
5630 }
5631 }
5632 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5633 xmlChar *name, *local, *prefix;
5634
5635 /*
5636 * Simplification: 4.10. QNames
5637 */
5638 name = xmlNodeGetContent(cur);
5639 if (name != NULL) {
5640 local = xmlSplitQName2(name, &prefix);
5641 if (local != NULL) {
5642 xmlNsPtr ns;
5643
5644 ns = xmlSearchNs(cur->doc, cur, prefix);
5645 if (ns == NULL) {
5646 if (ctxt->error != NULL)
5647 ctxt->error(ctxt->userData,
5648 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
5649 ctxt->nbErrors++;
5650 } else {
5651 xmlSetProp(cur, BAD_CAST "ns", ns->href);
5652 xmlNodeSetContent(cur, local);
5653 }
5654 xmlFree(local);
5655 xmlFree(prefix);
5656 }
5657 xmlFree(name);
5658 }
5659 }
Daniel Veillard44e1dd02003-02-21 23:23:28 +00005660 /*
5661 * 4.16
5662 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005663 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
5664 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5665 if (ctxt->error != NULL)
5666 ctxt->error(ctxt->userData,
5667 "Found nsName/except//nsName forbidden construct\n");
5668 ctxt->nbErrors++;
5669 }
5670 }
5671 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
5672 (cur != root)) {
5673 int oldflags = ctxt->flags;
5674
Daniel Veillard44e1dd02003-02-21 23:23:28 +00005675 /*
5676 * 4.16
5677 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005678 if ((cur->parent != NULL) &&
5679 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
5680 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
5681 xmlRelaxNGCleanupTree(ctxt, cur);
5682 ctxt->flags = oldflags;
5683 goto skip_children;
5684 } else if ((cur->parent != NULL) &&
5685 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
5686 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
5687 xmlRelaxNGCleanupTree(ctxt, cur);
5688 ctxt->flags = oldflags;
5689 goto skip_children;
5690 }
5691 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00005692 /*
5693 * 4.16
5694 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005695 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
5696 if (ctxt->error != NULL)
5697 ctxt->error(ctxt->userData,
5698 "Found anyName/except//anyName forbidden construct\n");
5699 ctxt->nbErrors++;
5700 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5701 if (ctxt->error != NULL)
5702 ctxt->error(ctxt->userData,
5703 "Found nsName/except//anyName forbidden construct\n");
5704 ctxt->nbErrors++;
5705 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005706 }
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005707 /*
5708 * Thisd is not an else since "include" is transformed
5709 * into a div
5710 */
5711 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
Daniel Veillard416589a2003-02-17 17:25:42 +00005712 xmlChar *ns;
5713 xmlNodePtr child, ins, tmp;
5714
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005715 /*
5716 * implements rule 4.11
5717 */
Daniel Veillard416589a2003-02-17 17:25:42 +00005718
5719 ns = xmlGetProp(cur, BAD_CAST "ns");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005720
5721 child = cur->children;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005722 ins = cur;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005723 while (child != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00005724 if (ns != NULL) {
5725 if (!xmlHasProp(child, BAD_CAST "ns")) {
5726 xmlSetProp(child, BAD_CAST "ns", ns);
5727 }
5728 }
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005729 tmp = child->next;
5730 xmlUnlinkNode(child);
5731 ins = xmlAddNextSibling(ins, child);
5732 child = tmp;
5733 }
Daniel Veillard416589a2003-02-17 17:25:42 +00005734 if (ns != NULL)
5735 xmlFree(ns);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005736 delete = cur;
5737 goto skip_children;
5738 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005739 }
5740 }
5741 /*
5742 * Simplification 4.2 whitespaces
5743 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00005744 else if ((cur->type == XML_TEXT_NODE) ||
5745 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005746 if (IS_BLANK_NODE(cur)) {
5747 if (cur->parent->type == XML_ELEMENT_NODE) {
5748 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
5749 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
5750 delete = cur;
5751 } else {
5752 delete = cur;
5753 goto skip_children;
5754 }
5755 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00005756 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005757 delete = cur;
5758 goto skip_children;
5759 }
5760
5761 /*
5762 * Skip to next node
5763 */
5764 if (cur->children != NULL) {
5765 if ((cur->children->type != XML_ENTITY_DECL) &&
5766 (cur->children->type != XML_ENTITY_REF_NODE) &&
5767 (cur->children->type != XML_ENTITY_NODE)) {
5768 cur = cur->children;
5769 continue;
5770 }
5771 }
5772skip_children:
5773 if (cur->next != NULL) {
5774 cur = cur->next;
5775 continue;
5776 }
5777
5778 do {
5779 cur = cur->parent;
5780 if (cur == NULL)
5781 break;
5782 if (cur == root) {
5783 cur = NULL;
5784 break;
5785 }
5786 if (cur->next != NULL) {
5787 cur = cur->next;
5788 break;
5789 }
5790 } while (cur != NULL);
5791 }
5792 if (delete != NULL) {
5793 xmlUnlinkNode(delete);
5794 xmlFreeNode(delete);
5795 delete = NULL;
5796 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00005797}
Daniel Veillard6eadf632003-01-23 18:29:16 +00005798
Daniel Veillardc5312d72003-02-21 17:14:10 +00005799/**
5800 * xmlRelaxNGCleanupDoc:
5801 * @ctxt: a Relax-NG parser context
5802 * @doc: an xmldocPtr document pointer
5803 *
5804 * Cleanup the document from unwanted nodes for parsing, resolve
5805 * Include and externalRef lookups.
5806 *
5807 * Returns the cleaned up document or NULL in case of error
5808 */
5809static xmlDocPtr
5810xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
5811 xmlNodePtr root;
5812
5813 /*
5814 * Extract the root
5815 */
5816 root = xmlDocGetRootElement(doc);
5817 if (root == NULL) {
5818 if (ctxt->error != NULL)
5819 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5820 ctxt->URL);
5821 ctxt->nbErrors++;
5822 return (NULL);
5823 }
5824 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005825 return(doc);
5826}
5827
5828/**
5829 * xmlRelaxNGParse:
5830 * @ctxt: a Relax-NG parser context
5831 *
5832 * parse a schema definition resource and build an internal
5833 * XML Shema struture which can be used to validate instances.
5834 * *WARNING* this interface is highly subject to change
5835 *
5836 * Returns the internal XML RelaxNG structure built from the resource or
5837 * NULL in case of error
5838 */
5839xmlRelaxNGPtr
5840xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
5841{
5842 xmlRelaxNGPtr ret = NULL;
5843 xmlDocPtr doc;
5844 xmlNodePtr root;
5845
5846 xmlRelaxNGInitTypes();
5847
5848 if (ctxt == NULL)
5849 return (NULL);
5850
5851 /*
5852 * First step is to parse the input document into an DOM/Infoset
5853 */
5854 if (ctxt->URL != NULL) {
5855 doc = xmlParseFile((const char *) ctxt->URL);
5856 if (doc == NULL) {
5857 if (ctxt->error != NULL)
5858 ctxt->error(ctxt->userData,
5859 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
5860 ctxt->nbErrors++;
5861 return (NULL);
5862 }
5863 } else if (ctxt->buffer != NULL) {
5864 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
5865 if (doc == NULL) {
5866 if (ctxt->error != NULL)
5867 ctxt->error(ctxt->userData,
5868 "xmlRelaxNGParse: could not parse schemas\n");
5869 ctxt->nbErrors++;
5870 return (NULL);
5871 }
5872 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5873 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5874 } else {
5875 if (ctxt->error != NULL)
5876 ctxt->error(ctxt->userData,
5877 "xmlRelaxNGParse: nothing to parse\n");
5878 ctxt->nbErrors++;
5879 return (NULL);
5880 }
5881 ctxt->document = doc;
5882
5883 /*
5884 * Some preprocessing of the document content
5885 */
5886 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
5887 if (doc == NULL) {
5888 xmlFreeDoc(ctxt->document);
5889 ctxt->document = NULL;
5890 return(NULL);
5891 }
5892
Daniel Veillard6eadf632003-01-23 18:29:16 +00005893 /*
5894 * Then do the parsing for good
5895 */
5896 root = xmlDocGetRootElement(doc);
5897 if (root == NULL) {
5898 if (ctxt->error != NULL)
5899 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5900 ctxt->URL);
5901 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005902 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005903 return (NULL);
5904 }
5905 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005906 if (ret == NULL) {
5907 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005908 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005909 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005910
5911 /*
5912 * Check the ref/defines links
5913 */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005914 /*
5915 * try to preprocess interleaves
5916 */
5917 if (ctxt->interleaves != NULL) {
5918 xmlHashScan(ctxt->interleaves,
5919 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
5920 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005921
5922 /*
5923 * if there was a parsing error return NULL
5924 */
5925 if (ctxt->nbErrors > 0) {
5926 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005927 ctxt->document = NULL;
5928 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005929 return(NULL);
5930 }
5931
5932 /*
5933 * Transfer the pointer for cleanup at the schema level.
5934 */
5935 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005936 ctxt->document = NULL;
5937 ret->documents = ctxt->documents;
5938 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005939
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005940 ret->includes = ctxt->includes;
5941 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00005942 ret->defNr = ctxt->defNr;
5943 ret->defTab = ctxt->defTab;
5944 ctxt->defTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005945
5946 return (ret);
5947}
5948
5949/**
5950 * xmlRelaxNGSetParserErrors:
5951 * @ctxt: a Relax-NG validation context
5952 * @err: the error callback
5953 * @warn: the warning callback
5954 * @ctx: contextual data for the callbacks
5955 *
5956 * Set the callback functions used to handle errors for a validation context
5957 */
5958void
5959xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
5960 xmlRelaxNGValidityErrorFunc err,
5961 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
5962 if (ctxt == NULL)
5963 return;
5964 ctxt->error = err;
5965 ctxt->warning = warn;
5966 ctxt->userData = ctx;
5967}
5968/************************************************************************
5969 * *
5970 * Dump back a compiled form *
5971 * *
5972 ************************************************************************/
5973static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
5974
5975/**
5976 * xmlRelaxNGDumpDefines:
5977 * @output: the file output
5978 * @defines: a list of define structures
5979 *
5980 * Dump a RelaxNG structure back
5981 */
5982static void
5983xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
5984 while (defines != NULL) {
5985 xmlRelaxNGDumpDefine(output, defines);
5986 defines = defines->next;
5987 }
5988}
5989
5990/**
5991 * xmlRelaxNGDumpDefine:
5992 * @output: the file output
5993 * @define: a define structure
5994 *
5995 * Dump a RelaxNG structure back
5996 */
5997static void
5998xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
5999 if (define == NULL)
6000 return;
6001 switch(define->type) {
6002 case XML_RELAXNG_EMPTY:
6003 fprintf(output, "<empty/>\n");
6004 break;
6005 case XML_RELAXNG_NOT_ALLOWED:
6006 fprintf(output, "<notAllowed/>\n");
6007 break;
6008 case XML_RELAXNG_TEXT:
6009 fprintf(output, "<text/>\n");
6010 break;
6011 case XML_RELAXNG_ELEMENT:
6012 fprintf(output, "<element>\n");
6013 if (define->name != NULL) {
6014 fprintf(output, "<name");
6015 if (define->ns != NULL)
6016 fprintf(output, " ns=\"%s\"", define->ns);
6017 fprintf(output, ">%s</name>\n", define->name);
6018 }
6019 xmlRelaxNGDumpDefines(output, define->attrs);
6020 xmlRelaxNGDumpDefines(output, define->content);
6021 fprintf(output, "</element>\n");
6022 break;
6023 case XML_RELAXNG_LIST:
6024 fprintf(output, "<list>\n");
6025 xmlRelaxNGDumpDefines(output, define->content);
6026 fprintf(output, "</list>\n");
6027 break;
6028 case XML_RELAXNG_ONEORMORE:
6029 fprintf(output, "<oneOrMore>\n");
6030 xmlRelaxNGDumpDefines(output, define->content);
6031 fprintf(output, "</oneOrMore>\n");
6032 break;
6033 case XML_RELAXNG_ZEROORMORE:
6034 fprintf(output, "<zeroOrMore>\n");
6035 xmlRelaxNGDumpDefines(output, define->content);
6036 fprintf(output, "</zeroOrMore>\n");
6037 break;
6038 case XML_RELAXNG_CHOICE:
6039 fprintf(output, "<choice>\n");
6040 xmlRelaxNGDumpDefines(output, define->content);
6041 fprintf(output, "</choice>\n");
6042 break;
6043 case XML_RELAXNG_GROUP:
6044 fprintf(output, "<group>\n");
6045 xmlRelaxNGDumpDefines(output, define->content);
6046 fprintf(output, "</group>\n");
6047 break;
6048 case XML_RELAXNG_INTERLEAVE:
6049 fprintf(output, "<interleave>\n");
6050 xmlRelaxNGDumpDefines(output, define->content);
6051 fprintf(output, "</interleave>\n");
6052 break;
6053 case XML_RELAXNG_OPTIONAL:
6054 fprintf(output, "<optional>\n");
6055 xmlRelaxNGDumpDefines(output, define->content);
6056 fprintf(output, "</optional>\n");
6057 break;
6058 case XML_RELAXNG_ATTRIBUTE:
6059 fprintf(output, "<attribute>\n");
6060 xmlRelaxNGDumpDefines(output, define->content);
6061 fprintf(output, "</attribute>\n");
6062 break;
6063 case XML_RELAXNG_DEF:
6064 fprintf(output, "<define");
6065 if (define->name != NULL)
6066 fprintf(output, " name=\"%s\"", define->name);
6067 fprintf(output, ">\n");
6068 xmlRelaxNGDumpDefines(output, define->content);
6069 fprintf(output, "</define>\n");
6070 break;
6071 case XML_RELAXNG_REF:
6072 fprintf(output, "<ref");
6073 if (define->name != NULL)
6074 fprintf(output, " name=\"%s\"", define->name);
6075 fprintf(output, ">\n");
6076 xmlRelaxNGDumpDefines(output, define->content);
6077 fprintf(output, "</ref>\n");
6078 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006079 case XML_RELAXNG_PARENTREF:
6080 fprintf(output, "<parentRef");
6081 if (define->name != NULL)
6082 fprintf(output, " name=\"%s\"", define->name);
6083 fprintf(output, ">\n");
6084 xmlRelaxNGDumpDefines(output, define->content);
6085 fprintf(output, "</parentRef>\n");
6086 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006087 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006088 fprintf(output, "<externalRef>");
Daniel Veillarde431a272003-01-29 23:02:33 +00006089 xmlRelaxNGDumpDefines(output, define->content);
6090 fprintf(output, "</externalRef>\n");
6091 break;
6092 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006093 case XML_RELAXNG_VALUE:
6094 TODO
6095 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006096 case XML_RELAXNG_START:
Daniel Veillard144fae12003-02-03 13:17:57 +00006097 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006098 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006099 TODO
6100 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006101 case XML_RELAXNG_NOOP:
6102 xmlRelaxNGDumpDefines(output, define->content);
6103 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006104 }
6105}
6106
6107/**
6108 * xmlRelaxNGDumpGrammar:
6109 * @output: the file output
6110 * @grammar: a grammar structure
6111 * @top: is this a top grammar
6112 *
6113 * Dump a RelaxNG structure back
6114 */
6115static void
6116xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6117{
6118 if (grammar == NULL)
6119 return;
6120
6121 fprintf(output, "<grammar");
6122 if (top)
6123 fprintf(output,
6124 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6125 switch(grammar->combine) {
6126 case XML_RELAXNG_COMBINE_UNDEFINED:
6127 break;
6128 case XML_RELAXNG_COMBINE_CHOICE:
6129 fprintf(output, " combine=\"choice\"");
6130 break;
6131 case XML_RELAXNG_COMBINE_INTERLEAVE:
6132 fprintf(output, " combine=\"interleave\"");
6133 break;
6134 default:
6135 fprintf(output, " <!-- invalid combine value -->");
6136 }
6137 fprintf(output, ">\n");
6138 if (grammar->start == NULL) {
6139 fprintf(output, " <!-- grammar had no start -->");
6140 } else {
6141 fprintf(output, "<start>\n");
6142 xmlRelaxNGDumpDefine(output, grammar->start);
6143 fprintf(output, "</start>\n");
6144 }
6145 /* TODO ? Dump the defines ? */
6146 fprintf(output, "</grammar>\n");
6147}
6148
6149/**
6150 * xmlRelaxNGDump:
6151 * @output: the file output
6152 * @schema: a schema structure
6153 *
6154 * Dump a RelaxNG structure back
6155 */
6156void
6157xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6158{
6159 if (schema == NULL) {
6160 fprintf(output, "RelaxNG empty or failed to compile\n");
6161 return;
6162 }
6163 fprintf(output, "RelaxNG: ");
6164 if (schema->doc == NULL) {
6165 fprintf(output, "no document\n");
6166 } else if (schema->doc->URL != NULL) {
6167 fprintf(output, "%s\n", schema->doc->URL);
6168 } else {
6169 fprintf(output, "\n");
6170 }
6171 if (schema->topgrammar == NULL) {
6172 fprintf(output, "RelaxNG has no top grammar\n");
6173 return;
6174 }
6175 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6176}
6177
Daniel Veillardfebcca42003-02-16 15:44:18 +00006178/**
6179 * xmlRelaxNGDumpTree:
6180 * @output: the file output
6181 * @schema: a schema structure
6182 *
6183 * Dump the transformed RelaxNG tree.
6184 */
6185void
6186xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6187{
6188 if (schema == NULL) {
6189 fprintf(output, "RelaxNG empty or failed to compile\n");
6190 return;
6191 }
6192 if (schema->doc == NULL) {
6193 fprintf(output, "no document\n");
6194 } else {
6195 xmlDocDump(output, schema->doc);
6196 }
6197}
6198
Daniel Veillard6eadf632003-01-23 18:29:16 +00006199/************************************************************************
6200 * *
6201 * Validation implementation *
6202 * *
6203 ************************************************************************/
6204static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6205 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006206static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6207 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006208
6209/**
6210 * xmlRelaxNGSkipIgnored:
6211 * @ctxt: a schema validation context
6212 * @node: the top node.
6213 *
6214 * Skip ignorable nodes in that context
6215 *
6216 * Returns the new sibling or NULL in case of error.
6217 */
6218static xmlNodePtr
6219xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6220 xmlNodePtr node) {
6221 /*
6222 * TODO complete and handle entities
6223 */
6224 while ((node != NULL) &&
6225 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006226 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006227 (((node->type == XML_TEXT_NODE) ||
6228 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard6eadf632003-01-23 18:29:16 +00006229 (IS_BLANK_NODE(node))))) {
6230 node = node->next;
6231 }
6232 return(node);
6233}
6234
6235/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006236 * xmlRelaxNGNormalize:
6237 * @ctxt: a schema validation context
6238 * @str: the string to normalize
6239 *
6240 * Implements the normalizeWhiteSpace( s ) function from
6241 * section 6.2.9 of the spec
6242 *
6243 * Returns the new string or NULL in case of error.
6244 */
6245static xmlChar *
6246xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6247 xmlChar *ret, *p;
6248 const xmlChar *tmp;
6249 int len;
6250
6251 if (str == NULL)
6252 return(NULL);
6253 tmp = str;
6254 while (*tmp != 0) tmp++;
6255 len = tmp - str;
6256
6257 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6258 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006259 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006260 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006261 } else {
6262 xmlGenericError(xmlGenericErrorContext,
6263 "xmlRelaxNGNormalize: out of memory\n");
6264 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006265 return(NULL);
6266 }
6267 p = ret;
6268 while (IS_BLANK(*str)) str++;
6269 while (*str != 0) {
6270 if (IS_BLANK(*str)) {
6271 while (IS_BLANK(*str)) str++;
6272 if (*str == 0)
6273 break;
6274 *p++ = ' ';
6275 } else
6276 *p++ = *str++;
6277 }
6278 *p = 0;
6279 return(ret);
6280}
6281
6282/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006283 * xmlRelaxNGValidateDatatype:
6284 * @ctxt: a Relax-NG validation context
6285 * @value: the string value
6286 * @type: the datatype definition
6287 *
6288 * Validate the given value against the dataype
6289 *
6290 * Returns 0 if the validation succeeded or an error code.
6291 */
6292static int
6293xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
6294 xmlRelaxNGDefinePtr define) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006295 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006296 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006297 void *result = NULL;
6298 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006299
6300 if ((define == NULL) || (define->data == NULL)) {
6301 return(-1);
6302 }
6303 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006304 if (lib->check != NULL) {
6305 if ((define->attrs != NULL) &&
6306 (define->attrs->type == XML_RELAXNG_PARAM)) {
6307 ret = lib->check(lib->data, define->name, value, &result);
6308 } else {
6309 ret = lib->check(lib->data, define->name, value, NULL);
6310 }
6311 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006312 ret = -1;
6313 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006314 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006315 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6316 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006317 return(-1);
6318 } else if (ret == 1) {
6319 ret = 0;
6320 } else {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006321 VALID_ERR3(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006322 ret = -1;
6323 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006324 cur = define->attrs;
6325 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6326 if (lib->facet != NULL) {
6327 tmp = lib->facet(lib->data, define->name, cur->name,
6328 cur->value, value, result);
6329 if (tmp != 0)
6330 ret = -1;
6331 }
6332 cur = cur->next;
6333 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006334 if ((ret == 0) && (define->content != NULL)) {
6335 const xmlChar *oldvalue, *oldendvalue;
6336
6337 oldvalue = ctxt->state->value;
6338 oldendvalue = ctxt->state->endvalue;
6339 ctxt->state->value = (xmlChar *) value;
6340 ctxt->state->endvalue = NULL;
6341 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6342 ctxt->state->value = (xmlChar *) oldvalue;
6343 ctxt->state->endvalue = (xmlChar *) oldendvalue;
6344 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006345 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6346 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006347 return(ret);
6348}
6349
6350/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006351 * xmlRelaxNGNextValue:
6352 * @ctxt: a Relax-NG validation context
6353 *
6354 * Skip to the next value when validating within a list
6355 *
6356 * Returns 0 if the operation succeeded or an error code.
6357 */
6358static int
6359xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
6360 xmlChar *cur;
6361
6362 cur = ctxt->state->value;
6363 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
6364 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00006365 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006366 return(0);
6367 }
6368 while (*cur != 0) cur++;
6369 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
6370 if (cur == ctxt->state->endvalue)
6371 ctxt->state->value = NULL;
6372 else
6373 ctxt->state->value = cur;
6374 return(0);
6375}
6376
6377/**
6378 * xmlRelaxNGValidateValueList:
6379 * @ctxt: a Relax-NG validation context
6380 * @defines: the list of definitions to verify
6381 *
6382 * Validate the given set of definitions for the current value
6383 *
6384 * Returns 0 if the validation succeeded or an error code.
6385 */
6386static int
6387xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
6388 xmlRelaxNGDefinePtr defines) {
6389 int ret = 0;
6390
6391 while (defines != NULL) {
6392 ret = xmlRelaxNGValidateValue(ctxt, defines);
6393 if (ret != 0)
6394 break;
6395 defines = defines->next;
6396 }
6397 return(ret);
6398}
6399
6400/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006401 * xmlRelaxNGValidateValue:
6402 * @ctxt: a Relax-NG validation context
6403 * @define: the definition to verify
6404 *
6405 * Validate the given definition for the current value
6406 *
6407 * Returns 0 if the validation succeeded or an error code.
6408 */
6409static int
6410xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6411 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00006412 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006413 xmlChar *value;
6414
6415 value = ctxt->state->value;
6416 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006417 case XML_RELAXNG_EMPTY: {
6418 if ((value != NULL) && (value[0] != 0)) {
6419 int idx = 0;
6420
6421 while (IS_BLANK(value[idx]))
6422 idx++;
6423 if (value[idx] != 0)
6424 ret = -1;
6425 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006426 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00006427 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006428 case XML_RELAXNG_TEXT:
6429 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00006430 case XML_RELAXNG_VALUE: {
6431 if (!xmlStrEqual(value, define->value)) {
6432 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006433 xmlRelaxNGTypeLibraryPtr lib;
6434
6435 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
6436 if ((lib != NULL) && (lib->comp != NULL))
6437 ret = lib->comp(lib->data, define->name, value,
6438 define->value);
6439 else
6440 ret = -1;
6441 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006442 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006443 return(-1);
6444 } else if (ret == 1) {
6445 ret = 0;
6446 } else {
6447 ret = -1;
6448 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006449 } else {
6450 xmlChar *nval, *nvalue;
6451
6452 /*
6453 * TODO: trivial optimizations are possible by
6454 * computing at compile-time
6455 */
6456 nval = xmlRelaxNGNormalize(ctxt, define->value);
6457 nvalue = xmlRelaxNGNormalize(ctxt, value);
6458
Daniel Veillardea3f3982003-01-26 19:45:18 +00006459 if ((nval == NULL) || (nvalue == NULL) ||
6460 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00006461 ret = -1;
6462 if (nval != NULL)
6463 xmlFree(nval);
6464 if (nvalue != NULL)
6465 xmlFree(nvalue);
6466 }
6467 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006468 if (ret == 0)
6469 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00006470 break;
6471 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006472 case XML_RELAXNG_DATATYPE: {
6473 ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
6474 if (ret == 0)
6475 xmlRelaxNGNextValue(ctxt);
6476
6477 break;
6478 }
6479 case XML_RELAXNG_CHOICE: {
6480 xmlRelaxNGDefinePtr list = define->content;
6481 xmlChar *oldvalue;
6482
6483 oldflags = ctxt->flags;
6484 ctxt->flags |= FLAGS_IGNORABLE;
6485
6486 oldvalue = ctxt->state->value;
6487 while (list != NULL) {
6488 ret = xmlRelaxNGValidateValue(ctxt, list);
6489 if (ret == 0) {
6490 break;
6491 }
6492 ctxt->state->value = oldvalue;
6493 list = list->next;
6494 }
6495 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006496 if (ret != 0) {
6497 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6498 xmlRelaxNGDumpValidError(ctxt);
6499 } else {
6500 ctxt->errNr = 0;
6501 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006502 if (ret == 0)
6503 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006504 break;
6505 }
6506 case XML_RELAXNG_LIST: {
6507 xmlRelaxNGDefinePtr list = define->content;
6508 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00006509#ifdef DEBUG_LIST
6510 int nb_values = 0;
6511#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006512
6513 oldvalue = ctxt->state->value;
6514 oldend = ctxt->state->endvalue;
6515
6516 val = xmlStrdup(oldvalue);
6517 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006518 val = xmlStrdup(BAD_CAST "");
6519 }
6520 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006521 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006522 return(-1);
6523 }
6524 cur = val;
6525 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006526 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006527 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00006528 cur++;
6529#ifdef DEBUG_LIST
6530 nb_values++;
6531#endif
6532 while (IS_BLANK(*cur))
6533 *cur++ = 0;
6534 } else
6535 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006536 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006537#ifdef DEBUG_LIST
6538 xmlGenericError(xmlGenericErrorContext,
6539 "list value: '%s' found %d items\n", oldvalue, nb_values);
6540 nb_values = 0;
6541#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006542 ctxt->state->endvalue = cur;
6543 cur = val;
6544 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
6545
6546 ctxt->state->value = cur;
6547
6548 while (list != NULL) {
Daniel Veillard2e9b1652003-02-19 13:29:45 +00006549 if (ctxt->state->value == ctxt->state->endvalue)
6550 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006551 ret = xmlRelaxNGValidateValue(ctxt, list);
6552 if (ret != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006553#ifdef DEBUG_LIST
6554 xmlGenericError(xmlGenericErrorContext,
6555 "Failed to validate value: '%s' with %d rule\n",
6556 ctxt->state->value, nb_values);
6557#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006558 break;
6559 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006560#ifdef DEBUG_LIST
6561 nb_values++;
6562#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006563 list = list->next;
6564 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00006565
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006566 if ((ret == 0) && (ctxt->state->value != NULL) &&
6567 (ctxt->state->value != ctxt->state->endvalue)) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006568 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006569 ret = -1;
6570 }
6571 xmlFree(val);
6572 ctxt->state->value = oldvalue;
6573 ctxt->state->endvalue = oldend;
6574 break;
6575 }
6576 case XML_RELAXNG_ONEORMORE:
6577 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6578 if (ret != 0) {
6579 break;
6580 }
6581 /* no break on purpose */
6582 case XML_RELAXNG_ZEROORMORE: {
6583 xmlChar *cur, *temp;
6584
6585 oldflags = ctxt->flags;
6586 ctxt->flags |= FLAGS_IGNORABLE;
6587 cur = ctxt->state->value;
6588 temp = NULL;
6589 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
6590 (temp != cur)) {
6591 temp = cur;
6592 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6593 if (ret != 0) {
6594 ctxt->state->value = temp;
6595 ret = 0;
6596 break;
6597 }
6598 cur = ctxt->state->value;
6599 }
6600 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006601 if (ret != 0) {
6602 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6603 xmlRelaxNGDumpValidError(ctxt);
6604 } else {
6605 ctxt->errNr = 0;
6606 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006607 break;
6608 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006609 case XML_RELAXNG_EXCEPT: {
6610 xmlRelaxNGDefinePtr list;
6611
6612 list = define->content;
6613 while (list != NULL) {
6614 ret = xmlRelaxNGValidateValue(ctxt, list);
6615 if (ret == 0) {
6616 ret = -1;
6617 break;
6618 } else
6619 ret = 0;
6620 list = list->next;
6621 }
6622 break;
6623 }
Daniel Veillard463a5472003-02-27 21:30:32 +00006624 case XML_RELAXNG_DEF:
Daniel Veillardd4310742003-02-18 21:12:46 +00006625 case XML_RELAXNG_GROUP: {
6626 xmlRelaxNGDefinePtr list;
6627
6628 list = define->content;
6629 while (list != NULL) {
6630 ret = xmlRelaxNGValidateValue(ctxt, list);
6631 if (ret != 0) {
6632 ret = -1;
6633 break;
6634 } else
6635 ret = 0;
6636 list = list->next;
6637 }
6638 break;
6639 }
Daniel Veillard463a5472003-02-27 21:30:32 +00006640 case XML_RELAXNG_REF:
6641 case XML_RELAXNG_PARENTREF:
6642 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6643 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006644 default:
6645 TODO
6646 ret = -1;
6647 }
6648 return(ret);
6649}
6650
6651/**
6652 * xmlRelaxNGValidateValueContent:
6653 * @ctxt: a Relax-NG validation context
6654 * @defines: the list of definitions to verify
6655 *
6656 * Validate the given definitions for the current value
6657 *
6658 * Returns 0 if the validation succeeded or an error code.
6659 */
6660static int
6661xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
6662 xmlRelaxNGDefinePtr defines) {
6663 int ret = 0;
6664
6665 while (defines != NULL) {
6666 ret = xmlRelaxNGValidateValue(ctxt, defines);
6667 if (ret != 0)
6668 break;
6669 defines = defines->next;
6670 }
6671 return(ret);
6672}
6673
6674/**
Daniel Veillard144fae12003-02-03 13:17:57 +00006675 * xmlRelaxNGAttributeMatch:
6676 * @ctxt: a Relax-NG validation context
6677 * @define: the definition to check
6678 * @prop: the attribute
6679 *
6680 * Check if the attribute matches the definition nameClass
6681 *
6682 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
6683 */
6684static int
6685xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
6686 xmlRelaxNGDefinePtr define,
6687 xmlAttrPtr prop) {
6688 int ret;
6689
6690 if (define->name != NULL) {
6691 if (!xmlStrEqual(define->name, prop->name))
6692 return(0);
6693 }
6694 if (define->ns != NULL) {
6695 if (define->ns[0] == 0) {
6696 if (prop->ns != NULL)
6697 return(0);
6698 } else {
6699 if ((prop->ns == NULL) ||
6700 (!xmlStrEqual(define->ns, prop->ns->href)))
6701 return(0);
6702 }
6703 }
6704 if (define->nameClass == NULL)
6705 return(1);
6706 define = define->nameClass;
6707 if (define->type == XML_RELAXNG_EXCEPT) {
6708 xmlRelaxNGDefinePtr list;
6709
6710 list = define->content;
6711 while (list != NULL) {
6712 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
6713 if (ret == 1)
6714 return(0);
6715 if (ret < 0)
6716 return(ret);
6717 list = list->next;
6718 }
6719 } else {
6720 TODO
6721 }
6722 return(1);
6723}
6724
6725/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006726 * xmlRelaxNGValidateAttribute:
6727 * @ctxt: a Relax-NG validation context
6728 * @define: the definition to verify
6729 *
6730 * Validate the given attribute definition for that node
6731 *
6732 * Returns 0 if the validation succeeded or an error code.
6733 */
6734static int
6735xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
6736 xmlRelaxNGDefinePtr define) {
6737 int ret = 0, i;
6738 xmlChar *value, *oldvalue;
6739 xmlAttrPtr prop = NULL, tmp;
6740
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006741 if (ctxt->state->nbAttrLeft <= 0)
6742 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006743 if (define->name != NULL) {
6744 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6745 tmp = ctxt->state->attrs[i];
6746 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
6747 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
6748 (tmp->ns == NULL)) ||
6749 ((tmp->ns != NULL) &&
6750 (xmlStrEqual(define->ns, tmp->ns->href)))) {
6751 prop = tmp;
6752 break;
6753 }
6754 }
6755 }
6756 if (prop != NULL) {
6757 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6758 oldvalue = ctxt->state->value;
6759 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00006760 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006761 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00006762 if (ctxt->state->value != NULL)
6763 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006764 if (value != NULL)
6765 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00006766 ctxt->state->value = oldvalue;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006767 if (ret == 0) {
6768 /*
6769 * flag the attribute as processed
6770 */
6771 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006772 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006773 }
6774 } else {
6775 ret = -1;
6776 }
6777#ifdef DEBUG
6778 xmlGenericError(xmlGenericErrorContext,
6779 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
6780#endif
6781 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006782 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6783 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00006784 if ((tmp != NULL) &&
6785 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006786 prop = tmp;
6787 break;
6788 }
6789 }
6790 if (prop != NULL) {
6791 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6792 oldvalue = ctxt->state->value;
6793 ctxt->state->value = value;
6794 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00006795 if (ctxt->state->value != NULL)
6796 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006797 if (value != NULL)
6798 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00006799 ctxt->state->value = oldvalue;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006800 if (ret == 0) {
6801 /*
6802 * flag the attribute as processed
6803 */
6804 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006805 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006806 }
6807 } else {
6808 ret = -1;
6809 }
6810#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00006811 if (define->ns != NULL) {
6812 xmlGenericError(xmlGenericErrorContext,
6813 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
6814 define->ns, ret);
6815 } else {
6816 xmlGenericError(xmlGenericErrorContext,
6817 "xmlRelaxNGValidateAttribute(anyName): %d\n",
6818 ret);
6819 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006820#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00006821 }
6822
6823 return(ret);
6824}
6825
6826/**
6827 * xmlRelaxNGValidateAttributeList:
6828 * @ctxt: a Relax-NG validation context
6829 * @define: the list of definition to verify
6830 *
6831 * Validate the given node against the list of attribute definitions
6832 *
6833 * Returns 0 if the validation succeeded or an error code.
6834 */
6835static int
6836xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
6837 xmlRelaxNGDefinePtr defines) {
6838 int ret = 0;
6839 while (defines != NULL) {
6840 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
6841 ret = -1;
6842 defines = defines->next;
6843 }
6844 return(ret);
6845}
6846
6847/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006848 * xmlRelaxNGNodeMatchesList:
6849 * @node: the node
6850 * @list: a NULL terminated array of definitions
6851 *
6852 * Check if a node can be matched by one of the definitions
6853 *
6854 * Returns 1 if matches 0 otherwise
6855 */
6856static int
6857xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
6858 xmlRelaxNGDefinePtr cur;
6859 int i = 0;
6860
6861 if ((node == NULL) || (list == NULL))
6862 return(0);
6863
6864 cur = list[i++];
6865 while (cur != NULL) {
6866 if ((node->type == XML_ELEMENT_NODE) &&
6867 (cur->type == XML_RELAXNG_ELEMENT)) {
6868 if (cur->name == NULL) {
6869 if ((node->ns != NULL) &&
6870 (xmlStrEqual(node->ns->href, cur->ns)))
6871 return(1);
6872 } else if (xmlStrEqual(cur->name, node->name)) {
6873 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
6874 if (node->ns == NULL)
6875 return(1);
6876 } else {
6877 if ((node->ns != NULL) &&
6878 (xmlStrEqual(node->ns->href, cur->ns)))
6879 return(1);
6880 }
6881 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006882 } else if (((node->type == XML_TEXT_NODE) ||
6883 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006884 (cur->type == XML_RELAXNG_TEXT)) {
6885 return(1);
6886 }
6887 cur = list[i++];
6888 }
6889 return(0);
6890}
6891
6892/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006893 * xmlRelaxNGValidateInterleave:
6894 * @ctxt: a Relax-NG validation context
6895 * @define: the definition to verify
6896 *
6897 * Validate an interleave definition for a node.
6898 *
6899 * Returns 0 if the validation succeeded or an error code.
6900 */
6901static int
6902xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
6903 xmlRelaxNGDefinePtr define) {
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006904 int ret = 0, i, nbgroups, left;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006905 int errNr = ctxt->errNr;
6906
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006907 xmlRelaxNGPartitionPtr partitions;
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006908 xmlRelaxNGInterleaveGroupPtr group = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006909 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006910 xmlNodePtr *list = NULL, *lasts = NULL;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006911
6912 if (define->data != NULL) {
6913 partitions = (xmlRelaxNGPartitionPtr) define->data;
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006914 nbgroups = partitions->nbgroups;
6915 left = nbgroups;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006916 } else {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006917 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006918 return(-1);
6919 }
6920
6921 /*
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006922 * Build arrays to store the first and last node of the chain
6923 * pertaining to each group
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006924 */
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006925 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6926 if (list == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006927 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006928 return(-1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006929 }
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006930 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
6931 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6932 if (lasts == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006933 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006934 return(-1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006935 }
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006936 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006937
6938 /*
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006939 * Walk the sequence of children finding the right group and
6940 * sorting them in sequences.
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006941 */
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006942 cur = ctxt->state->seq;
6943 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6944 start = cur;
6945 while (cur != NULL) {
6946 ctxt->state->seq = cur;
6947 for (i = 0;i < nbgroups;i++) {
6948 group = partitions->groups[i];
6949 if (group == NULL)
6950 continue;
6951 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
6952 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006953 }
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006954 /*
6955 * We break as soon as an element not matched is found
6956 */
6957 if (i >= nbgroups) {
6958 break;
6959 }
6960 if (lasts[i] != NULL) {
6961 lasts[i]->next = cur;
6962 lasts[i] = cur;
6963 } else {
6964 list[i] = cur;
6965 lasts[i] = cur;
6966 }
6967 if (cur->next != NULL)
6968 lastchg = cur->next;
6969 else
6970 lastchg = cur;
6971 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006972 }
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006973 if (ret != 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006974 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006975 ret = -1;
6976 goto done;
6977 }
6978 lastelem = cur;
6979 for (i = 0;i < nbgroups;i++) {
6980 group = partitions->groups[i];
6981 if (lasts[i] != NULL) {
6982 last = lasts[i]->next;
6983 lasts[i]->next = NULL;
6984 }
6985 ctxt->state->seq = list[i];
6986 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
6987 if (ret != 0)
6988 break;
6989 cur = ctxt->state->seq;
6990 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6991 if (cur != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006992 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00006993 ret = -1;
6994 goto done;
6995 }
6996 if (lasts[i] != NULL) {
6997 lasts[i]->next = last;
6998 }
6999 }
7000 ctxt->state->seq = lastelem;
7001 if (ret != 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007002 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007003 ret = -1;
7004 goto done;
7005 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007006
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007007done:
7008 /*
7009 * builds the next links chain from the prev one
7010 */
7011 cur = lastchg;
7012 while (cur != NULL) {
7013 if ((cur == start) || (cur->prev == NULL))
7014 break;
7015 cur->prev->next = cur;
7016 cur = cur->prev;
7017 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00007018 if (ret == 0) {
7019 ctxt->errNr = errNr;
7020 }
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007021
7022 xmlFree(list);
7023 xmlFree(lasts);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007024 return(ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007025}
7026
7027/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007028 * xmlRelaxNGValidateElementContent:
7029 * @ctxt: a Relax-NG validation context
7030 * @define: the list of definition to verify
7031 *
7032 * Validate the given node content against the (list) of definitions
7033 *
7034 * Returns 0 if the validation succeeded or an error code.
7035 */
7036static int
7037xmlRelaxNGValidateElementContent(xmlRelaxNGValidCtxtPtr ctxt,
7038 xmlRelaxNGDefinePtr defines) {
7039 int ret = 0, res;
7040
7041 if (ctxt->state == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007042 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007043 return(-1);
7044 }
7045 while (defines != NULL) {
7046 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7047 if (res < 0)
7048 ret = -1;
7049 defines = defines->next;
7050 }
7051
7052 return(ret);
7053}
7054
7055/**
Daniel Veillard416589a2003-02-17 17:25:42 +00007056 * xmlRelaxNGElementMatch:
7057 * @ctxt: a Relax-NG validation context
7058 * @define: the definition to check
7059 * @elem: the element
7060 *
7061 * Check if the element matches the definition nameClass
7062 *
7063 * Returns 1 if the element matches, 0 if no, or -1 in case of error
7064 */
7065static int
7066xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7067 xmlRelaxNGDefinePtr define,
7068 xmlNodePtr elem) {
7069 int ret, oldflags;
7070
7071 if (define->name != NULL) {
7072 if (!xmlStrEqual(elem->name, define->name)) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007073 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
Daniel Veillard416589a2003-02-17 17:25:42 +00007074 return(0);
7075 }
7076 }
7077 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7078 if (elem->ns == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007079 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
Daniel Veillard416589a2003-02-17 17:25:42 +00007080 elem->name);
7081 return(0);
7082 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007083 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
Daniel Veillard416589a2003-02-17 17:25:42 +00007084 elem->name, define->ns);
7085 return(0);
7086 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00007087 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7088 (define->name == NULL)) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007089 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7090 elem->name);
Daniel Veillard8fe98712003-02-19 00:19:14 +00007091 return(0);
7092 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007093 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
Daniel Veillard8fe98712003-02-19 00:19:14 +00007094 define->name);
7095 return(0);
Daniel Veillard416589a2003-02-17 17:25:42 +00007096 }
7097
7098 if (define->nameClass == NULL)
7099 return(1);
7100
7101 define = define->nameClass;
7102 if (define->type == XML_RELAXNG_EXCEPT) {
7103 xmlRelaxNGDefinePtr list;
7104 oldflags = ctxt->flags;
7105 ctxt->flags |= FLAGS_IGNORABLE;
7106
7107 list = define->content;
7108 while (list != NULL) {
7109 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7110 if (ret == 1) {
7111 ctxt->flags = oldflags;
7112 return(0);
7113 }
7114 if (ret < 0) {
7115 ctxt->flags = oldflags;
7116 return(ret);
7117 }
7118 list = list->next;
7119 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00007120 ret = 1;
7121 ctxt->flags = oldflags;
7122 } else if (define->type == XML_RELAXNG_CHOICE) {
7123 xmlRelaxNGDefinePtr list;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007124
Daniel Veillard2e9b1652003-02-19 13:29:45 +00007125 oldflags = ctxt->flags;
7126 ctxt->flags |= FLAGS_IGNORABLE;
7127
7128 list = define->nameClass;
7129 while (list != NULL) {
7130 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7131 if (ret == 1) {
7132 ctxt->flags = oldflags;
7133 return(1);
7134 }
7135 if (ret < 0) {
7136 ctxt->flags = oldflags;
7137 return(ret);
7138 }
7139 list = list->next;
7140 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00007141 if (ret != 0) {
7142 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7143 xmlRelaxNGDumpValidError(ctxt);
7144 } else {
7145 ctxt->errNr = 0;
7146 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00007147 ret = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007148 ctxt->flags = oldflags;
7149 } else {
7150 TODO
Daniel Veillard2e9b1652003-02-19 13:29:45 +00007151 ret = -1;
Daniel Veillard416589a2003-02-17 17:25:42 +00007152 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00007153 return(ret);
Daniel Veillard416589a2003-02-17 17:25:42 +00007154}
7155
7156/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007157 * xmlRelaxNGValidateDefinition:
7158 * @ctxt: a Relax-NG validation context
7159 * @define: the definition to verify
7160 *
7161 * Validate the current node against the definition
7162 *
7163 * Returns 0 if the validation succeeded or an error code.
7164 */
7165static int
7166xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7167 xmlRelaxNGDefinePtr define) {
7168 xmlNodePtr node;
7169 int ret = 0, i, tmp, oldflags;
7170 xmlRelaxNGValidStatePtr oldstate, state;
7171
7172 if (define == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007173 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007174 return(-1);
7175 }
7176 if (ctxt->state != NULL) {
7177 node = ctxt->state->seq;
7178 } else {
7179 node = NULL;
7180 }
Daniel Veillard231d7912003-02-09 14:22:17 +00007181#ifdef DEBUG
7182 for (i = 0;i < ctxt->depth;i++)
7183 xmlGenericError(xmlGenericErrorContext, " ");
7184 xmlGenericError(xmlGenericErrorContext,
7185 "Start validating %s ", xmlRelaxNGDefName(define));
7186 if (define->name != NULL)
7187 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7188 if ((node != NULL) && (node->name != NULL))
7189 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
7190 else
7191 xmlGenericError(xmlGenericErrorContext, "\n");
7192#endif
7193 ctxt->depth++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007194 switch (define->type) {
7195 case XML_RELAXNG_EMPTY:
Daniel Veillardd4310742003-02-18 21:12:46 +00007196 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007197#if 0
Daniel Veillard6eadf632003-01-23 18:29:16 +00007198 if (node != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007199 VALID_ERR2(XML_RELAXNG_ERR_ELEMNOTEMPTY,
7200 ctxt->state->node->name);
Daniel Veillard231d7912003-02-09 14:22:17 +00007201 ret = -1;
7202 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007203 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007204#endif
Daniel Veillard231d7912003-02-09 14:22:17 +00007205 ret = 0;
7206 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007207 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard231d7912003-02-09 14:22:17 +00007208 ret = -1;
7209 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007210 case XML_RELAXNG_TEXT:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007211 while ((node != NULL) &&
7212 ((node->type == XML_TEXT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007213 (node->type == XML_COMMENT_NODE) ||
7214 (node->type == XML_PI_NODE) ||
Daniel Veillard6eadf632003-01-23 18:29:16 +00007215 (node->type == XML_CDATA_SECTION_NODE)))
7216 node = node->next;
Daniel Veillard276be4a2003-01-24 01:03:34 +00007217 ctxt->state->seq = node;
7218 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007219 case XML_RELAXNG_ELEMENT:
7220 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillard231d7912003-02-09 14:22:17 +00007221 if (node == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007222 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
Daniel Veillard231d7912003-02-09 14:22:17 +00007223 ret = -1;
7224 break;
7225 }
7226 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007227 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
Daniel Veillard231d7912003-02-09 14:22:17 +00007228 ret = -1;
7229 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007230 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007231 /*
7232 * This node was already validated successfully against
7233 * this definition.
7234 */
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007235 if (node->_private == define) {
7236 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007237 break;
Daniel Veillardc64b8e92003-02-24 11:47:13 +00007238 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007239
7240 ret = xmlRelaxNGElementMatch(ctxt, define, node);
7241 if (ret <= 0) {
7242 ret = -1;
7243 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007244 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007245 ret = 0;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007246 if (ctxt->errNr != 0) {
7247 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7248 ctxt->errNr = 0;
7249 else {
7250 while ((ctxt->err != NULL) &&
7251 (ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
7252 (xmlStrEqual(ctxt->err->arg2, node->name)))
7253 xmlRelaxNGValidErrorPop(ctxt);
7254 }
7255 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007256
7257 state = xmlRelaxNGNewValidState(ctxt, node);
7258 if (state == NULL) {
Daniel Veillard231d7912003-02-09 14:22:17 +00007259 ret = -1;
7260 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007261 }
7262
7263 oldstate = ctxt->state;
7264 ctxt->state = state;
7265 if (define->attrs != NULL) {
7266 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
Daniel Veillard231d7912003-02-09 14:22:17 +00007267 if (tmp != 0) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007268 ret = -1;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007269 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
Daniel Veillard231d7912003-02-09 14:22:17 +00007270 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007271 }
7272 if (define->content != NULL) {
7273 tmp = xmlRelaxNGValidateElementContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007274 if (tmp != 0) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007275 ret = -1;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007276 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
Daniel Veillard231d7912003-02-09 14:22:17 +00007277 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007278 }
7279 state = ctxt->state;
7280 if (state->seq != NULL) {
7281 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
7282 if (state->seq != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007283 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007284 node->name, state->seq->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007285 ret = -1;
7286 }
7287 }
7288 for (i = 0;i < state->nbAttrs;i++) {
7289 if (state->attrs[i] != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007290 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
Daniel Veillard6eadf632003-01-23 18:29:16 +00007291 state->attrs[i]->name, node->name);
7292 ret = -1;
7293 }
7294 }
7295 ctxt->state = oldstate;
7296 xmlRelaxNGFreeValidState(state);
7297 if (oldstate != NULL)
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007298 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007299 if (ret == 0) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007300 node->_private = define;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007301 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007302
7303
7304#ifdef DEBUG
7305 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard231d7912003-02-09 14:22:17 +00007306 "xmlRelaxNGValidateDefinition(): validated %s : %d",
Daniel Veillard6eadf632003-01-23 18:29:16 +00007307 node->name, ret);
Daniel Veillard231d7912003-02-09 14:22:17 +00007308 if (oldstate == NULL)
7309 xmlGenericError(xmlGenericErrorContext, ": no state\n");
7310 else if (oldstate->seq == NULL)
7311 xmlGenericError(xmlGenericErrorContext, ": done\n");
7312 else if (oldstate->seq->type == XML_ELEMENT_NODE)
7313 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
7314 oldstate->seq->name);
7315 else
7316 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
7317 oldstate->seq->name, oldstate->seq->type);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007318#endif
7319 break;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007320 case XML_RELAXNG_OPTIONAL: {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007321 oldflags = ctxt->flags;
7322 ctxt->flags |= FLAGS_IGNORABLE;
7323 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7324 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
7325 if (ret != 0) {
7326 xmlRelaxNGFreeValidState(ctxt->state);
7327 ctxt->state = oldstate;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007328 ctxt->flags = oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007329 ret = 0;
7330 break;
7331 }
7332 xmlRelaxNGFreeValidState(oldstate);
7333 ctxt->flags = oldflags;
7334 ret = 0;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007335 ctxt->errNr = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007336 break;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007337 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007338 case XML_RELAXNG_ONEORMORE:
7339 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
7340 if (ret != 0) {
7341 break;
7342 }
7343 /* no break on purpose */
Daniel Veillard276be4a2003-01-24 01:03:34 +00007344 case XML_RELAXNG_ZEROORMORE: {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007345 oldflags = ctxt->flags;
7346 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007347 while (ctxt->state->nbAttrLeft != 0) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007348 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7349 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
7350 if (ret != 0) {
7351 xmlRelaxNGFreeValidState(ctxt->state);
7352 ctxt->state = oldstate;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007353 break;
7354 }
7355 xmlRelaxNGFreeValidState(oldstate);
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007356 }
7357 if (ret == 0) {
7358 /*
7359 * There is no attribute left to be consumed,
7360 * we can check the closure by looking at ctxt->state->seq
7361 */
7362 xmlNodePtr cur, temp;
7363
Daniel Veillard276be4a2003-01-24 01:03:34 +00007364 cur = ctxt->state->seq;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007365 temp = NULL;
7366 while ((cur != NULL) && (temp != cur)) {
7367 temp = cur;
7368 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7369 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
7370 if (ret != 0) {
7371 xmlRelaxNGFreeValidState(ctxt->state);
7372 ctxt->state = oldstate;
7373 break;
7374 }
7375 xmlRelaxNGFreeValidState(oldstate);
7376 cur = ctxt->state->seq;
7377 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007378 }
7379 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007380 if (ret == 0) {
7381 ctxt->errNr = 0;
7382 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007383 ret = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007384 break;
Daniel Veillard276be4a2003-01-24 01:03:34 +00007385 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007386 case XML_RELAXNG_CHOICE: {
7387 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardce14fa52003-02-19 17:32:48 +00007388 int success = 0;
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007389 xmlRelaxNGValidStatePtr sstate = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007390
7391 oldflags = ctxt->flags;
7392 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007393 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007394
7395 while (list != NULL) {
7396 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7397 ret = xmlRelaxNGValidateDefinition(ctxt, list);
7398 if (ret == 0) {
Daniel Veillardce14fa52003-02-19 17:32:48 +00007399 if (xmlRelaxNGEqualValidState(ctxt, ctxt->state, oldstate)){
7400 /*
7401 * if that pattern was nullable flag it but try
7402 * to make more progresses
7403 */
7404 success = 1;
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007405 if (sstate != NULL) {
7406 xmlRelaxNGFreeValidState(sstate);
7407 }
7408 sstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
Daniel Veillardce14fa52003-02-19 17:32:48 +00007409 } else {
7410 xmlRelaxNGFreeValidState(oldstate);
7411 break;
7412 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007413 }
7414 xmlRelaxNGFreeValidState(ctxt->state);
7415 ctxt->state = oldstate;
7416 list = list->next;
7417 }
7418 ctxt->flags = oldflags;
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007419 if (success == 1) {
7420 if (ret != 0) {
7421 xmlRelaxNGFreeValidState(ctxt->state);
7422 ctxt->state = sstate;
7423 } else {
7424 xmlRelaxNGFreeValidState(sstate);
7425 }
Daniel Veillardce14fa52003-02-19 17:32:48 +00007426 ret = 0;
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007427 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00007428 if (ret != 0) {
7429 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7430 xmlRelaxNGDumpValidError(ctxt);
7431 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7432 ctxt->errNr = 0;
7433 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007434 break;
7435 }
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007436 case XML_RELAXNG_DEF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007437 case XML_RELAXNG_GROUP: {
7438 xmlRelaxNGDefinePtr list = define->content;
7439
7440 while (list != NULL) {
7441 ret = xmlRelaxNGValidateDefinition(ctxt, list);
7442 if (ret != 0)
7443 break;
7444 list = list->next;
7445 }
7446 break;
7447 }
7448 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007449 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007450 break;
7451 case XML_RELAXNG_ATTRIBUTE:
7452 ret = xmlRelaxNGValidateAttribute(ctxt, define);
7453 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007454 case XML_RELAXNG_NOOP:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007455 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00007456 case XML_RELAXNG_PARENTREF:
7457 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007458 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
7459 break;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007460 case XML_RELAXNG_DATATYPE: {
Daniel Veillardd4310742003-02-18 21:12:46 +00007461 xmlNodePtr child;
7462 xmlChar *content = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007463
Daniel Veillardd4310742003-02-18 21:12:46 +00007464 child = node;
7465 while (child != NULL) {
7466 if (child->type == XML_ELEMENT_NODE) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007467 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
Daniel Veillardd4310742003-02-18 21:12:46 +00007468 node->parent->name);
7469 ret = -1;
7470 break;
7471 } else if ((child->type == XML_TEXT_NODE) ||
7472 (child->type == XML_CDATA_SECTION_NODE)) {
7473 content = xmlStrcat(content, child->content);
7474 }
7475 /* TODO: handle entities ... */
7476 child = child->next;
7477 }
7478 if (ret == -1) {
7479 if (content != NULL)
7480 xmlFree(content);
7481 break;
7482 }
7483 if (content == NULL) {
7484 content = xmlStrdup(BAD_CAST "");
7485 if (content == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007486 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardd4310742003-02-18 21:12:46 +00007487 ret = -1;
7488 break;
7489 }
7490 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007491 ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
7492 if (ret == -1) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007493 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007494 } else if (ret == 0) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007495 ctxt->state->seq = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007496 }
7497 if (content != NULL)
7498 xmlFree(content);
7499 break;
7500 }
Daniel Veillardea3f3982003-01-26 19:45:18 +00007501 case XML_RELAXNG_VALUE: {
Daniel Veillardd4310742003-02-18 21:12:46 +00007502 xmlChar *content = NULL;
Daniel Veillardea3f3982003-01-26 19:45:18 +00007503 xmlChar *oldvalue;
Daniel Veillardd4310742003-02-18 21:12:46 +00007504 xmlNodePtr child;
Daniel Veillardea3f3982003-01-26 19:45:18 +00007505
Daniel Veillardd4310742003-02-18 21:12:46 +00007506 child = node;
7507 while (child != NULL) {
7508 if (child->type == XML_ELEMENT_NODE) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007509 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
Daniel Veillardd4310742003-02-18 21:12:46 +00007510 node->parent->name);
7511 ret = -1;
7512 break;
7513 } else if ((child->type == XML_TEXT_NODE) ||
7514 (child->type == XML_CDATA_SECTION_NODE)) {
7515 content = xmlStrcat(content, child->content);
7516 }
7517 /* TODO: handle entities ... */
7518 child = child->next;
7519 }
7520 if (ret == -1) {
7521 if (content != NULL)
7522 xmlFree(content);
7523 break;
7524 }
7525 if (content == NULL) {
7526 content = xmlStrdup(BAD_CAST "");
7527 if (content == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007528 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardd4310742003-02-18 21:12:46 +00007529 ret = -1;
7530 break;
7531 }
7532 }
Daniel Veillardea3f3982003-01-26 19:45:18 +00007533 oldvalue = ctxt->state->value;
7534 ctxt->state->value = content;
7535 ret = xmlRelaxNGValidateValue(ctxt, define);
7536 ctxt->state->value = oldvalue;
7537 if (ret == -1) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007538 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007539 } else if (ret == 0) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007540 ctxt->state->seq = NULL;
Daniel Veillardea3f3982003-01-26 19:45:18 +00007541 }
7542 if (content != NULL)
7543 xmlFree(content);
7544 break;
7545 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007546 case XML_RELAXNG_LIST: {
7547 xmlChar *content;
Daniel Veillardd4310742003-02-18 21:12:46 +00007548 xmlNodePtr child;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007549 xmlChar *oldvalue, *oldendvalue;
7550 int len;
Daniel Veillardea3f3982003-01-26 19:45:18 +00007551
Daniel Veillardd4310742003-02-18 21:12:46 +00007552 /*
7553 * Make sure it's only text nodes
7554 */
7555
7556 content = NULL;
7557 child = node;
7558 while (child != NULL) {
7559 if (child->type == XML_ELEMENT_NODE) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007560 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
Daniel Veillardd4310742003-02-18 21:12:46 +00007561 node->parent->name);
7562 ret = -1;
7563 break;
7564 } else if ((child->type == XML_TEXT_NODE) ||
7565 (child->type == XML_CDATA_SECTION_NODE)) {
7566 content = xmlStrcat(content, child->content);
7567 }
7568 /* TODO: handle entities ... */
7569 child = child->next;
7570 }
7571 if (ret == -1) {
7572 if (content != NULL)
7573 xmlFree(content);
7574 break;
7575 }
7576 if (content == NULL) {
7577 content = xmlStrdup(BAD_CAST "");
7578 if (content == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007579 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardd4310742003-02-18 21:12:46 +00007580 ret = -1;
7581 break;
7582 }
7583 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007584 len = xmlStrlen(content);
7585 oldvalue = ctxt->state->value;
7586 oldendvalue = ctxt->state->endvalue;
7587 ctxt->state->value = content;
7588 ctxt->state->endvalue = content + len;
7589 ret = xmlRelaxNGValidateValue(ctxt, define);
7590 ctxt->state->value = oldvalue;
7591 ctxt->state->endvalue = oldendvalue;
7592 if (ret == -1) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007593 VALID_ERR(XML_RELAXNG_ERR_LIST);
Daniel Veillardd4310742003-02-18 21:12:46 +00007594 } else if ((ret == 0) && (node != NULL)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007595 ctxt->state->seq = node->next;
7596 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007597 if (content != NULL)
7598 xmlFree(content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007599 break;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007600 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007601 case XML_RELAXNG_START:
Daniel Veillard144fae12003-02-03 13:17:57 +00007602 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007603 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007604 TODO
Daniel Veillard416589a2003-02-17 17:25:42 +00007605 ret = -1;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007606 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007607 }
Daniel Veillard231d7912003-02-09 14:22:17 +00007608 ctxt->depth--;
7609#ifdef DEBUG
7610 for (i = 0;i < ctxt->depth;i++)
7611 xmlGenericError(xmlGenericErrorContext, " ");
7612 xmlGenericError(xmlGenericErrorContext,
7613 "Validating %s ", xmlRelaxNGDefName(define));
7614 if (define->name != NULL)
7615 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7616 if (ret == 0)
7617 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
7618 else
7619 xmlGenericError(xmlGenericErrorContext, "failed\n");
7620#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007621 return(ret);
7622}
7623
7624/**
7625 * xmlRelaxNGValidateDocument:
7626 * @ctxt: a Relax-NG validation context
7627 * @doc: the document
7628 *
7629 * Validate the given document
7630 *
7631 * Returns 0 if the validation succeeded or an error code.
7632 */
7633static int
7634xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7635 int ret;
7636 xmlRelaxNGPtr schema;
7637 xmlRelaxNGGrammarPtr grammar;
7638 xmlRelaxNGValidStatePtr state;
7639
7640 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
7641 return(-1);
7642
7643 schema = ctxt->schema;
7644 grammar = schema->topgrammar;
7645 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007646 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007647 return(-1);
7648 }
7649 state = xmlRelaxNGNewValidState(ctxt, NULL);
7650 ctxt->state = state;
7651 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
7652 state = ctxt->state;
7653 if ((state != NULL) && (state->seq != NULL)) {
7654 xmlNodePtr node;
7655
7656 node = state->seq;
7657 node = xmlRelaxNGSkipIgnored(ctxt, node);
7658 if (node != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007659 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007660 ret = -1;
7661 }
7662 }
7663 xmlRelaxNGFreeValidState(state);
7664
7665 return(ret);
7666}
7667
7668/************************************************************************
7669 * *
7670 * Validation interfaces *
7671 * *
7672 ************************************************************************/
7673/**
7674 * xmlRelaxNGNewValidCtxt:
7675 * @schema: a precompiled XML RelaxNGs
7676 *
7677 * Create an XML RelaxNGs validation context based on the given schema
7678 *
7679 * Returns the validation context or NULL in case of error
7680 */
7681xmlRelaxNGValidCtxtPtr
7682xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
7683 xmlRelaxNGValidCtxtPtr ret;
7684
7685 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
7686 if (ret == NULL) {
7687 xmlGenericError(xmlGenericErrorContext,
7688 "Failed to allocate new schama validation context\n");
7689 return (NULL);
7690 }
7691 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
7692 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00007693 ret->error = xmlGenericError;
7694 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007695 ret->errNr = 0;
7696 ret->errMax = 0;
7697 ret->err = NULL;
7698 ret->errTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007699 return (ret);
7700}
7701
7702/**
7703 * xmlRelaxNGFreeValidCtxt:
7704 * @ctxt: the schema validation context
7705 *
7706 * Free the resources associated to the schema validation context
7707 */
7708void
7709xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
7710 if (ctxt == NULL)
7711 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007712 if (ctxt->errTab != NULL)
7713 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007714 xmlFree(ctxt);
7715}
7716
7717/**
7718 * xmlRelaxNGSetValidErrors:
7719 * @ctxt: a Relax-NG validation context
7720 * @err: the error function
7721 * @warn: the warning function
7722 * @ctx: the functions context
7723 *
7724 * Set the error and warning callback informations
7725 */
7726void
7727xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
7728 xmlRelaxNGValidityErrorFunc err,
7729 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7730 if (ctxt == NULL)
7731 return;
7732 ctxt->error = err;
7733 ctxt->warning = warn;
7734 ctxt->userData = ctx;
7735}
7736
7737/**
7738 * xmlRelaxNGValidateDoc:
7739 * @ctxt: a Relax-NG validation context
7740 * @doc: a parsed document tree
7741 *
7742 * Validate a document tree in memory.
7743 *
7744 * Returns 0 if the document is valid, a positive error code
7745 * number otherwise and -1 in case of internal or API error.
7746 */
7747int
7748xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7749 int ret;
7750
7751 if ((ctxt == NULL) || (doc == NULL))
7752 return(-1);
7753
7754 ctxt->doc = doc;
7755
7756 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00007757 /*
7758 * TODO: build error codes
7759 */
7760 if (ret == -1)
7761 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007762 return(ret);
7763}
7764
7765#endif /* LIBXML_SCHEMAS_ENABLED */
7766