blob: 91e249b08c3a914142cdf48cd211e0e64902fe76 [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 Veillard1564e6e2003-03-15 21:30:25 +0000105#if 0
Daniel Veillard77648bb2003-02-20 15:03:22 +0000106 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000107#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +0000108 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
109 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000110 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000111 XML_RELAXNG_TEXT, /* textual content */
112 XML_RELAXNG_ELEMENT, /* an element */
113 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000114 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000115 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
116 XML_RELAXNG_LIST, /* a list of patterns */
117 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
118 XML_RELAXNG_DEF, /* a definition */
119 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000120 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000121 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000122 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 */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000126 XML_RELAXNG_START, /* Used to keep track of starts on grammars */
127 XML_RELAXNG_AFTER /* only generated at runtime */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000128} xmlRelaxNGType;
129
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000130#define IS_NULLABLE 1
131#define IS_NOT_NULLABLE 2
132#define IS_DYNAMIC 4
133
134struct _xmlRelaxNGShortDefine {
135 xmlRelaxNGType type; /* the type of definition */
136 short flags; /* used for the cycle detection */
137 short depth; /* used for the cycle detection */
138 xmlRelaxNGDefinePtr content;/* the expected content */
139 xmlRelaxNGDefinePtr cont2; /* the second content if dual operator */
140 xmlChar *name; /* the element local name if present */
141};
142
Daniel Veillard6eadf632003-01-23 18:29:16 +0000143struct _xmlRelaxNGDefine {
144 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000145 short flags; /* used for the cycle detection */
146 short depth; /* used for the cycle detection */
147 xmlRelaxNGDefinePtr content;/* the expected content */
148 xmlRelaxNGDefinePtr cont2; /* the second content if dual operator */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000149 xmlChar *name; /* the element local name if present */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000150 xmlNodePtr node; /* the node in the source */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000151 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000152 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000153 void *data; /* data lib or specific pointer */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000154 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000155 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000156 xmlRelaxNGDefinePtr prop; /* properties */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000157 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000158 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
159};
160
161/**
162 * _xmlRelaxNG:
163 *
164 * A RelaxNGs definition
165 */
166struct _xmlRelaxNG {
167 xmlRelaxNGGrammarPtr topgrammar;
168 xmlDocPtr doc;
169
170 xmlHashTablePtr defs; /* define */
171 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000172 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
173 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000174 int defNr; /* number of defines used */
175 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000176 void *_private; /* unused by the library for users or bindings */
177};
178
Daniel Veillard77648bb2003-02-20 15:03:22 +0000179#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
180#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
181#define XML_RELAXNG_IN_LIST (1 << 2)
182#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
183#define XML_RELAXNG_IN_START (1 << 4)
184#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
185#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
186#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000187#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
188#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000189
190struct _xmlRelaxNGParserCtxt {
191 void *userData; /* user specific data block */
192 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
193 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000194 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000195
196 xmlRelaxNGPtr schema; /* The schema in use */
197 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000198 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000199 int flags; /* parser flags */
200 int nbErrors; /* number of errors at parse time */
201 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000202 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000203 xmlRelaxNGDefinePtr def; /* the current define */
204
205 int nbInterleaves;
206 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000207
Daniel Veillardc482e262003-02-26 14:48:48 +0000208 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
209 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000210 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000211 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000212
Daniel Veillard419a7682003-02-03 23:22:49 +0000213 int defNr; /* number of defines used */
214 int defMax; /* number of defines aloocated */
215 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
216
Daniel Veillard6eadf632003-01-23 18:29:16 +0000217 const char *buffer;
218 int size;
219
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000220 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000221 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000222 int docNr; /* Depth of the parsing stack */
223 int docMax; /* Max depth of the parsing stack */
224 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000225
226 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000227 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000228 int incNr; /* Depth of the include parsing stack */
229 int incMax; /* Max depth of the parsing stack */
230 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000231};
232
233#define FLAGS_IGNORABLE 1
234#define FLAGS_NEGATIVE 2
235
236/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000237 * xmlRelaxNGInterleaveGroup:
238 *
239 * A RelaxNGs partition set associated to lists of definitions
240 */
241typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
242typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
243struct _xmlRelaxNGInterleaveGroup {
244 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
245 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000246 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000247};
248
249/**
250 * xmlRelaxNGPartitions:
251 *
252 * A RelaxNGs partition associated to an interleave group
253 */
254typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
255typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
256struct _xmlRelaxNGPartition {
257 int nbgroups; /* number of groups in the partitions */
258 xmlRelaxNGInterleaveGroupPtr *groups;
259};
260
261/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000262 * xmlRelaxNGValidState:
263 *
264 * A RelaxNGs validation state
265 */
266#define MAX_ATTR 20
267typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
268typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
269struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000270 xmlNodePtr node; /* the current node */
271 xmlNodePtr seq; /* the sequence of children left to validate */
272 int nbAttrs; /* the number of attributes */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000273 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000274 xmlChar *value; /* the value when operating on string */
275 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000276 xmlAttrPtr attrs[1]; /* the array of attributes */
277};
278
279/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000280 * xmlRelaxNGValidError:
281 *
282 * A RelaxNGs validation error
283 */
284typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
285typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
286struct _xmlRelaxNGValidError {
287 xmlRelaxNGValidErr err; /* the error number */
288 xmlNodePtr node; /* the current node */
289 xmlNodePtr seq; /* the current child */
290 const xmlChar * arg1; /* first arg */
291 const xmlChar * arg2; /* second arg */
292};
293
294/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000295 * xmlRelaxNGValidCtxt:
296 *
297 * A RelaxNGs validation context
298 */
299
300struct _xmlRelaxNGValidCtxt {
301 void *userData; /* user specific data block */
302 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
303 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
304
305 xmlRelaxNGPtr schema; /* The schema in use */
306 xmlDocPtr doc; /* the document being validated */
307 xmlRelaxNGValidStatePtr state; /* the current validation state */
308 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000309 int depth; /* validation depth */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000310
311 /*
312 * Errors accumulated in branches may have to be stacked to be
313 * provided back when it's sure they affect validation.
314 */
315 xmlRelaxNGValidErrorPtr err; /* Last error */
316 int errNr; /* Depth of the error stack */
317 int errMax; /* Max depth of the error stack */
318 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000319
320 /*
321 * To improve !!!
322 */
323 int defNr; /* number of defines used */
324 int defMax; /* number of defines aloocated */
325 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000326};
327
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000328/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000329 * xmlRelaxNGInclude:
330 *
331 * Structure associated to a RelaxNGs document element
332 */
333struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000334 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000335 xmlChar *href; /* the normalized href value */
336 xmlDocPtr doc; /* the associated XML document */
337 xmlRelaxNGDefinePtr content;/* the definitions */
338 xmlRelaxNGPtr schema; /* the schema */
339};
340
341/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000342 * xmlRelaxNGDocument:
343 *
344 * Structure associated to a RelaxNGs document element
345 */
346struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000347 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000348 xmlChar *href; /* the normalized href value */
349 xmlDocPtr doc; /* the associated XML document */
350 xmlRelaxNGDefinePtr content;/* the definitions */
351 xmlRelaxNGPtr schema; /* the schema */
352};
353
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000354
Daniel Veillard6eadf632003-01-23 18:29:16 +0000355/************************************************************************
356 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000357 * Preliminary type checking interfaces *
358 * *
359 ************************************************************************/
360/**
361 * xmlRelaxNGTypeHave:
362 * @data: data needed for the library
363 * @type: the type name
364 * @value: the value to check
365 *
366 * Function provided by a type library to check if a type is exported
367 *
368 * Returns 1 if yes, 0 if no and -1 in case of error.
369 */
370typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
371
372/**
373 * xmlRelaxNGTypeCheck:
374 * @data: data needed for the library
375 * @type: the type name
376 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000377 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000378 *
379 * Function provided by a type library to check if a value match a type
380 *
381 * Returns 1 if yes, 0 if no and -1 in case of error.
382 */
383typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000384 const xmlChar *value, void **result);
385
386/**
387 * xmlRelaxNGFacetCheck:
388 * @data: data needed for the library
389 * @type: the type name
390 * @facet: the facet name
391 * @val: the facet value
392 * @strval: the string value
393 * @value: the value to check
394 *
395 * Function provided by a type library to check a value facet
396 *
397 * Returns 1 if yes, 0 if no and -1 in case of error.
398 */
399typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
400 const xmlChar *facet, const xmlChar *val,
401 const xmlChar *strval, void *value);
402
403/**
404 * xmlRelaxNGTypeFree:
405 * @data: data needed for the library
406 * @result: the value to free
407 *
408 * Function provided by a type library to free a returned result
409 */
410typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000411
412/**
413 * xmlRelaxNGTypeCompare:
414 * @data: data needed for the library
415 * @type: the type name
416 * @value1: the first value
417 * @value2: the second value
418 *
419 * Function provided by a type library to compare two values accordingly
420 * to a type.
421 *
422 * Returns 1 if yes, 0 if no and -1 in case of error.
423 */
424typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
425 const xmlChar *value1,
426 const xmlChar *value2);
427typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
428typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
429struct _xmlRelaxNGTypeLibrary {
430 const xmlChar *namespace; /* the datatypeLibrary value */
431 void *data; /* data needed for the library */
432 xmlRelaxNGTypeHave have; /* the export function */
433 xmlRelaxNGTypeCheck check; /* the checking function */
434 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000435 xmlRelaxNGFacetCheck facet; /* the facet check function */
436 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000437};
438
439/************************************************************************
440 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000441 * Allocation functions *
442 * *
443 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000444static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
445static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000446static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000447static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000448static int xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000449
450/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000451 * xmlRelaxNGFreeDocument:
452 * @docu: a document structure
453 *
454 * Deallocate a RelaxNG document structure.
455 */
456static void
457xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
458{
459 if (docu == NULL)
460 return;
461
462 if (docu->href != NULL)
463 xmlFree(docu->href);
464 if (docu->doc != NULL)
465 xmlFreeDoc(docu->doc);
466 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000467 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000468 xmlFree(docu);
469}
470
471/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000472 * xmlRelaxNGFreeDocumentList:
473 * @docu: a list of document structure
474 *
475 * Deallocate a RelaxNG document structures.
476 */
477static void
478xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
479{
480 xmlRelaxNGDocumentPtr next;
481 while (docu != NULL) {
482 next = docu->next;
483 xmlRelaxNGFreeDocument(docu);
484 docu = next;
485 }
486}
487
488/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000489 * xmlRelaxNGFreeInclude:
490 * @incl: a include structure
491 *
492 * Deallocate a RelaxNG include structure.
493 */
494static void
495xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
496{
497 if (incl == NULL)
498 return;
499
500 if (incl->href != NULL)
501 xmlFree(incl->href);
502 if (incl->doc != NULL)
503 xmlFreeDoc(incl->doc);
504 if (incl->schema != NULL)
505 xmlRelaxNGFree(incl->schema);
506 xmlFree(incl);
507}
508
509/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000510 * xmlRelaxNGFreeIncludeList:
511 * @incl: a include structure list
512 *
513 * Deallocate a RelaxNG include structure.
514 */
515static void
516xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
517{
518 xmlRelaxNGIncludePtr next;
519 while (incl != NULL) {
520 next = incl->next;
521 xmlRelaxNGFreeInclude(incl);
522 incl = next;
523 }
524}
525
526/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000527 * xmlRelaxNGNewRelaxNG:
528 * @ctxt: a Relax-NG validation context (optional)
529 *
530 * Allocate a new RelaxNG structure.
531 *
532 * Returns the newly allocated structure or NULL in case or error
533 */
534static xmlRelaxNGPtr
535xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
536{
537 xmlRelaxNGPtr ret;
538
539 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
540 if (ret == NULL) {
541 if ((ctxt != NULL) && (ctxt->error != NULL))
542 ctxt->error(ctxt->userData, "Out of memory\n");
543 ctxt->nbErrors++;
544 return (NULL);
545 }
546 memset(ret, 0, sizeof(xmlRelaxNG));
547
548 return (ret);
549}
550
551/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000552 * xmlRelaxNGFreeInnerSchema:
553 * @schema: a schema structure
554 *
555 * Deallocate a RelaxNG schema structure.
556 */
557static void
558xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
559{
560 if (schema == NULL)
561 return;
562
563 if (schema->doc != NULL)
564 xmlFreeDoc(schema->doc);
565 if (schema->defTab != NULL) {
566 int i;
567
568 for (i = 0;i < schema->defNr;i++)
569 xmlRelaxNGFreeDefine(schema->defTab[i]);
570 xmlFree(schema->defTab);
571 }
572
573 xmlFree(schema);
574}
575
576/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000577 * xmlRelaxNGFree:
578 * @schema: a schema structure
579 *
580 * Deallocate a RelaxNG structure.
581 */
582void
583xmlRelaxNGFree(xmlRelaxNGPtr schema)
584{
585 if (schema == NULL)
586 return;
587
Daniel Veillard6eadf632003-01-23 18:29:16 +0000588 if (schema->topgrammar != NULL)
589 xmlRelaxNGFreeGrammar(schema->topgrammar);
590 if (schema->doc != NULL)
591 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000592 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000593 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000594 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000595 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000596 if (schema->defTab != NULL) {
597 int i;
598
599 for (i = 0;i < schema->defNr;i++)
600 xmlRelaxNGFreeDefine(schema->defTab[i]);
601 xmlFree(schema->defTab);
602 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000603
604 xmlFree(schema);
605}
606
607/**
608 * xmlRelaxNGNewGrammar:
609 * @ctxt: a Relax-NG validation context (optional)
610 *
611 * Allocate a new RelaxNG grammar.
612 *
613 * Returns the newly allocated structure or NULL in case or error
614 */
615static xmlRelaxNGGrammarPtr
616xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
617{
618 xmlRelaxNGGrammarPtr ret;
619
620 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
621 if (ret == NULL) {
622 if ((ctxt != NULL) && (ctxt->error != NULL))
623 ctxt->error(ctxt->userData, "Out of memory\n");
624 ctxt->nbErrors++;
625 return (NULL);
626 }
627 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
628
629 return (ret);
630}
631
632/**
633 * xmlRelaxNGFreeGrammar:
634 * @grammar: a grammar structure
635 *
636 * Deallocate a RelaxNG grammar structure.
637 */
638static void
639xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
640{
641 if (grammar == NULL)
642 return;
643
Daniel Veillardc482e262003-02-26 14:48:48 +0000644 if (grammar->children != NULL) {
645 xmlRelaxNGFreeGrammar(grammar->children);
646 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000647 if (grammar->next != NULL) {
648 xmlRelaxNGFreeGrammar(grammar->next);
649 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000650 if (grammar->refs != NULL) {
651 xmlHashFree(grammar->refs, NULL);
652 }
653 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000654 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000655 }
656
657 xmlFree(grammar);
658}
659
660/**
661 * xmlRelaxNGNewDefine:
662 * @ctxt: a Relax-NG validation context
663 * @node: the node in the input document.
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000664 * @type: the define type
Daniel Veillard6eadf632003-01-23 18:29:16 +0000665 *
666 * Allocate a new RelaxNG define.
667 *
668 * Returns the newly allocated structure or NULL in case or error
669 */
670static xmlRelaxNGDefinePtr
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000671xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
672 xmlRelaxNGType type)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000673{
674 xmlRelaxNGDefinePtr ret;
675
Daniel Veillard419a7682003-02-03 23:22:49 +0000676 if (ctxt->defMax == 0) {
677 ctxt->defMax = 16;
678 ctxt->defNr = 0;
679 ctxt->defTab = (xmlRelaxNGDefinePtr *)
680 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
681 if (ctxt->defTab == NULL) {
682 if ((ctxt != NULL) && (ctxt->error != NULL))
683 ctxt->error(ctxt->userData, "Out of memory\n");
684 ctxt->nbErrors++;
685 return (NULL);
686 }
687 } else if (ctxt->defMax <= ctxt->defNr) {
688 xmlRelaxNGDefinePtr *tmp;
689 ctxt->defMax *= 2;
690 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
691 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
692 if (tmp == NULL) {
693 if ((ctxt != NULL) && (ctxt->error != NULL))
694 ctxt->error(ctxt->userData, "Out of memory\n");
695 ctxt->nbErrors++;
696 return (NULL);
697 }
698 ctxt->defTab = tmp;
699 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000700 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
701 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000702 if ((ctxt != NULL) && (ctxt->error != NULL))
703 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000704 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000705 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000706 }
707 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000708 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000709 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000710 ret->depth = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000711 ret->type = type;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000712 return (ret);
713}
714
715/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000716 * xmlRelaxNGFreePartition:
717 * @partitions: a partition set structure
718 *
719 * Deallocate RelaxNG partition set structures.
720 */
721static void
722xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
723 xmlRelaxNGInterleaveGroupPtr group;
724 int j;
725
726 if (partitions != NULL) {
727 if (partitions->groups != NULL) {
728 for (j = 0;j < partitions->nbgroups;j++) {
729 group = partitions->groups[j];
730 if (group != NULL) {
731 if (group->defs != NULL)
732 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000733 if (group->attrs != NULL)
734 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000735 xmlFree(group);
736 }
737 }
738 xmlFree(partitions->groups);
739 }
740 xmlFree(partitions);
741 }
742}
743/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000744 * xmlRelaxNGFreeDefine:
745 * @define: a define structure
746 *
747 * Deallocate a RelaxNG define structure.
748 */
749static void
750xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
751{
752 if (define == NULL)
753 return;
754
Daniel Veillard419a7682003-02-03 23:22:49 +0000755 if ((define->data != NULL) &&
756 (define->type == XML_RELAXNG_INTERLEAVE))
757 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000758 if (define->name != NULL)
759 xmlFree(define->name);
760 if (define->ns != NULL)
761 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000762 if (define->value != NULL)
763 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000764 xmlFree(define);
765}
766
767/**
768 * xmlRelaxNGNewValidState:
769 * @ctxt: a Relax-NG validation context
770 * @node: the current node or NULL for the document
771 *
772 * Allocate a new RelaxNG validation state
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000773 * TODO: keep a pool in the ctxt
Daniel Veillard6eadf632003-01-23 18:29:16 +0000774 *
775 * Returns the newly allocated structure or NULL in case or error
776 */
777static xmlRelaxNGValidStatePtr
778xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
779{
780 xmlRelaxNGValidStatePtr ret;
781 xmlAttrPtr attr;
782 xmlAttrPtr attrs[MAX_ATTR];
783 int nbAttrs = 0;
784 xmlNodePtr root = NULL;
785
786 if (node == NULL) {
787 root = xmlDocGetRootElement(ctxt->doc);
788 if (root == NULL)
789 return(NULL);
790 } else {
791 attr = node->properties;
792 while (attr != NULL) {
793 if (nbAttrs < MAX_ATTR)
794 attrs[nbAttrs++] = attr;
795 else
796 nbAttrs++;
797 attr = attr->next;
798 }
799 }
800
801 if (nbAttrs < MAX_ATTR)
802 attrs[nbAttrs] = NULL;
803 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
804 nbAttrs * sizeof(xmlAttrPtr));
805 if (ret == NULL) {
806 if ((ctxt != NULL) && (ctxt->error != NULL))
807 ctxt->error(ctxt->userData, "Out of memory\n");
808 return (NULL);
809 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000810 ret->value = NULL;
811 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000812 if (node == NULL) {
813 ret->node = (xmlNodePtr) ctxt->doc;
814 ret->seq = root;
815 ret->nbAttrs = 0;
816 } else {
817 ret->node = node;
818 ret->seq = node->children;
819 ret->nbAttrs = nbAttrs;
820 if (nbAttrs > 0) {
821 if (nbAttrs < MAX_ATTR) {
822 memcpy(&(ret->attrs[0]), attrs,
823 sizeof(xmlAttrPtr) * (nbAttrs + 1));
824 } else {
825 attr = node->properties;
826 nbAttrs = 0;
827 while (attr != NULL) {
828 ret->attrs[nbAttrs++] = attr;
829 attr = attr->next;
830 }
831 ret->attrs[nbAttrs] = NULL;
832 }
833 }
834 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000835 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000836 return (ret);
837}
838
839/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000840 * xmlRelaxNGFreeValidState:
841 * @state: a validation state structure
842 *
843 * Deallocate a RelaxNG validation state structure.
844 */
845static void
846xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
847{
848 if (state == NULL)
849 return;
850
851 xmlFree(state);
852}
853
854/************************************************************************
855 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000856 * Document functions *
857 * *
858 ************************************************************************/
859static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
860 xmlDocPtr doc);
861
862/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000863 * xmlRelaxNGIncludePush:
864 * @ctxt: the parser context
865 * @value: the element doc
866 *
867 * Pushes a new include on top of the include stack
868 *
869 * Returns 0 in case of error, the index in the stack otherwise
870 */
871static int
872xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
873 xmlRelaxNGIncludePtr value)
874{
875 if (ctxt->incTab == NULL) {
876 ctxt->incMax = 4;
877 ctxt->incNr = 0;
878 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
879 ctxt->incMax * sizeof(ctxt->incTab[0]));
880 if (ctxt->incTab == NULL) {
881 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
882 return (0);
883 }
884 }
885 if (ctxt->incNr >= ctxt->incMax) {
886 ctxt->incMax *= 2;
887 ctxt->incTab =
888 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
889 ctxt->incMax *
890 sizeof(ctxt->incTab[0]));
891 if (ctxt->incTab == NULL) {
892 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
893 return (0);
894 }
895 }
896 ctxt->incTab[ctxt->incNr] = value;
897 ctxt->inc = value;
898 return (ctxt->incNr++);
899}
900
901/**
902 * xmlRelaxNGIncludePop:
903 * @ctxt: the parser context
904 *
905 * Pops the top include from the include stack
906 *
907 * Returns the include just removed
908 */
909static xmlRelaxNGIncludePtr
910xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
911{
912 xmlRelaxNGIncludePtr ret;
913
914 if (ctxt->incNr <= 0)
915 return (0);
916 ctxt->incNr--;
917 if (ctxt->incNr > 0)
918 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
919 else
920 ctxt->inc = NULL;
921 ret = ctxt->incTab[ctxt->incNr];
922 ctxt->incTab[ctxt->incNr] = 0;
923 return (ret);
924}
925
926/**
Daniel Veillard5add8682003-03-10 13:13:58 +0000927 * xmlRelaxNGRemoveRedefine:
928 * @ctxt: the parser context
929 * @URL: the normalized URL
930 * @target: the included target
931 * @name: the define name to eliminate
932 *
933 * Applies the elimination algorithm of 4.7
934 *
935 * Returns 0 in case of error, 1 in case of success.
936 */
937static int
938xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
939 const xmlChar *URL ATTRIBUTE_UNUSED,
940 xmlNodePtr target, const xmlChar *name) {
941 int found = 0;
942 xmlNodePtr tmp, tmp2;
943 xmlChar *name2;
944
945#ifdef DEBUG_INCLUDE
946 xmlGenericError(xmlGenericErrorContext,
947 "Elimination of <include> %s from %s\n", name, URL);
948#endif
949 tmp = target;
950 while (tmp != NULL) {
951 tmp2 = tmp->next;
952 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
953 found = 1;
954 xmlUnlinkNode(tmp);
955 xmlFreeNode(tmp);
956 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
957 name2 = xmlGetProp(tmp, BAD_CAST "name");
958 xmlRelaxNGNormExtSpace(name2);
959 if (name2 != NULL) {
960 if (xmlStrEqual(name, name2)) {
961 found = 1;
962 xmlUnlinkNode(tmp);
963 xmlFreeNode(tmp);
964 }
965 xmlFree(name2);
966 }
967 } else if (IS_RELAXNG(tmp, "include")) {
968 xmlChar *href = NULL;
969 xmlRelaxNGDocumentPtr inc = tmp->_private;
970
971 if ((inc != NULL) && (inc->doc != NULL) &&
972 (inc->doc->children != NULL)) {
973
974 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
975#ifdef DEBUG_INCLUDE
976 href = xmlGetProp(tmp, BAD_CAST "href");
977#endif
978 if (xmlRelaxNGRemoveRedefine(ctxt, href,
979 inc->doc->children->children, name) == 1) {
980 found = 1;
981 }
982 if (href != NULL)
983 xmlFree(href);
984 }
985 }
986 }
987 tmp = tmp2;
988 }
989 return(found);
990}
991
992/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000993 * xmlRelaxNGLoadInclude:
994 * @ctxt: the parser context
995 * @URL: the normalized URL
996 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +0000997 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000998 *
999 * First lookup if the document is already loaded into the parser context,
1000 * check against recursion. If not found the resource is loaded and
1001 * the content is preprocessed before being returned back to the caller.
1002 *
1003 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1004 */
1005static xmlRelaxNGIncludePtr
1006xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001007 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001008 xmlRelaxNGIncludePtr ret = NULL;
1009 xmlDocPtr doc;
1010 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001011 xmlNodePtr root, cur;
1012
1013#ifdef DEBUG_INCLUDE
1014 xmlGenericError(xmlGenericErrorContext,
1015 "xmlRelaxNGLoadInclude(%s)\n", URL);
1016#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001017
1018 /*
1019 * check against recursion in the stack
1020 */
1021 for (i = 0;i < ctxt->incNr;i++) {
1022 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1023 if (ctxt->error != NULL)
1024 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001025 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001026 URL);
1027 ctxt->nbErrors++;
1028 return(NULL);
1029 }
1030 }
1031
1032 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001033 * load the document
1034 */
1035 doc = xmlParseFile((const char *) URL);
1036 if (doc == NULL) {
1037 if (ctxt->error != NULL)
1038 ctxt->error(ctxt->userData,
1039 "xmlRelaxNG: could not load %s\n", URL);
1040 ctxt->nbErrors++;
1041 return (NULL);
1042 }
1043
Daniel Veillard5add8682003-03-10 13:13:58 +00001044#ifdef DEBUG_INCLUDE
1045 xmlGenericError(xmlGenericErrorContext,
1046 "Parsed %s Okay\n", URL);
1047#endif
1048
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001049 /*
1050 * Allocate the document structures and register it first.
1051 */
1052 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1053 if (ret == NULL) {
1054 if (ctxt->error != NULL)
1055 ctxt->error(ctxt->userData,
1056 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1057 ctxt->nbErrors++;
1058 xmlFreeDoc(doc);
1059 return (NULL);
1060 }
1061 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1062 ret->doc = doc;
1063 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001064 ret->next = ctxt->includes;
1065 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001066
1067 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001068 * transmit the ns if needed
1069 */
1070 if (ns != NULL) {
1071 root = xmlDocGetRootElement(doc);
1072 if (root != NULL) {
1073 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1074 xmlSetProp(root, BAD_CAST"ns", ns);
1075 }
1076 }
1077 }
1078
1079 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001080 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001081 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001082 xmlRelaxNGIncludePush(ctxt, ret);
1083
1084 /*
1085 * Some preprocessing of the document content, this include recursing
1086 * in the include stack.
1087 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001088#ifdef DEBUG_INCLUDE
1089 xmlGenericError(xmlGenericErrorContext,
1090 "cleanup of %s\n", URL);
1091#endif
1092
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001093 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1094 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001095 ctxt->inc = NULL;
1096 return(NULL);
1097 }
1098
1099 /*
1100 * Pop up the include from the stack
1101 */
1102 xmlRelaxNGIncludePop(ctxt);
1103
Daniel Veillard5add8682003-03-10 13:13:58 +00001104#ifdef DEBUG_INCLUDE
1105 xmlGenericError(xmlGenericErrorContext,
1106 "Checking of %s\n", URL);
1107#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001108 /*
1109 * Check that the top element is a grammar
1110 */
1111 root = xmlDocGetRootElement(doc);
1112 if (root == NULL) {
1113 if (ctxt->error != NULL)
1114 ctxt->error(ctxt->userData,
1115 "xmlRelaxNG: included document is empty %s\n", URL);
1116 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001117 return (NULL);
1118 }
1119 if (!IS_RELAXNG(root, "grammar")) {
1120 if (ctxt->error != NULL)
1121 ctxt->error(ctxt->userData,
1122 "xmlRelaxNG: included document %s root is not a grammar\n",
1123 URL);
1124 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001125 return (NULL);
1126 }
1127
1128 /*
1129 * Elimination of redefined rules in the include.
1130 */
1131 cur = node->children;
1132 while (cur != NULL) {
1133 if (IS_RELAXNG(cur, "start")) {
1134 int found = 0;
1135
Daniel Veillard5add8682003-03-10 13:13:58 +00001136 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001137 if (!found) {
1138 if (ctxt->error != NULL)
1139 ctxt->error(ctxt->userData,
1140 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1141 URL);
1142 ctxt->nbErrors++;
1143 }
1144 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001145 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001146
1147 name = xmlGetProp(cur, BAD_CAST "name");
1148 if (name == NULL) {
1149 if (ctxt->error != NULL)
1150 ctxt->error(ctxt->userData,
1151 "xmlRelaxNG: include %s has define without name\n",
1152 URL);
1153 ctxt->nbErrors++;
1154 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001155 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001156
Daniel Veillardd2298792003-02-14 16:54:11 +00001157 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001158 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1159 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001160 if (!found) {
1161 if (ctxt->error != NULL)
1162 ctxt->error(ctxt->userData,
1163 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1164 URL, name);
1165 ctxt->nbErrors++;
1166 }
1167 xmlFree(name);
1168 }
1169 }
1170 cur = cur->next;
1171 }
1172
1173
1174 return(ret);
1175}
1176
1177/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001178 * xmlRelaxNGValidErrorPush:
1179 * @ctxt: the validation context
1180 * @err: the error code
1181 * @arg1: the first string argument
1182 * @arg2: the second string argument
1183 *
1184 * Pushes a new error on top of the error stack
1185 *
1186 * Returns 0 in case of error, the index in the stack otherwise
1187 */
1188static int
1189xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1190 const xmlChar *arg1, const xmlChar *arg2)
1191{
1192 xmlRelaxNGValidErrorPtr cur;
1193 if (ctxt->errTab == NULL) {
1194 ctxt->errMax = 8;
1195 ctxt->errNr = 0;
1196 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1197 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1198 if (ctxt->errTab == NULL) {
1199 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1200 return (0);
1201 }
1202 }
1203 if (ctxt->errNr >= ctxt->errMax) {
1204 ctxt->errMax *= 2;
1205 ctxt->errTab =
1206 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1207 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1208 if (ctxt->errTab == NULL) {
1209 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1210 return (0);
1211 }
1212 }
1213 cur = &ctxt->errTab[ctxt->errNr];
1214 cur->err = err;
1215 cur->arg1 = arg1;
1216 cur->arg2 = arg2;
1217 if (ctxt->state != NULL) {
1218 cur->node = ctxt->state->node;
1219 cur->seq = ctxt->state->seq;
1220 } else {
1221 cur->node = NULL;
1222 cur->seq = NULL;
1223 }
1224 ctxt->err = cur;
1225 return (ctxt->errNr++);
1226}
1227
1228/**
1229 * xmlRelaxNGValidErrorPop:
1230 * @ctxt: the validation context
1231 *
1232 * Pops the top error from the error stack
1233 *
1234 * Returns the error just removed
1235 */
1236static xmlRelaxNGValidErrorPtr
1237xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1238{
1239 xmlRelaxNGValidErrorPtr ret;
1240
1241 if (ctxt->errNr <= 0)
1242 return (NULL);
1243 ctxt->errNr--;
1244 if (ctxt->errNr > 0)
1245 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1246 else
1247 ctxt->err = NULL;
1248 ret = &ctxt->errTab[ctxt->errNr];
1249 return (ret);
1250}
1251
1252
1253/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001254 * xmlRelaxNGDocumentPush:
1255 * @ctxt: the parser context
1256 * @value: the element doc
1257 *
1258 * Pushes a new doc on top of the doc stack
1259 *
1260 * Returns 0 in case of error, the index in the stack otherwise
1261 */
1262static int
1263xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1264 xmlRelaxNGDocumentPtr value)
1265{
1266 if (ctxt->docTab == NULL) {
1267 ctxt->docMax = 4;
1268 ctxt->docNr = 0;
1269 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1270 ctxt->docMax * sizeof(ctxt->docTab[0]));
1271 if (ctxt->docTab == NULL) {
1272 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1273 return (0);
1274 }
1275 }
1276 if (ctxt->docNr >= ctxt->docMax) {
1277 ctxt->docMax *= 2;
1278 ctxt->docTab =
1279 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1280 ctxt->docMax *
1281 sizeof(ctxt->docTab[0]));
1282 if (ctxt->docTab == NULL) {
1283 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1284 return (0);
1285 }
1286 }
1287 ctxt->docTab[ctxt->docNr] = value;
1288 ctxt->doc = value;
1289 return (ctxt->docNr++);
1290}
1291
1292/**
1293 * xmlRelaxNGDocumentPop:
1294 * @ctxt: the parser context
1295 *
1296 * Pops the top doc from the doc stack
1297 *
1298 * Returns the doc just removed
1299 */
1300static xmlRelaxNGDocumentPtr
1301xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1302{
1303 xmlRelaxNGDocumentPtr ret;
1304
1305 if (ctxt->docNr <= 0)
1306 return (0);
1307 ctxt->docNr--;
1308 if (ctxt->docNr > 0)
1309 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1310 else
1311 ctxt->doc = NULL;
1312 ret = ctxt->docTab[ctxt->docNr];
1313 ctxt->docTab[ctxt->docNr] = 0;
1314 return (ret);
1315}
1316
1317/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001318 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001319 * @ctxt: the parser context
1320 * @URL: the normalized URL
1321 * @ns: the inherited ns if any
1322 *
1323 * First lookup if the document is already loaded into the parser context,
1324 * check against recursion. If not found the resource is loaded and
1325 * the content is preprocessed before being returned back to the caller.
1326 *
1327 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1328 */
1329static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001330xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001331 const xmlChar *ns) {
1332 xmlRelaxNGDocumentPtr ret = NULL;
1333 xmlDocPtr doc;
1334 xmlNodePtr root;
1335 int i;
1336
1337 /*
1338 * check against recursion in the stack
1339 */
1340 for (i = 0;i < ctxt->docNr;i++) {
1341 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1342 if (ctxt->error != NULL)
1343 ctxt->error(ctxt->userData,
1344 "Detected an externalRef recursion for %s\n",
1345 URL);
1346 ctxt->nbErrors++;
1347 return(NULL);
1348 }
1349 }
1350
1351 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001352 * load the document
1353 */
1354 doc = xmlParseFile((const char *) URL);
1355 if (doc == NULL) {
1356 if (ctxt->error != NULL)
1357 ctxt->error(ctxt->userData,
1358 "xmlRelaxNG: could not load %s\n", URL);
1359 ctxt->nbErrors++;
1360 return (NULL);
1361 }
1362
1363 /*
1364 * Allocate the document structures and register it first.
1365 */
1366 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1367 if (ret == NULL) {
1368 if (ctxt->error != NULL)
1369 ctxt->error(ctxt->userData,
1370 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1371 ctxt->nbErrors++;
1372 xmlFreeDoc(doc);
1373 return (NULL);
1374 }
1375 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1376 ret->doc = doc;
1377 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001378 ret->next = ctxt->documents;
1379 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001380
1381 /*
1382 * transmit the ns if needed
1383 */
1384 if (ns != NULL) {
1385 root = xmlDocGetRootElement(doc);
1386 if (root != NULL) {
1387 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1388 xmlSetProp(root, BAD_CAST"ns", ns);
1389 }
1390 }
1391 }
1392
1393 /*
1394 * push it on the stack and register it in the hash table
1395 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001396 xmlRelaxNGDocumentPush(ctxt, ret);
1397
1398 /*
1399 * Some preprocessing of the document content
1400 */
1401 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1402 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001403 ctxt->doc = NULL;
1404 return(NULL);
1405 }
1406
1407 xmlRelaxNGDocumentPop(ctxt);
1408
1409 return(ret);
1410}
1411
1412/************************************************************************
1413 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001414 * Error functions *
1415 * *
1416 ************************************************************************/
1417
Daniel Veillard42f12e92003-03-07 18:32:59 +00001418#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL);
1419#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL);
1420#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001421
Daniel Veillard231d7912003-02-09 14:22:17 +00001422static const char *
1423xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1424 if (def == NULL)
1425 return("none");
1426 switch(def->type) {
1427 case XML_RELAXNG_EMPTY: return("empty");
1428 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1429 case XML_RELAXNG_EXCEPT: return("except");
1430 case XML_RELAXNG_TEXT: return("text");
1431 case XML_RELAXNG_ELEMENT: return("element");
1432 case XML_RELAXNG_DATATYPE: return("datatype");
1433 case XML_RELAXNG_VALUE: return("value");
1434 case XML_RELAXNG_LIST: return("list");
1435 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1436 case XML_RELAXNG_DEF: return("def");
1437 case XML_RELAXNG_REF: return("ref");
1438 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1439 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillard231d7912003-02-09 14:22:17 +00001440 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1441 case XML_RELAXNG_CHOICE: return("choice");
1442 case XML_RELAXNG_GROUP: return("group");
1443 case XML_RELAXNG_INTERLEAVE: return("interleave");
1444 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001445#if 0
1446 case XML_RELAXNG_NOOP: return("noop");
1447#endif
1448 case XML_RELAXNG_PARAM: return("param");
1449 case XML_RELAXNG_AFTER: return("after");
Daniel Veillard231d7912003-02-09 14:22:17 +00001450 }
1451 return("unknown");
1452}
Daniel Veillardd2298792003-02-14 16:54:11 +00001453
Daniel Veillard6eadf632003-01-23 18:29:16 +00001454/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001455 * xmlRelaxNGGetErrorString:
1456 * @err: the error code
1457 * @arg1: the first string argument
1458 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001459 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001460 * computes a formatted error string for the given error code and args
1461 *
1462 * Returns the error string, it must be deallocated by the caller
1463 */
1464static xmlChar *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001465xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
1466 const xmlChar * arg2)
1467{
Daniel Veillard42f12e92003-03-07 18:32:59 +00001468 char msg[1000];
1469
1470 if (arg1 == NULL)
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001471 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001472 if (arg2 == NULL)
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001473 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001474
1475 msg[0] = 0;
1476 switch (err) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001477 case XML_RELAXNG_OK:
1478 return (NULL);
1479 case XML_RELAXNG_ERR_MEMORY:
1480 return (xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001481 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001482 snprintf(msg, 1000, "failed to validate type %s", arg1);
1483 break;
1484 case XML_RELAXNG_ERR_TYPEVAL:
1485 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1,
1486 arg2);
1487 break;
1488 case XML_RELAXNG_ERR_TYPECMP:
1489 snprintf(msg, 1000, "failed to compare type %s", arg1);
1490 break;
1491 case XML_RELAXNG_ERR_NOSTATE:
1492 return (xmlCharStrdup("Internal error: no state"));
1493 case XML_RELAXNG_ERR_NODEFINE:
1494 return (xmlCharStrdup("Internal error: no define"));
1495 case XML_RELAXNG_ERR_LISTEXTRA:
1496 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1497 break;
1498 case XML_RELAXNG_ERR_LISTEMPTY:
1499 return (xmlCharStrdup("List is empty"));
1500 case XML_RELAXNG_ERR_INTERNODATA:
1501 return (xmlCharStrdup
1502 ("Internal: interleave block has no data"));
1503 case XML_RELAXNG_ERR_INTERSEQ:
1504 return (xmlCharStrdup("Invalid sequence in interleave"));
1505 case XML_RELAXNG_ERR_INTEREXTRA:
1506 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1507 break;
1508 case XML_RELAXNG_ERR_ELEMNAME:
1509 snprintf(msg, 1000, "Expecting element %s, got %s", arg1,
1510 arg2);
1511 break;
1512 case XML_RELAXNG_ERR_ELEMNONS:
1513 snprintf(msg, 1000, "Expecting a namespace for element %s",
1514 arg1);
1515 break;
1516 case XML_RELAXNG_ERR_ELEMWRONGNS:
1517 snprintf(msg, 1000,
1518 "Element %s has wrong namespace: expecting %s", arg1,
1519 arg2);
1520 break;
1521 case XML_RELAXNG_ERR_ELEMEXTRANS:
1522 snprintf(msg, 1000, "Expecting no namespace for element %s",
1523 arg1);
1524 break;
1525 case XML_RELAXNG_ERR_ATTRNAME:
1526 snprintf(msg, 1000, "Expecting attribute %s, got %s", arg1,
1527 arg2);
1528 break;
1529 case XML_RELAXNG_ERR_ATTRNONS:
1530 snprintf(msg, 1000, "Expecting a namespace for attribute %s",
1531 arg1);
1532 break;
1533 case XML_RELAXNG_ERR_ATTRWRONGNS:
1534 snprintf(msg, 1000,
1535 "Attribute %s has wrong namespace: expecting %s",
1536 arg1, arg2);
1537 break;
1538 case XML_RELAXNG_ERR_ATTREXTRANS:
1539 snprintf(msg, 1000, "Expecting no namespace for attribute %s",
1540 arg1);
1541 break;
1542 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1543 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1544 break;
1545 case XML_RELAXNG_ERR_NOELEM:
1546 snprintf(msg, 1000, "Expecting an element %s, got nothing",
1547 arg1);
1548 break;
1549 case XML_RELAXNG_ERR_NOTELEM:
1550 return (xmlCharStrdup("Expecting an element got text"));
1551 case XML_RELAXNG_ERR_ATTRVALID:
1552 snprintf(msg, 1000, "Element %s failed to validate attributes",
1553 arg1);
1554 break;
1555 case XML_RELAXNG_ERR_CONTENTVALID:
1556 snprintf(msg, 1000, "Element %s failed to validate content",
1557 arg1);
1558 break;
1559 case XML_RELAXNG_ERR_EXTRACONTENT:
1560 snprintf(msg, 1000, "Element %s has extra content: %s",
1561 arg1, arg2);
1562 break;
1563 case XML_RELAXNG_ERR_INVALIDATTR:
1564 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1565 arg1, arg2);
1566 break;
1567 case XML_RELAXNG_ERR_DATAELEM:
1568 snprintf(msg, 1000, "Datatype element %s has child elements",
1569 arg1);
1570 break;
1571 case XML_RELAXNG_ERR_VALELEM:
1572 snprintf(msg, 1000, "Value element %s has child elements",
1573 arg1);
1574 break;
1575 case XML_RELAXNG_ERR_LISTELEM:
1576 snprintf(msg, 1000, "List element %s has child elements",
1577 arg1);
1578 break;
1579 case XML_RELAXNG_ERR_DATATYPE:
1580 snprintf(msg, 1000, "Error validating datatype %s", arg1);
1581 break;
1582 case XML_RELAXNG_ERR_VALUE:
1583 snprintf(msg, 1000, "Error validating value %s", arg1);
1584 break;
1585 case XML_RELAXNG_ERR_LIST:
1586 return (xmlCharStrdup("Error validating list"));
1587 case XML_RELAXNG_ERR_NOGRAMMAR:
1588 return (xmlCharStrdup("No top grammar defined"));
1589 case XML_RELAXNG_ERR_EXTRADATA:
1590 return (xmlCharStrdup("Extra data in the document"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001591 }
1592 if (msg[0] == 0) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001593 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001594 }
1595 msg[1000] = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001596 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001597}
1598
1599/**
1600 * xmlRelaxNGValidErrorContext:
1601 * @ctxt: the validation context
1602 * @node: the node
1603 * @child: the node child generating the problem.
1604 *
1605 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001606 */
1607static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001608xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1609 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001610{
1611 int line = 0;
1612 const xmlChar *file = NULL;
1613 const xmlChar *name = NULL;
1614 const char *type = "error";
1615
1616 if ((ctxt == NULL) || (ctxt->error == NULL))
1617 return;
1618
1619 if (child != NULL)
1620 node = child;
1621
1622 if (node != NULL) {
1623 if ((node->type == XML_DOCUMENT_NODE) ||
1624 (node->type == XML_HTML_DOCUMENT_NODE)) {
1625 xmlDocPtr doc = (xmlDocPtr) node;
1626
1627 file = doc->URL;
1628 } else {
1629 /*
1630 * Try to find contextual informations to report
1631 */
1632 if (node->type == XML_ELEMENT_NODE) {
1633 line = (int) node->content;
1634 } else if ((node->prev != NULL) &&
1635 (node->prev->type == XML_ELEMENT_NODE)) {
1636 line = (int) node->prev->content;
1637 } else if ((node->parent != NULL) &&
1638 (node->parent->type == XML_ELEMENT_NODE)) {
1639 line = (int) node->parent->content;
1640 }
1641 if ((node->doc != NULL) && (node->doc->URL != NULL))
1642 file = node->doc->URL;
1643 if (node->name != NULL)
1644 name = node->name;
1645 }
1646 }
1647
Daniel Veillard42f12e92003-03-07 18:32:59 +00001648 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001649
1650 if ((file != NULL) && (line != 0) && (name != NULL))
1651 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1652 type, file, line, name);
1653 else if ((file != NULL) && (name != NULL))
1654 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1655 type, file, name);
1656 else if ((file != NULL) && (line != 0))
1657 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1658 else if (file != NULL)
1659 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1660 else if (name != NULL)
1661 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1662 else
1663 ctxt->error(ctxt->userData, "%s\n", type);
1664}
Daniel Veillard42f12e92003-03-07 18:32:59 +00001665
1666/**
1667 * xmlRelaxNGShowValidError:
1668 * @ctxt: the validation context
1669 * @err: the error number
1670 * @node: the node
1671 * @child: the node child generating the problem.
1672 * @arg1: the first argument
1673 * @arg2: the second argument
1674 *
1675 * Show a validation error.
1676 */
1677static void
1678xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1679 xmlNodePtr node, xmlNodePtr child,
1680 const xmlChar *arg1, const xmlChar *arg2)
1681{
1682 xmlChar *msg;
1683
1684 if (ctxt->error == NULL)
1685 return;
1686
1687 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
1688 if (msg == NULL)
1689 return;
1690
1691 xmlRelaxNGValidErrorContext(ctxt, node, child);
1692 ctxt->error(ctxt->userData, "%s\n", msg);
1693 xmlFree(msg);
1694}
1695
1696/**
1697 * xmlRelaxNGDumpValidError:
1698 * @ctxt: the validation context
1699 *
1700 * Show all validation error over a given index.
1701 */
1702static void
1703xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
1704 int i;
1705 xmlRelaxNGValidErrorPtr err;
1706
1707 for (i = 0;i < ctxt->errNr;i++) {
1708 err = &ctxt->errTab[i];
1709 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
1710 err->arg1, err->arg2);
1711 }
1712 ctxt->errNr = 0;
1713}
1714/**
1715 * xmlRelaxNGAddValidError:
1716 * @ctxt: the validation context
1717 * @err: the error number
1718 * @arg1: the first argument
1719 * @arg2: the second argument
1720 *
1721 * Register a validation error, either generating it if it's sure
1722 * or stacking it for later handling if unsure.
1723 */
1724static void
1725xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1726 const xmlChar *arg1, const xmlChar *arg2)
1727{
1728 if ((ctxt == NULL) || (ctxt->error == NULL))
1729 return;
1730
1731 /*
1732 * generate the error directly
1733 */
1734 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
1735 xmlNodePtr node, seq;
1736 /*
1737 * Flush first any stacked error which might be the
1738 * real cause of the problem.
1739 */
1740 if (ctxt->errNr != 0)
1741 xmlRelaxNGDumpValidError(ctxt);
1742 if (ctxt->state != NULL) {
1743 node = ctxt->state->node;
1744 seq = ctxt->state->seq;
1745 } else {
1746 node = seq = NULL;
1747 }
1748 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
1749 }
1750 /*
1751 * Stack the error for later processing if needed
1752 */
1753 else {
1754 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2);
1755 }
1756}
1757
Daniel Veillard6eadf632003-01-23 18:29:16 +00001758
1759/************************************************************************
1760 * *
1761 * Type library hooks *
1762 * *
1763 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00001764static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1765 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001766
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001767/**
1768 * xmlRelaxNGSchemaTypeHave:
1769 * @data: data needed for the library
1770 * @type: the type name
1771 *
1772 * Check if the given type is provided by
1773 * the W3C XMLSchema Datatype library.
1774 *
1775 * Returns 1 if yes, 0 if no and -1 in case of error.
1776 */
1777static int
1778xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001779 const xmlChar *type) {
1780 xmlSchemaTypePtr typ;
1781
1782 if (type == NULL)
1783 return(-1);
1784 typ = xmlSchemaGetPredefinedType(type,
1785 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1786 if (typ == NULL)
1787 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001788 return(1);
1789}
1790
1791/**
1792 * xmlRelaxNGSchemaTypeCheck:
1793 * @data: data needed for the library
1794 * @type: the type name
1795 * @value: the value to check
1796 *
1797 * Check if the given type and value are validated by
1798 * the W3C XMLSchema Datatype library.
1799 *
1800 * Returns 1 if yes, 0 if no and -1 in case of error.
1801 */
1802static int
1803xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001804 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001805 const xmlChar *value,
1806 void **result) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001807 xmlSchemaTypePtr typ;
1808 int ret;
1809
1810 /*
1811 * TODO: the type should be cached ab provided back, interface subject
1812 * to changes.
1813 * TODO: handle facets, may require an additional interface and keep
1814 * the value returned from the validation.
1815 */
1816 if ((type == NULL) || (value == NULL))
1817 return(-1);
1818 typ = xmlSchemaGetPredefinedType(type,
1819 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1820 if (typ == NULL)
1821 return(-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001822 ret = xmlSchemaValidatePredefinedType(typ, value,
1823 (xmlSchemaValPtr *) result);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001824 if (ret == 0)
1825 return(1);
1826 if (ret > 0)
1827 return(0);
1828 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001829}
1830
1831/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001832 * xmlRelaxNGSchemaFacetCheck:
1833 * @data: data needed for the library
1834 * @type: the type name
1835 * @facet: the facet name
1836 * @val: the facet value
1837 * @strval: the string value
1838 * @value: the value to check
1839 *
1840 * Function provided by a type library to check a value facet
1841 *
1842 * Returns 1 if yes, 0 if no and -1 in case of error.
1843 */
1844static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00001845xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001846 const xmlChar *facetname, const xmlChar *val,
1847 const xmlChar *strval, void *value) {
1848 xmlSchemaFacetPtr facet;
1849 xmlSchemaTypePtr typ;
1850 int ret;
1851
1852 if ((type == NULL) || (strval == NULL))
1853 return(-1);
1854 typ = xmlSchemaGetPredefinedType(type,
1855 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1856 if (typ == NULL)
1857 return(-1);
1858
1859 facet = xmlSchemaNewFacet();
1860 if (facet == NULL)
1861 return(-1);
1862
1863 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
1864 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
1865 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
1866 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
1867 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
1868 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
1869 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
1870 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
1871 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
1872 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
1873 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
1874 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
1875 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
1876 facet->type = XML_SCHEMA_FACET_PATTERN;
1877 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
1878 facet->type = XML_SCHEMA_FACET_ENUMERATION;
1879 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
1880 facet->type = XML_SCHEMA_FACET_WHITESPACE;
1881 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
1882 facet->type = XML_SCHEMA_FACET_LENGTH;
1883 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
1884 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
1885 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
1886 facet->type = XML_SCHEMA_FACET_MINLENGTH;
1887 } else {
1888 xmlSchemaFreeFacet(facet);
1889 return(-1);
1890 }
1891 facet->value = xmlStrdup(val);
1892 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
1893 if (ret != 0) {
1894 xmlSchemaFreeFacet(facet);
1895 return(-1);
1896 }
1897 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
1898 xmlSchemaFreeFacet(facet);
1899 if (ret != 0)
1900 return(-1);
1901 return(0);
1902}
1903
1904/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001905 * xmlRelaxNGSchemaTypeCompare:
1906 * @data: data needed for the library
1907 * @type: the type name
1908 * @value1: the first value
1909 * @value2: the second value
1910 *
1911 * Compare two values accordingly a type from the W3C XMLSchema
1912 * Datatype library.
1913 *
1914 * Returns 1 if yes, 0 if no and -1 in case of error.
1915 */
1916static int
1917xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
1918 const xmlChar *type ATTRIBUTE_UNUSED,
1919 const xmlChar *value1 ATTRIBUTE_UNUSED,
1920 const xmlChar *value2 ATTRIBUTE_UNUSED) {
1921 TODO
1922 return(1);
1923}
1924
1925/**
1926 * xmlRelaxNGDefaultTypeHave:
1927 * @data: data needed for the library
1928 * @type: the type name
1929 *
1930 * Check if the given type is provided by
1931 * the default datatype library.
1932 *
1933 * Returns 1 if yes, 0 if no and -1 in case of error.
1934 */
1935static int
1936xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
1937 if (type == NULL)
1938 return(-1);
1939 if (xmlStrEqual(type, BAD_CAST "string"))
1940 return(1);
1941 if (xmlStrEqual(type, BAD_CAST "token"))
1942 return(1);
1943 return(0);
1944}
1945
1946/**
1947 * xmlRelaxNGDefaultTypeCheck:
1948 * @data: data needed for the library
1949 * @type: the type name
1950 * @value: the value to check
1951 *
1952 * Check if the given type and value are validated by
1953 * the default datatype library.
1954 *
1955 * Returns 1 if yes, 0 if no and -1 in case of error.
1956 */
1957static int
1958xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
1959 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001960 const xmlChar *value ATTRIBUTE_UNUSED,
1961 void **result ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00001962 if (value == NULL)
1963 return(-1);
1964 if (xmlStrEqual(type, BAD_CAST "string"))
1965 return(1);
1966 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00001967 return(1);
1968 }
1969
1970 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001971}
1972
1973/**
1974 * xmlRelaxNGDefaultTypeCompare:
1975 * @data: data needed for the library
1976 * @type: the type name
1977 * @value1: the first value
1978 * @value2: the second value
1979 *
1980 * Compare two values accordingly a type from the default
1981 * datatype library.
1982 *
1983 * Returns 1 if yes, 0 if no and -1 in case of error.
1984 */
1985static int
1986xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
1987 const xmlChar *type ATTRIBUTE_UNUSED,
1988 const xmlChar *value1 ATTRIBUTE_UNUSED,
1989 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00001990 int ret = -1;
1991
1992 if (xmlStrEqual(type, BAD_CAST "string")) {
1993 ret = xmlStrEqual(value1, value2);
1994 } else if (xmlStrEqual(type, BAD_CAST "token")) {
1995 if (!xmlStrEqual(value1, value2)) {
1996 xmlChar *nval, *nvalue;
1997
1998 /*
1999 * TODO: trivial optimizations are possible by
2000 * computing at compile-time
2001 */
2002 nval = xmlRelaxNGNormalize(NULL, value1);
2003 nvalue = xmlRelaxNGNormalize(NULL, value2);
2004
Daniel Veillardd4310742003-02-18 21:12:46 +00002005 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002006 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002007 else if (xmlStrEqual(nval, nvalue))
2008 ret = 1;
2009 else
2010 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002011 if (nval != NULL)
2012 xmlFree(nval);
2013 if (nvalue != NULL)
2014 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002015 } else
2016 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002017 }
2018 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002019}
2020
2021static int xmlRelaxNGTypeInitialized = 0;
2022static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2023
2024/**
2025 * xmlRelaxNGFreeTypeLibrary:
2026 * @lib: the type library structure
2027 * @namespace: the URI bound to the library
2028 *
2029 * Free the structure associated to the type library
2030 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002031static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002032xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2033 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2034 if (lib == NULL)
2035 return;
2036 if (lib->namespace != NULL)
2037 xmlFree((xmlChar *)lib->namespace);
2038 xmlFree(lib);
2039}
2040
2041/**
2042 * xmlRelaxNGRegisterTypeLibrary:
2043 * @namespace: the URI bound to the library
2044 * @data: data associated to the library
2045 * @have: the provide function
2046 * @check: the checking function
2047 * @comp: the comparison function
2048 *
2049 * Register a new type library
2050 *
2051 * Returns 0 in case of success and -1 in case of error.
2052 */
2053static int
2054xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2055 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002056 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2057 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002058 xmlRelaxNGTypeLibraryPtr lib;
2059 int ret;
2060
2061 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2062 (check == NULL) || (comp == NULL))
2063 return(-1);
2064 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2065 xmlGenericError(xmlGenericErrorContext,
2066 "Relax-NG types library '%s' already registered\n",
2067 namespace);
2068 return(-1);
2069 }
2070 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2071 if (lib == NULL) {
2072 xmlGenericError(xmlGenericErrorContext,
2073 "Relax-NG types library '%s' malloc() failed\n",
2074 namespace);
2075 return (-1);
2076 }
2077 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2078 lib->namespace = xmlStrdup(namespace);
2079 lib->data = data;
2080 lib->have = have;
2081 lib->comp = comp;
2082 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002083 lib->facet = facet;
2084 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002085 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2086 if (ret < 0) {
2087 xmlGenericError(xmlGenericErrorContext,
2088 "Relax-NG types library failed to register '%s'\n",
2089 namespace);
2090 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2091 return(-1);
2092 }
2093 return(0);
2094}
2095
2096/**
2097 * xmlRelaxNGInitTypes:
2098 *
2099 * Initilize the default type libraries.
2100 *
2101 * Returns 0 in case of success and -1 in case of error.
2102 */
2103static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002104xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002105 if (xmlRelaxNGTypeInitialized != 0)
2106 return(0);
2107 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2108 if (xmlRelaxNGRegisteredTypes == NULL) {
2109 xmlGenericError(xmlGenericErrorContext,
2110 "Failed to allocate sh table for Relax-NG types\n");
2111 return(-1);
2112 }
2113 xmlRelaxNGRegisterTypeLibrary(
2114 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2115 NULL,
2116 xmlRelaxNGSchemaTypeHave,
2117 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002118 xmlRelaxNGSchemaTypeCompare,
2119 xmlRelaxNGSchemaFacetCheck,
2120 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002121 xmlRelaxNGRegisterTypeLibrary(
2122 xmlRelaxNGNs,
2123 NULL,
2124 xmlRelaxNGDefaultTypeHave,
2125 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002126 xmlRelaxNGDefaultTypeCompare,
2127 NULL,
2128 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002129 xmlRelaxNGTypeInitialized = 1;
2130 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002131}
2132
2133/**
2134 * xmlRelaxNGCleanupTypes:
2135 *
2136 * Cleanup the default Schemas type library associated to RelaxNG
2137 */
2138void
2139xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002140 if (xmlRelaxNGTypeInitialized == 0)
2141 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002142 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002143 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2144 xmlRelaxNGFreeTypeLibrary);
2145 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002146}
2147
2148/************************************************************************
2149 * *
2150 * Parsing functions *
2151 * *
2152 ************************************************************************/
2153
2154static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2155 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2156static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2157 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2158static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002159 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002160static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2161 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002162static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2163 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002164static int xmlRelaxNGParseGrammarContent(
2165 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002166static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2167 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2168 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002169static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2170 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002171static int xmlRelaxNGNsNameMatch(xmlRelaxNGValidCtxtPtr ctxt,
2172 xmlRelaxNGDefinePtr define, xmlNodePtr elem, int eora);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002173
2174
2175#define IS_BLANK_NODE(n) \
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002176 ((((n)->type == XML_TEXT_NODE) || \
2177 ((n)->type == XML_CDATA_SECTION_NODE)) && \
2178 (xmlRelaxNGIsBlank((n)->content)))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002179
2180/**
2181 * xmlRelaxNGIsBlank:
2182 * @str: a string
2183 *
2184 * Check if a string is ignorable c.f. 4.2. Whitespace
2185 *
2186 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2187 */
2188static int
2189xmlRelaxNGIsBlank(xmlChar *str) {
2190 if (str == NULL)
2191 return(1);
2192 while (*str != 0) {
2193 if (!(IS_BLANK(*str))) return(0);
2194 str++;
2195 }
2196 return(1);
2197}
2198
Daniel Veillard6eadf632003-01-23 18:29:16 +00002199/**
2200 * xmlRelaxNGGetDataTypeLibrary:
2201 * @ctxt: a Relax-NG parser context
2202 * @node: the current data or value element
2203 *
2204 * Applies algorithm from 4.3. datatypeLibrary attribute
2205 *
2206 * Returns the datatypeLibary value or NULL if not found
2207 */
2208static xmlChar *
2209xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2210 xmlNodePtr node) {
2211 xmlChar *ret, *escape;
2212
Daniel Veillard6eadf632003-01-23 18:29:16 +00002213 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2214 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2215 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002216 if (ret[0] == 0) {
2217 xmlFree(ret);
2218 return(NULL);
2219 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002220 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002221 if (escape == NULL) {
2222 return(ret);
2223 }
2224 xmlFree(ret);
2225 return(escape);
2226 }
2227 }
2228 node = node->parent;
2229 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002230 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2231 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002232 if (ret[0] == 0) {
2233 xmlFree(ret);
2234 return(NULL);
2235 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002236 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2237 if (escape == NULL) {
2238 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002239 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002240 xmlFree(ret);
2241 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002242 }
2243 node = node->parent;
2244 }
2245 return(NULL);
2246}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002247
2248/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002249 * xmlRelaxNGParseValue:
2250 * @ctxt: a Relax-NG parser context
2251 * @node: the data node.
2252 *
2253 * parse the content of a RelaxNG value node.
2254 *
2255 * Returns the definition pointer or NULL in case of error
2256 */
2257static xmlRelaxNGDefinePtr
2258xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2259 xmlRelaxNGDefinePtr def = NULL;
2260 xmlRelaxNGTypeLibraryPtr lib;
2261 xmlChar *type;
2262 xmlChar *library;
2263 int tmp;
2264
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002265 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_VALUE);
Daniel Veillardedc91922003-01-26 00:52:04 +00002266 if (def == NULL)
2267 return(NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00002268
2269 type = xmlGetProp(node, BAD_CAST "type");
2270 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002271 xmlRelaxNGNormExtSpace(type);
2272 if (xmlValidateNCName(type, 0)) {
2273 if (ctxt->error != NULL)
2274 ctxt->error(ctxt->userData,
2275 "value type '%s' is not an NCName\n",
2276 type);
2277 ctxt->nbErrors++;
2278 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002279 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2280 if (library == NULL)
2281 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2282
2283 def->name = type;
2284 def->ns = library;
2285
2286 lib = (xmlRelaxNGTypeLibraryPtr)
2287 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2288 if (lib == NULL) {
2289 if (ctxt->error != NULL)
2290 ctxt->error(ctxt->userData,
2291 "Use of unregistered type library '%s'\n",
2292 library);
2293 ctxt->nbErrors++;
2294 def->data = NULL;
2295 } else {
2296 def->data = lib;
2297 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002298 if (ctxt->error != NULL)
2299 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002300 "Internal error with type library '%s': no 'have'\n",
2301 library);
2302 ctxt->nbErrors++;
2303 } else {
2304 tmp = lib->have(lib->data, def->name);
2305 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002306 if (ctxt->error != NULL)
2307 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002308 "Error type '%s' is not exported by type library '%s'\n",
2309 def->name, library);
2310 ctxt->nbErrors++;
2311 }
2312 }
2313 }
2314 }
2315 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002316 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002317 } else if (((node->children->type != XML_TEXT_NODE) &&
2318 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002319 (node->children->next != NULL)) {
2320 if (ctxt->error != NULL)
2321 ctxt->error(ctxt->userData,
2322 "Expecting a single text value for <value>content\n");
2323 ctxt->nbErrors++;
2324 } else {
2325 def->value = xmlNodeGetContent(node);
2326 if (def->value == NULL) {
2327 if (ctxt->error != NULL)
2328 ctxt->error(ctxt->userData,
2329 "Element <value> has no content\n");
2330 ctxt->nbErrors++;
2331 }
2332 }
2333 /* TODO check ahead of time that the value is okay per the type */
2334 return(def);
2335}
2336
2337/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002338 * xmlRelaxNGParseData:
2339 * @ctxt: a Relax-NG parser context
2340 * @node: the data node.
2341 *
2342 * parse the content of a RelaxNG data node.
2343 *
2344 * Returns the definition pointer or NULL in case of error
2345 */
2346static xmlRelaxNGDefinePtr
2347xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002348 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002349 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002350 xmlRelaxNGTypeLibraryPtr lib;
2351 xmlChar *type;
2352 xmlChar *library;
2353 xmlNodePtr content;
2354 int tmp;
2355
2356 type = xmlGetProp(node, BAD_CAST "type");
2357 if (type == NULL) {
2358 if (ctxt->error != NULL)
2359 ctxt->error(ctxt->userData,
2360 "data has no type\n");
2361 ctxt->nbErrors++;
2362 return(NULL);
2363 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002364 xmlRelaxNGNormExtSpace(type);
2365 if (xmlValidateNCName(type, 0)) {
2366 if (ctxt->error != NULL)
2367 ctxt->error(ctxt->userData,
2368 "data type '%s' is not an NCName\n",
2369 type);
2370 ctxt->nbErrors++;
2371 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002372 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2373 if (library == NULL)
2374 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2375
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002376 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_DATATYPE);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002377 if (def == NULL) {
2378 xmlFree(type);
2379 return(NULL);
2380 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002381 def->name = type;
2382 def->ns = library;
2383
2384 lib = (xmlRelaxNGTypeLibraryPtr)
2385 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2386 if (lib == NULL) {
2387 if (ctxt->error != NULL)
2388 ctxt->error(ctxt->userData,
2389 "Use of unregistered type library '%s'\n",
2390 library);
2391 ctxt->nbErrors++;
2392 def->data = NULL;
2393 } else {
2394 def->data = lib;
2395 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002396 if (ctxt->error != NULL)
2397 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002398 "Internal error with type library '%s': no 'have'\n",
2399 library);
2400 ctxt->nbErrors++;
2401 } else {
2402 tmp = lib->have(lib->data, def->name);
2403 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002404 if (ctxt->error != NULL)
2405 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002406 "Error type '%s' is not exported by type library '%s'\n",
2407 def->name, library);
2408 ctxt->nbErrors++;
2409 }
2410 }
2411 }
2412 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002413
2414 /*
2415 * Handle optional params
2416 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002417 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002418 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2419 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002420 if (xmlStrEqual(library,
2421 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2422 if (ctxt->error != NULL)
2423 ctxt->error(ctxt->userData,
2424 "Type library '%s' does not allow type parameters\n",
2425 library);
2426 ctxt->nbErrors++;
2427 content = content->next;
2428 while ((content != NULL) &&
2429 (xmlStrEqual(content->name, BAD_CAST "param")))
2430 content = content->next;
2431 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002432 param = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_PARAM);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002433 if (param != NULL) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002434 param->name = xmlGetProp(content, BAD_CAST "name");
2435 if (param->name == NULL) {
2436 if (ctxt->error != NULL)
2437 ctxt->error(ctxt->userData,
2438 "param has no name\n");
2439 ctxt->nbErrors++;
2440 }
2441 param->value = xmlNodeGetContent(content);
2442 if (lastparam == NULL) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002443 def->prop = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002444 } else {
2445 lastparam->next = param;
2446 lastparam = param;
2447 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002448 if (lib != NULL) {
2449 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002450 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002451 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002452 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002453 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002454 /*
2455 * Handle optional except
2456 */
2457 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2458 xmlNodePtr child;
2459 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2460
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002461 except = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EXCEPT);
Daniel Veillard416589a2003-02-17 17:25:42 +00002462 if (except == NULL) {
2463 return(def);
2464 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002465 child = content->children;
2466 if (last == NULL) {
2467 def->content = except;
2468 } else {
2469 last->next = except;
2470 }
2471 if (child == NULL) {
2472 if (ctxt->error != NULL)
2473 ctxt->error(ctxt->userData,
2474 "except has no content\n");
2475 ctxt->nbErrors++;
2476 }
2477 while (child != NULL) {
2478 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2479 if (tmp2 != NULL) {
2480 if (last2 == NULL) {
2481 except->content = last2 = tmp2;
2482 } else {
2483 last2->next = tmp2;
2484 last2 = tmp2;
2485 }
2486 }
2487 child = child->next;
2488 }
2489 content = content->next;
2490 }
2491 /*
2492 * Check there is no unhandled data
2493 */
2494 if (content != NULL) {
2495 if (ctxt->error != NULL)
2496 ctxt->error(ctxt->userData,
2497 "Element data has unexpected content %s\n", content->name);
2498 ctxt->nbErrors++;
2499 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002500
2501 return(def);
2502}
2503
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002504static const xmlChar *invalidName = BAD_CAST "\1";
2505
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002506/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002507 * xmlRelaxNGCompareNameClasses:
2508 * @defs1: the first element/attribute defs
2509 * @defs2: the second element/attribute defs
2510 * @name: the restriction on the name
2511 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002512 *
2513 * Compare the 2 lists of element definitions. The comparison is
2514 * that if both lists do not accept the same QNames, it returns 1
2515 * If the 2 lists can accept the same QName the comparison returns 0
2516 *
2517 * Returns 1 disttinct, 0 if equal
2518 */
2519static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002520xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2521 xmlRelaxNGDefinePtr def2) {
2522 int ret = 1;
2523 xmlNode node;
2524 xmlNs ns;
2525 xmlRelaxNGValidCtxt ctxt;
2526 ctxt.flags = FLAGS_IGNORABLE;
2527
Daniel Veillard42f12e92003-03-07 18:32:59 +00002528 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
2529
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002530 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2531 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2532 if (def2->type == XML_RELAXNG_TEXT)
2533 return(1);
2534 if (def1->name != NULL) {
2535 node.name = def1->name;
2536 } else {
2537 node.name = invalidName;
2538 }
2539 node.ns = &ns;
2540 if (def1->ns != NULL) {
2541 if (def1->ns[0] == 0) {
2542 node.ns = NULL;
2543 } else {
2544 ns.href = def1->ns;
2545 }
2546 } else {
2547 ns.href = invalidName;
2548 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002549 if (xmlRelaxNGNsNameMatch(&ctxt, def2, &node,
2550 (def1->type == XML_RELAXNG_ELEMENT))) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002551 if (def1->nameClass != NULL) {
2552 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2553 } else {
2554 ret = 0;
2555 }
2556 } else {
2557 ret = 1;
2558 }
2559 } else if (def1->type == XML_RELAXNG_TEXT) {
2560 if (def2->type == XML_RELAXNG_TEXT)
2561 return(0);
2562 return(1);
2563 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002564 TODO
2565 ret = 0;
2566 } else {
2567 TODO
2568 ret = 0;
2569 }
2570 if (ret == 0)
2571 return(ret);
2572 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2573 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2574 if (def2->name != NULL) {
2575 node.name = def2->name;
2576 } else {
2577 node.name = invalidName;
2578 }
2579 node.ns = &ns;
2580 if (def2->ns != NULL) {
2581 if (def2->ns[0] == 0) {
2582 node.ns = NULL;
2583 } else {
2584 ns.href = def2->ns;
2585 }
2586 } else {
2587 ns.href = invalidName;
2588 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002589 if (xmlRelaxNGNsNameMatch(&ctxt, def1, &node,
2590 (def1->type == XML_RELAXNG_ELEMENT))) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002591 if (def2->nameClass != NULL) {
2592 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2593 } else {
2594 ret = 0;
2595 }
2596 } else {
2597 ret = 1;
2598 }
2599 } else {
2600 TODO
2601 ret = 0;
2602 }
2603
2604 return(ret);
2605}
2606
2607/**
2608 * xmlRelaxNGCompareElemDefLists:
2609 * @ctxt: a Relax-NG parser context
2610 * @defs1: the first list of element/attribute defs
2611 * @defs2: the second list of element/attribute defs
2612 *
2613 * Compare the 2 lists of element or attribute definitions. The comparison
2614 * is that if both lists do not accept the same QNames, it returns 1
2615 * If the 2 lists can accept the same QName the comparison returns 0
2616 *
2617 * Returns 1 disttinct, 0 if equal
2618 */
2619static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002620xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2621 xmlRelaxNGDefinePtr *def1,
2622 xmlRelaxNGDefinePtr *def2) {
2623 xmlRelaxNGDefinePtr *basedef2 = def2;
2624
Daniel Veillard154877e2003-01-30 12:17:05 +00002625 if ((def1 == NULL) || (def2 == NULL))
2626 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002627 if ((*def1 == NULL) || (*def2 == NULL))
2628 return(1);
2629 while (*def1 != NULL) {
2630 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002631 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2632 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002633 def2++;
2634 }
2635 def2 = basedef2;
2636 def1++;
2637 }
2638 return(1);
2639}
2640
2641/**
2642 * xmlRelaxNGGetElements:
2643 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002644 * @def: the definition definition
2645 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002646 *
2647 * Compute the list of top elements a definition can generate
2648 *
2649 * Returns a list of elements or NULL if none was found.
2650 */
2651static xmlRelaxNGDefinePtr *
2652xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002653 xmlRelaxNGDefinePtr def,
2654 int eora) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002655 xmlRelaxNGDefinePtr *ret = NULL, parent, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002656 int len = 0;
2657 int max = 0;
2658
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002659 /*
2660 * Don't run that check in case of error. Infinite recursion
2661 * becomes possible.
2662 */
2663 if (ctxt->nbErrors != 0)
2664 return(NULL);
2665
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002666 parent = NULL;
2667 cur = def;
2668 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002669 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
2670 (cur->type == XML_RELAXNG_TEXT))) ||
2671 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002672 if (ret == NULL) {
2673 max = 10;
2674 ret = (xmlRelaxNGDefinePtr *)
2675 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
2676 if (ret == NULL) {
2677 if (ctxt->error != NULL)
2678 ctxt->error(ctxt->userData,
2679 "Out of memory in element search\n");
2680 ctxt->nbErrors++;
2681 return(NULL);
2682 }
2683 } else if (max <= len) {
2684 max *= 2;
2685 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
2686 if (ret == NULL) {
2687 if (ctxt->error != NULL)
2688 ctxt->error(ctxt->userData,
2689 "Out of memory in element search\n");
2690 ctxt->nbErrors++;
2691 return(NULL);
2692 }
2693 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00002694 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002695 ret[len] = NULL;
2696 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
2697 (cur->type == XML_RELAXNG_INTERLEAVE) ||
2698 (cur->type == XML_RELAXNG_GROUP) ||
2699 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00002700 (cur->type == XML_RELAXNG_REF) ||
2701 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002702 /*
2703 * Don't go within elements or attributes or string values.
2704 * Just gather the element top list
2705 */
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002706 if (cur->cont2 != NULL)
2707 cur->cont2->parent = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002708 if (cur->content != NULL) {
2709 parent = cur;
2710 cur = cur->content;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002711 cur->parent = parent;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002712 continue;
2713 }
2714 }
Daniel Veillard154877e2003-01-30 12:17:05 +00002715 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002716 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002717 if ((cur->parent != NULL) && (cur == cur->parent->content) &&
2718 (cur->parent->cont2 != NULL)) {
2719 cur = cur->parent->cont2;
2720 continue;
2721 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002722 if (cur->next != NULL) {
2723 cur = cur->next;
2724 continue;
2725 }
2726 do {
2727 cur = cur->parent;
2728 if (cur == NULL) break;
2729 if (cur == def) return(ret);
2730 if (cur->next != NULL) {
2731 cur = cur->next;
2732 break;
2733 }
2734 } while (cur != NULL);
2735 }
2736 return(ret);
2737}
2738
2739/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002740 * xmlRelaxNGCheckGroupAttrs:
2741 * @ctxt: a Relax-NG parser context
2742 * @def: the group definition
2743 *
2744 * Detects violations of rule 7.3
2745 */
2746static void
2747xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
2748 xmlRelaxNGDefinePtr def) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002749 xmlRelaxNGDefinePtr *list[2];
2750 int ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002751
2752 if ((def == NULL) ||
2753 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002754 (def->type != XML_RELAXNG_INTERLEAVE)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002755 return;
2756
2757 /*
2758 * Don't run that check in case of error. Infinite recursion
2759 * becomes possible.
2760 */
2761 if (ctxt->nbErrors != 0)
2762 return;
2763
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002764 list[0] = xmlRelaxNGGetElements(ctxt, def->content, 1);
2765 list[1] = xmlRelaxNGGetElements(ctxt, def->cont2, 1);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002766
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002767 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[0], list[1]);
2768 if (ret == 0) {
2769 if (ctxt->error != NULL) {
2770 if (def->type == XML_RELAXNG_GROUP)
2771 ctxt->error(ctxt->userData,
2772 "Attributes conflicts in group\n");
2773 else
2774 ctxt->error(ctxt->userData,
2775 "Attributes conflicts in interleave\n");
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002776
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002777 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002778 ctxt->nbErrors++;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002779 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002780 if (list[0] != NULL)
2781 xmlFree(list[0]);
2782 if (list[1] != NULL)
2783 xmlFree(list[1]);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002784}
2785
2786/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002787 * xmlRelaxNGCheckInterleave:
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002788 * @ctxt: a Relax-NG parser context
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002789 * @def: the group definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002790 *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002791 * Detects violations of rule 7.3
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002792 */
2793static void
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002794xmlRelaxNGCheckInterleave(xmlRelaxNGParserCtxtPtr ctxt,
2795 xmlRelaxNGDefinePtr def) {
2796 xmlRelaxNGDefinePtr *list[2];
2797 int ret;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002798
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002799 if ((def == NULL) ||
2800 (def->type != XML_RELAXNG_INTERLEAVE))
2801 return;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002802
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002803 /*
2804 * Don't run that check in case of error. Infinite recursion
2805 * becomes possible.
2806 */
2807 if (ctxt->nbErrors != 0)
2808 return;
2809
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002810 list[0] = xmlRelaxNGGetElements(ctxt, def->content, 0);
2811 list[1] = xmlRelaxNGGetElements(ctxt, def->cont2, 0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002812
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002813 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[0], list[1]);
2814 if (ret == 0) {
2815 if (ctxt->error != NULL) {
2816 ctxt->error(ctxt->userData,
2817 "Element or text conflicts in interleave\n");
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002818 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002819 ctxt->nbErrors++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002820 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002821 if (list[0] != NULL)
2822 xmlFree(list[0]);
2823 if (list[1] != NULL)
2824 xmlFree(list[1]);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002825}
2826
2827/**
2828 * xmlRelaxNGParseInterleave:
2829 * @ctxt: a Relax-NG parser context
2830 * @node: the data node.
2831 *
2832 * parse the content of a RelaxNG interleave node.
2833 *
2834 * Returns the definition pointer or NULL in case of error
2835 */
2836static xmlRelaxNGDefinePtr
2837xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2838 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002839 xmlNodePtr child;
2840
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002841 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00002842 if (child == NULL) {
2843 if (ctxt->error != NULL)
2844 ctxt->error(ctxt->userData, "Element interleave is empty\n");
2845 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002846 } else if (child->next == NULL) {
2847 def = xmlRelaxNGParseElement(ctxt, child);
2848 } else {
2849 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_INTERLEAVE);
2850 if (def == NULL) {
2851 return(NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002852 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002853
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002854 def->content = xmlRelaxNGParsePattern(ctxt, child);
2855 child = child->next;
2856 def->cont2 = xmlRelaxNGParsePattern(ctxt, child);
2857 child = child->next;
2858 if (child != NULL) {
2859 if (ctxt->error != NULL)
2860 ctxt->error(ctxt->userData,
2861 "Internal: interleave has more than 2 children");
2862 ctxt->nbErrors++;
2863 }
2864 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002865 return(def);
2866}
Daniel Veillard6eadf632003-01-23 18:29:16 +00002867
2868/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002869 * xmlRelaxNGParseInclude:
2870 * @ctxt: a Relax-NG parser context
2871 * @node: the include node
2872 *
2873 * Integrate the content of an include node in the current grammar
2874 *
2875 * Returns 0 in case of success or -1 in case of error
2876 */
2877static int
2878xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2879 xmlRelaxNGIncludePtr incl;
2880 xmlNodePtr root;
2881 int ret = 0, tmp;
2882
2883 incl = node->_private;
2884 if (incl == NULL) {
2885 if (ctxt->error != NULL)
2886 ctxt->error(ctxt->userData,
2887 "Include node has no data\n");
2888 ctxt->nbErrors++;
2889 return(-1);
2890 }
2891 root = xmlDocGetRootElement(incl->doc);
2892 if (root == NULL) {
2893 if (ctxt->error != NULL)
2894 ctxt->error(ctxt->userData,
2895 "Include document is empty\n");
2896 ctxt->nbErrors++;
2897 return(-1);
2898 }
2899 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
2900 if (ctxt->error != NULL)
2901 ctxt->error(ctxt->userData,
2902 "Include document root is not a grammar\n");
2903 ctxt->nbErrors++;
2904 return(-1);
2905 }
2906
2907 /*
2908 * Merge the definition from both the include and the internal list
2909 */
2910 if (root->children != NULL) {
2911 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
2912 if (tmp != 0)
2913 ret = -1;
2914 }
2915 if (node->children != NULL) {
2916 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
2917 if (tmp != 0)
2918 ret = -1;
2919 }
2920 return(ret);
2921}
2922
2923/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00002924 * xmlRelaxNGParseDefine:
2925 * @ctxt: a Relax-NG parser context
2926 * @node: the define node
2927 *
2928 * parse the content of a RelaxNG define element node.
2929 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002930 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00002931 */
2932static int
2933xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2934 xmlChar *name;
2935 int ret = 0, tmp;
2936 xmlRelaxNGDefinePtr def;
2937 const xmlChar *olddefine;
2938
2939 name = xmlGetProp(node, BAD_CAST "name");
2940 if (name == NULL) {
2941 if (ctxt->error != NULL)
2942 ctxt->error(ctxt->userData,
2943 "define has no name\n");
2944 ctxt->nbErrors++;
2945 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00002946 xmlRelaxNGNormExtSpace(name);
2947 if (xmlValidateNCName(name, 0)) {
2948 if (ctxt->error != NULL)
2949 ctxt->error(ctxt->userData,
2950 "define name '%s' is not an NCName\n",
2951 name);
2952 ctxt->nbErrors++;
2953 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00002954 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_DEF);
Daniel Veillard276be4a2003-01-24 01:03:34 +00002955 if (def == NULL) {
2956 xmlFree(name);
2957 return(-1);
2958 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00002959 def->name = name;
2960 if (node->children == NULL) {
2961 if (ctxt->error != NULL)
2962 ctxt->error(ctxt->userData,
2963 "define has no children\n");
2964 ctxt->nbErrors++;
2965 } else {
2966 olddefine = ctxt->define;
2967 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00002968 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00002969 ctxt->define = olddefine;
2970 }
2971 if (ctxt->grammar->defs == NULL)
2972 ctxt->grammar->defs = xmlHashCreate(10);
2973 if (ctxt->grammar->defs == NULL) {
2974 if (ctxt->error != NULL)
2975 ctxt->error(ctxt->userData,
2976 "Could not create definition hash\n");
2977 ctxt->nbErrors++;
2978 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00002979 } else {
2980 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
2981 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00002982 xmlRelaxNGDefinePtr prev;
2983
2984 prev = xmlHashLookup(ctxt->grammar->defs, name);
2985 if (prev == NULL) {
2986 if (ctxt->error != NULL)
2987 ctxt->error(ctxt->userData,
2988 "Internal error on define aggregation of %s\n",
2989 name);
2990 ctxt->nbErrors++;
2991 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00002992 } else {
2993 while (prev->nextHash != NULL)
2994 prev = prev->nextHash;
2995 prev->nextHash = def;
2996 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00002997 }
2998 }
2999 }
3000 return(ret);
3001}
3002
3003/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003004 * xmlRelaxNGProcessExternalRef:
3005 * @ctxt: the parser context
3006 * @node: the externlRef node
3007 *
3008 * Process and compile an externlRef node
3009 *
3010 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3011 */
3012static xmlRelaxNGDefinePtr
3013xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3014 xmlRelaxNGDocumentPtr docu;
3015 xmlNodePtr root, tmp;
3016 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003017 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003018 xmlRelaxNGDefinePtr def;
3019
3020 docu = node->_private;
3021 if (docu != NULL) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003022 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EXTERNALREF);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003023 if (def == NULL)
3024 return(NULL);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003025
3026 if (docu->content == NULL) {
3027 /*
3028 * Then do the parsing for good
3029 */
3030 root = xmlDocGetRootElement(docu->doc);
3031 if (root == NULL) {
3032 if (ctxt->error != NULL)
3033 ctxt->error(ctxt->userData,
3034 "xmlRelaxNGParse: %s is empty\n",
3035 ctxt->URL);
3036 ctxt->nbErrors++;
3037 return (NULL);
3038 }
3039 /*
3040 * ns transmission rules
3041 */
3042 ns = xmlGetProp(root, BAD_CAST "ns");
3043 if (ns == NULL) {
3044 tmp = node;
3045 while ((tmp != NULL) &&
3046 (tmp->type == XML_ELEMENT_NODE)) {
3047 ns = xmlGetProp(tmp, BAD_CAST "ns");
3048 if (ns != NULL) {
3049 break;
3050 }
3051 tmp = tmp->parent;
3052 }
3053 if (ns != NULL) {
3054 xmlSetProp(root, BAD_CAST "ns", ns);
3055 newNs = 1;
3056 xmlFree(ns);
3057 }
3058 } else {
3059 xmlFree(ns);
3060 }
3061
3062 /*
3063 * Parsing to get a precompiled schemas.
3064 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003065 oldflags = ctxt->flags;
3066 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003067 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003068 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003069 if ((docu->schema != NULL) &&
3070 (docu->schema->topgrammar != NULL)) {
3071 docu->content = docu->schema->topgrammar->start;
3072 }
3073
3074 /*
3075 * the externalRef may be reused in a different ns context
3076 */
3077 if (newNs == 1) {
3078 xmlUnsetProp(root, BAD_CAST "ns");
3079 }
3080 }
3081 def->content = docu->content;
3082 } else {
3083 def = NULL;
3084 }
3085 return(def);
3086}
3087
3088/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003089 * xmlRelaxNGParsePattern:
3090 * @ctxt: a Relax-NG parser context
3091 * @node: the pattern node.
3092 *
3093 * parse the content of a RelaxNG pattern node.
3094 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003095 * Returns the definition pointer or NULL in case of error or if no
3096 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003097 */
3098static xmlRelaxNGDefinePtr
3099xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3100 xmlRelaxNGDefinePtr def = NULL;
3101
Daniel Veillardd2298792003-02-14 16:54:11 +00003102 if (node == NULL) {
3103 return(NULL);
3104 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003105 if (IS_RELAXNG(node, "element")) {
3106 def = xmlRelaxNGParseElement(ctxt, node);
3107 } else if (IS_RELAXNG(node, "attribute")) {
3108 def = xmlRelaxNGParseAttribute(ctxt, node);
3109 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003110 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EMPTY);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003111 if (def == NULL)
3112 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003113 if (node->children != NULL) {
3114 if (ctxt->error != NULL)
3115 ctxt->error(ctxt->userData, "empty: had a child node\n");
3116 ctxt->nbErrors++;
3117 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003118 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003119 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_TEXT);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003120 if (def == NULL)
3121 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003122 if (node->children != NULL) {
3123 if (ctxt->error != NULL)
3124 ctxt->error(ctxt->userData, "text: had a child node\n");
3125 ctxt->nbErrors++;
3126 }
3127 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003128 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_CHOICE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003129 if (def == NULL)
3130 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003131 if (node->children == NULL) {
3132 if (ctxt->error != NULL)
3133 ctxt->error(ctxt->userData,
3134 "Element %s is empty\n", node->name);
3135 ctxt->nbErrors++;
3136 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003137 def->cont2 = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EMPTY);
3138 def->content = xmlRelaxNGNewDefine(ctxt, node,
3139 XML_RELAXNG_ONEORMORE);
3140 if (def->content != NULL) {
3141 def->content->content =
3142 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3143 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003144 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003145 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003146 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_ONEORMORE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003147 if (def == NULL)
3148 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003149 if (node->children == NULL) {
3150 if (ctxt->error != NULL)
3151 ctxt->error(ctxt->userData,
3152 "Element %s is empty\n", node->name);
3153 ctxt->nbErrors++;
3154 } else {
3155 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3156 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003157 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003158 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_CHOICE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003159 if (def == NULL)
3160 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003161 if (node->children == NULL) {
3162 if (ctxt->error != NULL)
3163 ctxt->error(ctxt->userData,
3164 "Element %s is empty\n", node->name);
3165 ctxt->nbErrors++;
3166 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003167 def->cont2 = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EMPTY);
Daniel Veillardd2298792003-02-14 16:54:11 +00003168 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3169 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003170 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003171 if (node->children == NULL) {
3172 if (ctxt->error != NULL)
3173 ctxt->error(ctxt->userData,
3174 "Element %s is empty\n", node->name);
3175 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003176 } else if (node->children->next == NULL) {
3177 def = xmlRelaxNGParsePattern(ctxt, node->children);
Daniel Veillardd2298792003-02-14 16:54:11 +00003178 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003179 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_CHOICE);
3180 if (def == NULL)
3181 return(NULL);
3182 def->content = xmlRelaxNGParsePattern(ctxt, node->children);
3183 def->cont2 = xmlRelaxNGParsePattern(ctxt, node->children->next);
Daniel Veillardd2298792003-02-14 16:54:11 +00003184 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003185 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003186 if (node->children == NULL) {
3187 if (ctxt->error != NULL)
3188 ctxt->error(ctxt->userData,
3189 "Element %s is empty\n", node->name);
3190 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003191 } else if (node->children->next == NULL) {
3192 def = xmlRelaxNGParsePattern(ctxt, node->children);
Daniel Veillardd2298792003-02-14 16:54:11 +00003193 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003194 def = xmlRelaxNGParseInterleave(ctxt, node);
3195 }
3196 } else if (IS_RELAXNG(node, "group")) {
3197 if (node->children == NULL) {
3198 if (ctxt->error != NULL)
3199 ctxt->error(ctxt->userData,
3200 "Element %s is empty\n", node->name);
3201 ctxt->nbErrors++;
3202 } else if (node->children->next == NULL) {
3203 def = xmlRelaxNGParsePattern(ctxt, node->children);
3204 } else {
3205 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_GROUP);
3206 if (def == NULL)
3207 return(NULL);
3208 def->content = xmlRelaxNGParsePattern(ctxt, node->children);
3209 def->cont2 = xmlRelaxNGParsePattern(ctxt, node->children->next);
Daniel Veillardd2298792003-02-14 16:54:11 +00003210 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003211 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003212 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_REF);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003213 if (def == NULL)
3214 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003215 def->name = xmlGetProp(node, BAD_CAST "name");
3216 if (def->name == NULL) {
3217 if (ctxt->error != NULL)
3218 ctxt->error(ctxt->userData,
3219 "ref has no name\n");
3220 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003221 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003222 xmlRelaxNGNormExtSpace(def->name);
3223 if (xmlValidateNCName(def->name, 0)) {
3224 if (ctxt->error != NULL)
3225 ctxt->error(ctxt->userData,
3226 "ref name '%s' is not an NCName\n",
3227 def->name);
3228 ctxt->nbErrors++;
3229 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003230 }
3231 if (node->children != NULL) {
3232 if (ctxt->error != NULL)
3233 ctxt->error(ctxt->userData,
3234 "ref is not empty\n");
3235 ctxt->nbErrors++;
3236 }
3237 if (ctxt->grammar->refs == NULL)
3238 ctxt->grammar->refs = xmlHashCreate(10);
3239 if (ctxt->grammar->refs == NULL) {
3240 if (ctxt->error != NULL)
3241 ctxt->error(ctxt->userData,
3242 "Could not create references hash\n");
3243 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003244 def = NULL;
3245 } else {
3246 int tmp;
3247
3248 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
3249 if (tmp < 0) {
3250 xmlRelaxNGDefinePtr prev;
3251
3252 prev = (xmlRelaxNGDefinePtr)
3253 xmlHashLookup(ctxt->grammar->refs, def->name);
3254 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003255 if (def->name != NULL) {
3256 if (ctxt->error != NULL)
3257 ctxt->error(ctxt->userData,
3258 "Error refs definitions '%s'\n",
3259 def->name);
3260 } else {
3261 if (ctxt->error != NULL)
3262 ctxt->error(ctxt->userData,
3263 "Error refs definitions\n");
3264 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003265 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003266 def = NULL;
3267 } else {
3268 def->nextHash = prev->nextHash;
3269 prev->nextHash = def;
3270 }
3271 }
3272 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003273 } else if (IS_RELAXNG(node, "data")) {
3274 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003275 } else if (IS_RELAXNG(node, "value")) {
3276 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003277 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003278 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_LIST);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003279 if (def == NULL)
3280 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003281 if (node->children == NULL) {
3282 if (ctxt->error != NULL)
3283 ctxt->error(ctxt->userData,
3284 "Element %s is empty\n", node->name);
3285 ctxt->nbErrors++;
3286 } else {
3287 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3288 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003289 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003290 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003291 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003292 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_NOT_ALLOWED);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003293 if (def == NULL)
3294 return(NULL);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003295 if (node->children != NULL) {
3296 if (ctxt->error != NULL)
3297 ctxt->error(ctxt->userData,
3298 "xmlRelaxNGParse: notAllowed element is not empty\n");
3299 ctxt->nbErrors++;
3300 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003301 } else if (IS_RELAXNG(node, "grammar")) {
3302 xmlRelaxNGGrammarPtr grammar, old;
3303 xmlRelaxNGGrammarPtr oldparent;
3304
Daniel Veillardc482e262003-02-26 14:48:48 +00003305#ifdef DEBUG_GRAMMAR
3306 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
3307#endif
3308
Daniel Veillard419a7682003-02-03 23:22:49 +00003309 oldparent = ctxt->parentgrammar;
3310 old = ctxt->grammar;
3311 ctxt->parentgrammar = old;
3312 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
3313 if (old != NULL) {
3314 ctxt->grammar = old;
3315 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00003316#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00003317 if (grammar != NULL) {
3318 grammar->next = old->next;
3319 old->next = grammar;
3320 }
Daniel Veillardc482e262003-02-26 14:48:48 +00003321#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00003322 }
3323 if (grammar != NULL)
3324 def = grammar->start;
3325 else
3326 def = NULL;
3327 } else if (IS_RELAXNG(node, "parentRef")) {
3328 if (ctxt->parentgrammar == NULL) {
3329 if (ctxt->error != NULL)
3330 ctxt->error(ctxt->userData,
3331 "Use of parentRef without a parent grammar\n");
3332 ctxt->nbErrors++;
3333 return(NULL);
3334 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003335 def = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_PARENTREF);
Daniel Veillard419a7682003-02-03 23:22:49 +00003336 if (def == NULL)
3337 return(NULL);
Daniel Veillard419a7682003-02-03 23:22:49 +00003338 def->name = xmlGetProp(node, BAD_CAST "name");
3339 if (def->name == NULL) {
3340 if (ctxt->error != NULL)
3341 ctxt->error(ctxt->userData,
3342 "parentRef has no name\n");
3343 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00003344 } else {
3345 xmlRelaxNGNormExtSpace(def->name);
3346 if (xmlValidateNCName(def->name, 0)) {
3347 if (ctxt->error != NULL)
3348 ctxt->error(ctxt->userData,
3349 "parentRef name '%s' is not an NCName\n",
3350 def->name);
3351 ctxt->nbErrors++;
3352 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003353 }
3354 if (node->children != NULL) {
3355 if (ctxt->error != NULL)
3356 ctxt->error(ctxt->userData,
3357 "parentRef is not empty\n");
3358 ctxt->nbErrors++;
3359 }
3360 if (ctxt->parentgrammar->refs == NULL)
3361 ctxt->parentgrammar->refs = xmlHashCreate(10);
3362 if (ctxt->parentgrammar->refs == NULL) {
3363 if (ctxt->error != NULL)
3364 ctxt->error(ctxt->userData,
3365 "Could not create references hash\n");
3366 ctxt->nbErrors++;
3367 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003368 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00003369 int tmp;
3370
3371 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3372 if (tmp < 0) {
3373 xmlRelaxNGDefinePtr prev;
3374
3375 prev = (xmlRelaxNGDefinePtr)
3376 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3377 if (prev == NULL) {
3378 if (ctxt->error != NULL)
3379 ctxt->error(ctxt->userData,
3380 "Internal error parentRef definitions '%s'\n",
3381 def->name);
3382 ctxt->nbErrors++;
3383 def = NULL;
3384 } else {
3385 def->nextHash = prev->nextHash;
3386 prev->nextHash = def;
3387 }
3388 }
3389 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003390 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003391 /* we should not go there unless an error happened */
3392 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003393 } else {
3394 if (ctxt->error != NULL)
3395 ctxt->error(ctxt->userData,
3396 "Unexpected node %s is not a pattern\n",
3397 node->name);
3398 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003399 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003400 }
3401 return(def);
3402}
3403
3404/**
3405 * xmlRelaxNGParseAttribute:
3406 * @ctxt: a Relax-NG parser context
3407 * @node: the element node
3408 *
3409 * parse the content of a RelaxNG attribute node.
3410 *
3411 * Returns the definition pointer or NULL in case of error.
3412 */
3413static xmlRelaxNGDefinePtr
3414xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003415 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003416 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003417 int old_flags;
3418
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003419 ret = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_ATTRIBUTE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003420 if (ret == NULL)
3421 return(NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003422 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003423 child = node->children;
3424 if (child == NULL) {
3425 if (ctxt->error != NULL)
3426 ctxt->error(ctxt->userData,
3427 "xmlRelaxNGParseattribute: attribute has no children\n");
3428 ctxt->nbErrors++;
3429 return(ret);
3430 }
3431 old_flags = ctxt->flags;
3432 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003433 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3434 if (cur != NULL)
3435 child = child->next;
3436
Daniel Veillardd2298792003-02-14 16:54:11 +00003437 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00003438 cur = xmlRelaxNGParsePattern(ctxt, child);
3439 if (cur != NULL) {
3440 switch (cur->type) {
3441 case XML_RELAXNG_EMPTY:
3442 case XML_RELAXNG_NOT_ALLOWED:
3443 case XML_RELAXNG_TEXT:
3444 case XML_RELAXNG_ELEMENT:
3445 case XML_RELAXNG_DATATYPE:
3446 case XML_RELAXNG_VALUE:
3447 case XML_RELAXNG_LIST:
3448 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00003449 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003450 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003451 case XML_RELAXNG_DEF:
3452 case XML_RELAXNG_ONEORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003453 case XML_RELAXNG_CHOICE:
3454 case XML_RELAXNG_GROUP:
3455 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00003456 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00003457 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003458 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003459 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003460 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00003461 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00003462 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00003463 if (ctxt->error != NULL)
3464 ctxt->error(ctxt->userData,
3465 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003466 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003467 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003468#if 0
Daniel Veillard77648bb2003-02-20 15:03:22 +00003469 case XML_RELAXNG_NOOP:
3470 TODO
3471 if (ctxt->error != NULL)
3472 ctxt->error(ctxt->userData,
3473 "Internal error, noop found\n");
3474 ctxt->nbErrors++;
3475 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003476#endif
3477 case XML_RELAXNG_AFTER:
3478 TODO
3479 if (ctxt->error != NULL)
3480 ctxt->error(ctxt->userData,
3481 "Internal error, after found\n");
3482 ctxt->nbErrors++;
3483 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003484 }
3485 }
3486 child = child->next;
3487 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003488 if (child != NULL) {
3489 if (ctxt->error != NULL)
3490 ctxt->error(ctxt->userData, "attribute has multiple children\n");
3491 ctxt->nbErrors++;
3492 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003493 ctxt->flags = old_flags;
3494 return(ret);
3495}
3496
3497/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003498 * xmlRelaxNGParseExceptNameClass:
3499 * @ctxt: a Relax-NG parser context
3500 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00003501 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003502 *
3503 * parse the content of a RelaxNG nameClass node.
3504 *
3505 * Returns the definition pointer or NULL in case of error.
3506 */
3507static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00003508xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
3509 xmlNodePtr node, int attr) {
3510 xmlRelaxNGDefinePtr ret, cur, last = NULL;
3511 xmlNodePtr child;
3512
Daniel Veillardd2298792003-02-14 16:54:11 +00003513 if (!IS_RELAXNG(node, "except")) {
3514 if (ctxt->error != NULL)
3515 ctxt->error(ctxt->userData,
3516 "Expecting an except node\n");
3517 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00003518 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003519 }
3520 if (node->next != NULL) {
3521 if (ctxt->error != NULL)
3522 ctxt->error(ctxt->userData,
3523 "exceptNameClass allows only a single except node\n");
3524 ctxt->nbErrors++;
3525 }
Daniel Veillard144fae12003-02-03 13:17:57 +00003526 if (node->children == NULL) {
3527 if (ctxt->error != NULL)
3528 ctxt->error(ctxt->userData,
3529 "except has no content\n");
3530 ctxt->nbErrors++;
3531 return(NULL);
3532 }
3533
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003534 ret = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_EXCEPT);
Daniel Veillard144fae12003-02-03 13:17:57 +00003535 if (ret == NULL)
3536 return(NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00003537 child = node->children;
3538 while (child != NULL) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003539 cur = xmlRelaxNGNewDefine(ctxt, child, XML_RELAXNG_ELEMENT);
Daniel Veillard144fae12003-02-03 13:17:57 +00003540 if (cur == NULL)
3541 break;
3542 if (attr)
3543 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard144fae12003-02-03 13:17:57 +00003544
Daniel Veillard419a7682003-02-03 23:22:49 +00003545 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00003546 if (last == NULL) {
3547 ret->content = cur;
3548 } else {
3549 last->next = cur;
3550 }
3551 last = cur;
3552 }
3553 child = child->next;
3554 }
3555
3556 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003557}
3558
3559/**
3560 * xmlRelaxNGParseNameClass:
3561 * @ctxt: a Relax-NG parser context
3562 * @node: the nameClass node
3563 * @def: the current definition
3564 *
3565 * parse the content of a RelaxNG nameClass node.
3566 *
3567 * Returns the definition pointer or NULL in case of error.
3568 */
3569static xmlRelaxNGDefinePtr
3570xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3571 xmlRelaxNGDefinePtr def) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003572 xmlRelaxNGDefinePtr ret;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003573 xmlChar *val;
3574
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003575 ret = def;
3576 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
3577 (IS_RELAXNG(node, "nsName"))) {
3578 if ((def->type != XML_RELAXNG_ELEMENT) &&
3579 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003580 ret = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_ELEMENT);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003581 if (ret == NULL)
3582 return(NULL);
3583 ret->parent = def;
3584 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
3585 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003586 }
3587 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003588 if (IS_RELAXNG(node, "name")) {
3589 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00003590 xmlRelaxNGNormExtSpace(val);
3591 if (xmlValidateNCName(val, 0)) {
3592 if (ctxt->error != NULL) {
3593 if (node->parent != NULL)
3594 ctxt->error(ctxt->userData,
3595 "Element %s name '%s' is not an NCName\n",
3596 node->parent->name, val);
3597 else
3598 ctxt->error(ctxt->userData,
3599 "name '%s' is not an NCName\n",
3600 val);
3601 }
3602 ctxt->nbErrors++;
3603 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003604 ret->name = val;
3605 val = xmlGetProp(node, BAD_CAST "ns");
3606 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00003607 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3608 (val != NULL) &&
3609 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3610 ctxt->error(ctxt->userData,
3611 "Attribute with namespace '%s' is not allowed\n",
3612 val);
3613 ctxt->nbErrors++;
3614 }
3615 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3616 (val != NULL) &&
3617 (val[0] == 0) &&
3618 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
3619 ctxt->error(ctxt->userData,
3620 "Attribute with QName 'xmlns' is not allowed\n",
3621 val);
3622 ctxt->nbErrors++;
3623 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003624 } else if (IS_RELAXNG(node, "anyName")) {
3625 ret->name = NULL;
3626 ret->ns = NULL;
3627 if (node->children != NULL) {
3628 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00003629 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3630 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003631 }
3632 } else if (IS_RELAXNG(node, "nsName")) {
3633 ret->name = NULL;
3634 ret->ns = xmlGetProp(node, BAD_CAST "ns");
3635 if (ret->ns == NULL) {
3636 if (ctxt->error != NULL)
3637 ctxt->error(ctxt->userData,
3638 "nsName has no ns attribute\n");
3639 ctxt->nbErrors++;
3640 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003641 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3642 (ret->ns != NULL) &&
3643 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3644 ctxt->error(ctxt->userData,
3645 "Attribute with namespace '%s' is not allowed\n",
3646 ret->ns);
3647 ctxt->nbErrors++;
3648 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003649 if (node->children != NULL) {
3650 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00003651 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3652 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003653 }
3654 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003655 if (node->children == NULL) {
3656 if (ctxt->error != NULL)
3657 ctxt->error(ctxt->userData,
3658 "Element choice is empty\n");
3659 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003660 } else if (node->children->next == NULL) {
3661 ret = xmlRelaxNGParseNameClass(ctxt, node->children, def);
3662 def->nameClass = ret;
Daniel Veillardd2298792003-02-14 16:54:11 +00003663 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003664 ret = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_CHOICE);
3665 if (ret == NULL)
3666 return(NULL);
3667 ret->content = xmlRelaxNGParseNameClass(ctxt, node->children, ret);
3668 ret->cont2 = xmlRelaxNGParseNameClass(ctxt, node->children->next, ret);
3669 def->nameClass = ret;
Daniel Veillardd2298792003-02-14 16:54:11 +00003670 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003671 } else {
3672 if (ctxt->error != NULL)
3673 ctxt->error(ctxt->userData,
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003674 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003675 node->name);
3676 ctxt->nbErrors++;
3677 return(NULL);
3678 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003679#if 0
Daniel Veillard2e9b1652003-02-19 13:29:45 +00003680 if (ret != def) {
3681 if (def->nameClass == NULL) {
3682 def->nameClass = ret;
3683 } else {
3684 tmp = def->nameClass;
3685 while (tmp->next != NULL) {
3686 tmp = tmp->next;
3687 }
3688 tmp->next = ret;
3689 }
3690 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003691#endif
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003692 return(ret);
3693}
3694
3695/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003696 * xmlRelaxNGParseElement:
3697 * @ctxt: a Relax-NG parser context
3698 * @node: the element node
3699 *
3700 * parse the content of a RelaxNG element node.
3701 *
3702 * Returns the definition pointer or NULL in case of error.
3703 */
3704static xmlRelaxNGDefinePtr
3705xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3706 xmlRelaxNGDefinePtr ret, cur, last;
3707 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003708 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003709
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003710 ret = xmlRelaxNGNewDefine(ctxt, node, XML_RELAXNG_ELEMENT);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003711 if (ret == NULL)
3712 return(NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003713 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003714 child = node->children;
3715 if (child == NULL) {
3716 if (ctxt->error != NULL)
3717 ctxt->error(ctxt->userData,
3718 "xmlRelaxNGParseElement: element has no children\n");
3719 ctxt->nbErrors++;
3720 return(ret);
3721 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003722 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3723 if (cur != NULL)
3724 child = child->next;
3725
Daniel Veillard6eadf632003-01-23 18:29:16 +00003726 if (child == NULL) {
3727 if (ctxt->error != NULL)
3728 ctxt->error(ctxt->userData,
3729 "xmlRelaxNGParseElement: element has no content\n");
3730 ctxt->nbErrors++;
3731 return(ret);
3732 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003733 olddefine = ctxt->define;
3734 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003735 last = NULL;
3736 while (child != NULL) {
3737 cur = xmlRelaxNGParsePattern(ctxt, child);
3738 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003739 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003740 switch (cur->type) {
3741 case XML_RELAXNG_EMPTY:
3742 case XML_RELAXNG_NOT_ALLOWED:
3743 case XML_RELAXNG_TEXT:
3744 case XML_RELAXNG_ELEMENT:
3745 case XML_RELAXNG_DATATYPE:
3746 case XML_RELAXNG_VALUE:
3747 case XML_RELAXNG_LIST:
3748 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00003749 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003750 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003751 case XML_RELAXNG_DEF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003752 case XML_RELAXNG_ONEORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003753 case XML_RELAXNG_CHOICE:
3754 case XML_RELAXNG_GROUP:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003755 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003756 case XML_RELAXNG_INTERLEAVE:
3757 if (last == NULL) {
3758 ret->content = last = cur;
3759 } else {
3760 if ((last->type == XML_RELAXNG_ELEMENT) &&
3761 (ret->content == last)) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003762 ret->content = xmlRelaxNGNewDefine(ctxt, node,
3763 XML_RELAXNG_GROUP);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003764 if (ret->content != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00003765 ret->content->content = last;
3766 } else {
3767 ret->content = last;
3768 }
3769 }
3770 last->next = cur;
3771 last = cur;
3772 }
3773 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003774 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00003775 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00003776 case XML_RELAXNG_EXCEPT:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003777 case XML_RELAXNG_AFTER:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003778 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003779 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003780 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003781#if 0
Daniel Veillard77648bb2003-02-20 15:03:22 +00003782 case XML_RELAXNG_NOOP:
3783 TODO
3784 if (ctxt->error != NULL)
3785 ctxt->error(ctxt->userData,
3786 "Internal error, noop found\n");
3787 ctxt->nbErrors++;
3788 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003789#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00003790 }
3791 }
3792 child = child->next;
3793 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003794 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003795 return(ret);
3796}
3797
3798/**
3799 * xmlRelaxNGParsePatterns:
3800 * @ctxt: a Relax-NG parser context
3801 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00003802 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00003803 *
3804 * parse the content of a RelaxNG start node.
3805 *
3806 * Returns the definition pointer or NULL in case of error.
3807 */
3808static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00003809xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
3810 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003811 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003812
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003813 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003814 while (nodes != NULL) {
3815 if (IS_RELAXNG(nodes, "element")) {
3816 cur = xmlRelaxNGParseElement(ctxt, nodes);
3817 if (def == NULL) {
3818 def = last = cur;
3819 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00003820 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
3821 (def == last)) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003822 def = xmlRelaxNGNewDefine(ctxt, nodes, XML_RELAXNG_GROUP);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003823 def->content = last;
3824 }
3825 last->next = cur;
3826 last = cur;
3827 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003828 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003829 } else {
3830 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00003831 if (cur != NULL) {
3832 if (def == NULL) {
3833 def = last = cur;
3834 } else {
3835 last->next = cur;
3836 last = cur;
3837 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003838 }
3839 }
3840 nodes = nodes->next;
3841 }
3842 return(def);
3843}
3844
3845/**
3846 * xmlRelaxNGParseStart:
3847 * @ctxt: a Relax-NG parser context
3848 * @nodes: start children nodes
3849 *
3850 * parse the content of a RelaxNG start node.
3851 *
3852 * Returns 0 in case of success, -1 in case of error
3853 */
3854static int
3855xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
3856 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00003857 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003858
Daniel Veillardd2298792003-02-14 16:54:11 +00003859 if (nodes == NULL) {
3860 if (ctxt->error != NULL)
3861 ctxt->error(ctxt->userData,
3862 "start has no children\n");
3863 ctxt->nbErrors++;
3864 return(-1);
3865 }
3866 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003867 def = xmlRelaxNGNewDefine(ctxt, nodes, XML_RELAXNG_EMPTY);
Daniel Veillardd2298792003-02-14 16:54:11 +00003868 if (def == NULL)
3869 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003870 if (nodes->children != NULL) {
3871 if (ctxt->error != NULL)
3872 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003873 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003874 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003875 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003876 def = xmlRelaxNGNewDefine(ctxt, nodes, XML_RELAXNG_NOT_ALLOWED);
Daniel Veillardd2298792003-02-14 16:54:11 +00003877 if (def == NULL)
3878 return(-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003879 if (nodes->children != NULL) {
3880 if (ctxt->error != NULL)
3881 ctxt->error(ctxt->userData,
3882 "element notAllowed is not empty\n");
3883 ctxt->nbErrors++;
3884 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003885 } else {
3886 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00003887 }
3888 if (ctxt->grammar->start != NULL) {
3889 last = ctxt->grammar->start;
3890 while (last->next != NULL)
3891 last = last->next;
3892 last->next = def;
3893 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003894 ctxt->grammar->start = def;
3895 }
3896 nodes = nodes->next;
3897 if (nodes != NULL) {
3898 if (ctxt->error != NULL)
3899 ctxt->error(ctxt->userData,
3900 "start more than one children\n");
3901 ctxt->nbErrors++;
3902 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003903 }
3904 return(ret);
3905}
3906
3907/**
3908 * xmlRelaxNGParseGrammarContent:
3909 * @ctxt: a Relax-NG parser context
3910 * @nodes: grammar children nodes
3911 *
3912 * parse the content of a RelaxNG grammar node.
3913 *
3914 * Returns 0 in case of success, -1 in case of error
3915 */
3916static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003917xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00003918{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003919 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003920
3921 if (nodes == NULL) {
3922 if (ctxt->error != NULL)
3923 ctxt->error(ctxt->userData,
3924 "grammar has no children\n");
3925 ctxt->nbErrors++;
3926 return(-1);
3927 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003928 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003929 if (IS_RELAXNG(nodes, "start")) {
3930 if (nodes->children == NULL) {
3931 if (ctxt->error != NULL)
3932 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00003933 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003934 ctxt->nbErrors++;
3935 } else {
3936 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
3937 if (tmp != 0)
3938 ret = -1;
3939 }
3940 } else if (IS_RELAXNG(nodes, "define")) {
3941 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
3942 if (tmp != 0)
3943 ret = -1;
3944 } else if (IS_RELAXNG(nodes, "include")) {
3945 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
3946 if (tmp != 0)
3947 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003948 } else {
3949 if (ctxt->error != NULL)
3950 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003951 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003952 ctxt->nbErrors++;
3953 ret = -1;
3954 }
3955 nodes = nodes->next;
3956 }
3957 return (ret);
3958}
3959
3960/**
3961 * xmlRelaxNGCheckReference:
3962 * @ref: the ref
3963 * @ctxt: a Relax-NG parser context
3964 * @name: the name associated to the defines
3965 *
3966 * Applies the 4.17. combine attribute rule for all the define
3967 * element of a given grammar using the same name.
3968 */
3969static void
3970xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
3971 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
3972 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003973 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003974
3975 grammar = ctxt->grammar;
3976 if (grammar == NULL) {
3977 if (ctxt->error != NULL)
3978 ctxt->error(ctxt->userData,
3979 "Internal error: no grammar in CheckReference %s\n",
3980 name);
3981 ctxt->nbErrors++;
3982 return;
3983 }
3984 if (ref->content != NULL) {
3985 if (ctxt->error != NULL)
3986 ctxt->error(ctxt->userData,
3987 "Internal error: reference has content in CheckReference %s\n",
3988 name);
3989 ctxt->nbErrors++;
3990 return;
3991 }
3992 if (grammar->defs != NULL) {
3993 def = xmlHashLookup(grammar->defs, name);
3994 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00003995 cur = ref;
3996 while (cur != NULL) {
3997 cur->content = def;
3998 cur = cur->nextHash;
3999 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004000 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004001 if (ctxt->error != NULL)
4002 ctxt->error(ctxt->userData,
4003 "Reference %s has no matching definition\n",
4004 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004005 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004006 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004007 } else {
4008 if (ctxt->error != NULL)
4009 ctxt->error(ctxt->userData,
4010 "Reference %s has no matching definition\n",
4011 name);
4012 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004013 }
4014 /*
4015 * TODO: make a closure and verify there is no loop !
4016 */
4017}
4018
4019/**
4020 * xmlRelaxNGCheckCombine:
4021 * @define: the define(s) list
4022 * @ctxt: a Relax-NG parser context
4023 * @name: the name associated to the defines
4024 *
4025 * Applies the 4.17. combine attribute rule for all the define
4026 * element of a given grammar using the same name.
4027 */
4028static void
4029xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4030 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4031 xmlChar *combine;
4032 int choiceOrInterleave = -1;
4033 int missing = 0;
4034 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4035
4036 if (define->nextHash == NULL)
4037 return;
4038 cur = define;
4039 while (cur != NULL) {
4040 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4041 if (combine != NULL) {
4042 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4043 if (choiceOrInterleave == -1)
4044 choiceOrInterleave = 1;
4045 else if (choiceOrInterleave == 0) {
4046 if (ctxt->error != NULL)
4047 ctxt->error(ctxt->userData,
4048 "Defines for %s use both 'choice' and 'interleave'\n",
4049 name);
4050 ctxt->nbErrors++;
4051 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004052 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004053 if (choiceOrInterleave == -1)
4054 choiceOrInterleave = 0;
4055 else if (choiceOrInterleave == 1) {
4056 if (ctxt->error != NULL)
4057 ctxt->error(ctxt->userData,
4058 "Defines for %s use both 'choice' and 'interleave'\n",
4059 name);
4060 ctxt->nbErrors++;
4061 }
4062 } else {
4063 if (ctxt->error != NULL)
4064 ctxt->error(ctxt->userData,
4065 "Defines for %s use unknown combine value '%s''\n",
4066 name, combine);
4067 ctxt->nbErrors++;
4068 }
4069 xmlFree(combine);
4070 } else {
4071 if (missing == 0)
4072 missing = 1;
4073 else {
4074 if (ctxt->error != NULL)
4075 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004076 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004077 name);
4078 ctxt->nbErrors++;
4079 }
4080 }
4081
4082 cur = cur->nextHash;
4083 }
4084#ifdef DEBUG
4085 xmlGenericError(xmlGenericErrorContext,
4086 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4087 name, choiceOrInterleave);
4088#endif
4089 if (choiceOrInterleave == -1)
4090 choiceOrInterleave = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004091 cur = xmlRelaxNGNewDefine(ctxt, define->node, XML_RELAXNG_CHOICE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004092 if (cur == NULL)
4093 return;
4094 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004095 cur->type = XML_RELAXNG_INTERLEAVE;
4096 tmp = define;
4097 last = NULL;
4098 while (tmp != NULL) {
4099 if (tmp->content != NULL) {
4100 if (tmp->content->next != NULL) {
4101 /*
4102 * we need first to create a wrapper.
4103 */
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004104 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node,
4105 XML_RELAXNG_GROUP);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004106 if (tmp2 == NULL)
4107 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004108 tmp2->content = tmp->content;
4109 } else {
4110 tmp2 = tmp->content;
4111 }
4112 if (last == NULL) {
4113 cur->content = tmp2;
4114 } else {
4115 last->next = tmp2;
4116 }
4117 last = tmp2;
4118 tmp->content = NULL;
4119 }
4120 tmp = tmp->nextHash;
4121 }
4122 define->content = cur;
4123}
4124
4125/**
4126 * xmlRelaxNGCombineStart:
4127 * @ctxt: a Relax-NG parser context
4128 * @grammar: the grammar
4129 *
4130 * Applies the 4.17. combine rule for all the start
4131 * element of a given grammar.
4132 */
4133static void
4134xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
4135 xmlRelaxNGGrammarPtr grammar) {
4136 xmlRelaxNGDefinePtr starts;
4137 xmlChar *combine;
4138 int choiceOrInterleave = -1;
4139 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004140 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004141
Daniel Veillard2df2de22003-02-17 23:34:33 +00004142 starts = grammar->start;
4143 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00004144 return;
4145 cur = starts;
4146 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00004147 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
4148 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
4149 combine = NULL;
4150 if (ctxt->error != NULL)
4151 ctxt->error(ctxt->userData,
4152 "Internal error: start element not found\n");
4153 ctxt->nbErrors++;
4154 } else {
4155 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
4156 }
4157
Daniel Veillard6eadf632003-01-23 18:29:16 +00004158 if (combine != NULL) {
4159 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4160 if (choiceOrInterleave == -1)
4161 choiceOrInterleave = 1;
4162 else if (choiceOrInterleave == 0) {
4163 if (ctxt->error != NULL)
4164 ctxt->error(ctxt->userData,
4165 "<start> use both 'choice' and 'interleave'\n");
4166 ctxt->nbErrors++;
4167 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00004168 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004169 if (choiceOrInterleave == -1)
4170 choiceOrInterleave = 0;
4171 else if (choiceOrInterleave == 1) {
4172 if (ctxt->error != NULL)
4173 ctxt->error(ctxt->userData,
4174 "<start> use both 'choice' and 'interleave'\n");
4175 ctxt->nbErrors++;
4176 }
4177 } else {
4178 if (ctxt->error != NULL)
4179 ctxt->error(ctxt->userData,
4180 "<start> uses unknown combine value '%s''\n", combine);
4181 ctxt->nbErrors++;
4182 }
4183 xmlFree(combine);
4184 } else {
4185 if (missing == 0)
4186 missing = 1;
4187 else {
4188 if (ctxt->error != NULL)
4189 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004190 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00004191 ctxt->nbErrors++;
4192 }
4193 }
4194
Daniel Veillard2df2de22003-02-17 23:34:33 +00004195 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004196 }
4197#ifdef DEBUG
4198 xmlGenericError(xmlGenericErrorContext,
4199 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
4200 choiceOrInterleave);
4201#endif
4202 if (choiceOrInterleave == -1)
4203 choiceOrInterleave = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004204 cur = xmlRelaxNGNewDefine(ctxt, starts->node, XML_RELAXNG_CHOICE);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004205 if (cur == NULL)
4206 return;
4207 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004208 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004209 cur->content = grammar->start;
4210 grammar->start = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004211}
4212
4213/**
Daniel Veillardd4310742003-02-18 21:12:46 +00004214 * xmlRelaxNGCheckCycles:
4215 * @ctxt: a Relax-NG parser context
4216 * @nodes: grammar children nodes
4217 * @depth: the counter
4218 *
4219 * Check for cycles.
4220 *
4221 * Returns 0 if check passed, and -1 in case of error
4222 */
4223static int
4224xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
4225 xmlRelaxNGDefinePtr cur, int depth) {
4226 int ret = 0;
4227
4228 while ((ret == 0) && (cur != NULL)) {
4229 if ((cur->type == XML_RELAXNG_REF) ||
4230 (cur->type == XML_RELAXNG_PARENTREF)) {
4231 if (cur->depth == -1) {
4232 cur->depth = depth;
4233 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4234 cur->depth = -2;
4235 } else if (depth == cur->depth) {
4236 if (ctxt->error != NULL)
4237 ctxt->error(ctxt->userData,
4238 "Detected a cycle in %s references\n", cur->name);
4239 ctxt->nbErrors++;
4240 return(-1);
4241 }
4242 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4243 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4244 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004245 if (cur->content != NULL)
4246 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4247 if ((cur->cont2 != NULL) && (ret == 0))
4248 ret = xmlRelaxNGCheckCycles(ctxt, cur->cont2, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00004249 }
4250 cur = cur->next;
4251 }
4252 return(ret);
4253}
4254
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004255#if 0
Daniel Veillardd4310742003-02-18 21:12:46 +00004256/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00004257 * xmlRelaxNGTryUnlink:
4258 * @ctxt: a Relax-NG parser context
4259 * @cur: the definition to unlink
4260 * @parent: the parent definition
4261 * @prev: the previous sibling definition
4262 *
4263 * Try to unlink a definition. If not possble make it a NOOP
4264 *
4265 * Returns the new prev definition
4266 */
4267static xmlRelaxNGDefinePtr
4268xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4269 xmlRelaxNGDefinePtr cur,
4270 xmlRelaxNGDefinePtr parent,
4271 xmlRelaxNGDefinePtr prev) {
Daniel Veillard77648bb2003-02-20 15:03:22 +00004272}
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004273#endif
Daniel Veillard77648bb2003-02-20 15:03:22 +00004274
4275/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004276 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004277 * @ctxt: a Relax-NG parser context
4278 * @nodes: grammar children nodes
4279 *
4280 * Check for simplification of empty and notAllowed
4281 */
4282static void
4283xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4284 xmlRelaxNGDefinePtr cur,
4285 xmlRelaxNGDefinePtr parent) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004286 if ((cur == NULL) || (ctxt->nbErrors != 0))
4287 return;
4288 cur->parent = parent;
4289 if ((cur->type == XML_RELAXNG_REF) ||
4290 (cur->type == XML_RELAXNG_PARENTREF)) {
4291 if (cur->depth != -3) {
4292 cur->depth = -3;
4293 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4294 }
4295 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4296 if ((parent != NULL) &&
4297 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4298 (parent->type == XML_RELAXNG_LIST) ||
4299 (parent->type == XML_RELAXNG_GROUP) ||
4300 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4301 (parent->type == XML_RELAXNG_ONEORMORE))) {
4302 parent->type = XML_RELAXNG_NOT_ALLOWED;
4303 }
4304 } else if (cur->type == XML_RELAXNG_EMPTY){
4305 cur->parent = parent;
4306 if ((parent != NULL) &&
4307 (parent->type == XML_RELAXNG_ONEORMORE)) {
4308 parent->type = XML_RELAXNG_EMPTY;
4309 }
4310 } else if ((cur->type == XML_RELAXNG_GROUP) ||
4311 (cur->type == XML_RELAXNG_CHOICE) ||
4312 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4313 cur->parent = parent;
4314 if ((cur->cont2 != NULL) && (cur->content == NULL)) {
4315 cur->content = cur->cont2;
4316 cur->cont2 = NULL;
4317 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004318
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004319 if ((cur->cont2 == NULL) && (cur->content != NULL) &&
4320 (cur->content->next != NULL)) {
4321 xmlRelaxNGDefinePtr c, n, tmp;
4322
4323 c = cur;
4324 n = cur->content;
4325 while (n->next != NULL) {
4326 tmp = n->next;
4327
4328 n->next = NULL;
4329 n->parent = c;
4330 c->content = n;
4331
4332 n = tmp;
4333 if (n->next != NULL) {
4334 tmp = xmlRelaxNGNewDefine(ctxt, cur->node, cur->type);
4335 if (tmp != NULL) {
4336 c->cont2 = tmp;
4337 tmp->parent = c;
4338 c = tmp;
4339 c->content = n;
4340 } else {
4341 c->cont2 = tmp;
4342 }
4343 } else {
4344 c->cont2 = n;
4345 n->parent = c;
4346 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004347 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004348 }
4349
4350 if (cur->content != NULL)
4351 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4352 if (cur->cont2 != NULL)
4353 xmlRelaxNGSimplify(ctxt, cur->cont2, cur);
4354
4355 if ((cur->cont2 != NULL) && (cur->content == NULL)) {
4356 cur->content = cur->cont2;
4357 cur->cont2 = NULL;
4358 }
4359 if ((cur->content == NULL) && (cur->cont2 == NULL)) {
4360 cur->type = XML_RELAXNG_EMPTY;
4361 } else if (cur->cont2 == NULL) {
4362 xmlRelaxNGDefinePtr tmp = cur->content;
4363
4364 memcpy(cur, cur->content, sizeof(xmlRelaxNGDefine));
4365 memset(tmp, 0, sizeof(xmlRelaxNGDefine));
4366 } else if ((cur->type == XML_RELAXNG_GROUP) ||
4367 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4368 if ((cur->content != NULL) &&
4369 (cur->content->type == XML_RELAXNG_EMPTY)) {
4370 xmlRelaxNGDefinePtr tmp = cur->cont2;
4371
4372 memcpy(cur, cur->cont2, sizeof(xmlRelaxNGDefine));
4373 memset(tmp, 0, sizeof(xmlRelaxNGDefine));
4374 } else if ((cur->cont2 != NULL) &&
4375 (cur->cont2->type == XML_RELAXNG_EMPTY)) {
4376 xmlRelaxNGDefinePtr tmp = cur->content;
4377
4378 memcpy(cur, cur->content, sizeof(xmlRelaxNGDefine));
4379 memset(tmp, 0, sizeof(xmlRelaxNGDefine));
4380 } else if ((cur->content != NULL) &&
4381 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4382 cur->type = XML_RELAXNG_NOT_ALLOWED;
4383 } else if ((cur->cont2 != NULL) &&
4384 (cur->cont2->type == XML_RELAXNG_NOT_ALLOWED)) {
4385 cur->type = XML_RELAXNG_NOT_ALLOWED;
4386 }
4387 } else if (cur->type == XML_RELAXNG_CHOICE) {
4388 if ((cur->content != NULL) &&
4389 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4390 xmlRelaxNGDefinePtr tmp = cur->cont2;
4391
4392 memcpy(cur, cur->cont2, sizeof(xmlRelaxNGDefine));
4393 memset(tmp, 0, sizeof(xmlRelaxNGDefine));
4394 } else if ((cur->cont2 != NULL) &&
4395 (cur->cont2->type == XML_RELAXNG_NOT_ALLOWED)) {
4396 xmlRelaxNGDefinePtr tmp = cur->content;
4397
4398 memcpy(cur, cur->content, sizeof(xmlRelaxNGDefine));
4399 memset(tmp, 0, sizeof(xmlRelaxNGDefine));
4400 }
4401 }
4402 } else {
4403 cur->parent = parent;
4404 if (cur->content != NULL)
4405 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4406 if (cur->cont2 != NULL)
4407 xmlRelaxNGSimplify(ctxt, cur->cont2, cur);
4408 if (cur->nameClass != NULL)
4409 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
4410 /*
4411 * the current node may have been transformed back
4412 */
4413 if ((cur->type == XML_RELAXNG_EXCEPT) &&
4414 (cur->content != NULL) &&
4415 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4416 TODO
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004417 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4418 if ((parent != NULL) &&
4419 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4420 (parent->type == XML_RELAXNG_LIST) ||
4421 (parent->type == XML_RELAXNG_GROUP) ||
4422 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004423 (parent->type == XML_RELAXNG_ONEORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004424 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004425 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004426 } else if (cur->type == XML_RELAXNG_EMPTY){
4427 if ((parent != NULL) &&
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004428 (parent->type == XML_RELAXNG_ONEORMORE)) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004429 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004430 }
4431 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004432 }
4433}
4434
4435/**
4436 * xmlRelaxNGSimplifyRefs:
4437 * @ctxt: a Relax-NG parser context
4438 * @cur: the current define children nodes
4439 *
4440 * Check for the elimination of the DEF/REF references
4441 */
4442static void
4443xmlRelaxNGSimplifyRefs(xmlRelaxNGParserCtxtPtr ctxt,
4444 xmlRelaxNGDefinePtr cur) {
4445 if ((cur == NULL) || (ctxt->nbErrors != 0))
4446 return;
4447 if ((cur->content != NULL) &&
4448 ((cur->content->type == XML_RELAXNG_REF) ||
4449 (cur->content->type == XML_RELAXNG_PARENTREF))) {
4450 if ((cur->content->content != NULL) &&
4451 (cur->content->content->type == XML_RELAXNG_DEF) &&
4452 (cur->content->content->content != NULL))
4453 cur->content = cur->content->content->content;
4454 else {
4455 if (ctxt->error != NULL) {
4456 if (cur->content->name != NULL) {
4457 ctxt->error(ctxt->userData,
4458 "No target in %s reference\n", cur->content->name);
4459 } else {
4460 ctxt->error(ctxt->userData,
4461 "No target in reference\n");
4462 }
4463 }
4464 ctxt->nbErrors++;
4465 }
4466 }
4467 if ((cur->cont2 != NULL) &&
4468 ((cur->cont2->type == XML_RELAXNG_REF) ||
4469 (cur->cont2->type == XML_RELAXNG_PARENTREF))) {
4470 if ((cur->cont2->content != NULL) &&
4471 (cur->cont2->content->type == XML_RELAXNG_DEF) &&
4472 (cur->cont2->content->content != NULL))
4473 cur->cont2 = cur->cont2->content->content;
4474 else {
4475 if (ctxt->error != NULL) {
4476 if (cur->cont2->name != NULL) {
4477 ctxt->error(ctxt->userData,
4478 "No target in %s reference\n", cur->cont2->name);
4479 } else {
4480 ctxt->error(ctxt->userData,
4481 "No target in reference\n");
4482 }
4483 }
4484 ctxt->nbErrors++;
4485 }
4486 }
4487 if (cur->depth != -4) {
4488 cur->depth = -4;
4489 if (cur->content != NULL) xmlRelaxNGSimplifyRefs(ctxt, cur->content);
4490 if (cur->cont2 != NULL) xmlRelaxNGSimplifyRefs(ctxt, cur->cont2);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004491 }
4492}
4493
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004494/**
4495 * xmlRelaxNGGroupContentType:
4496 * @ct1: the first content type
4497 * @ct2: the second content type
4498 *
4499 * Try to group 2 content types
4500 *
4501 * Returns the content type
4502 */
4503static xmlRelaxNGContentType
4504xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
4505 xmlRelaxNGContentType ct2) {
4506 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4507 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4508 return(XML_RELAXNG_CONTENT_ERROR);
4509 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
4510 return(ct2);
4511 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
4512 return(ct1);
4513 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
4514 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4515 return(XML_RELAXNG_CONTENT_COMPLEX);
4516 return(XML_RELAXNG_CONTENT_ERROR);
4517}
4518
4519/**
4520 * xmlRelaxNGMaxContentType:
4521 * @ct1: the first content type
4522 * @ct2: the second content type
4523 *
4524 * Compute the max content-type
4525 *
4526 * Returns the content type
4527 */
4528static xmlRelaxNGContentType
4529xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
4530 xmlRelaxNGContentType ct2) {
4531 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4532 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4533 return(XML_RELAXNG_CONTENT_ERROR);
4534 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
4535 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
4536 return(XML_RELAXNG_CONTENT_SIMPLE);
4537 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
4538 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4539 return(XML_RELAXNG_CONTENT_COMPLEX);
4540 return(XML_RELAXNG_CONTENT_EMPTY);
4541}
Daniel Veillard77648bb2003-02-20 15:03:22 +00004542
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004543/**
4544 * xmlRelaxNGCheckRules:
4545 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004546 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00004547 * @flags: some accumulated flags
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004548 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004549 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004550 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004551 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004552 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004553static xmlRelaxNGContentType
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004554xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
4555 xmlRelaxNGDefinePtr cur, int flags)
4556{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004557 int nflags = flags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004558 xmlRelaxNGContentType ret, tmp;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004559
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004560 ret = XML_RELAXNG_CONTENT_EMPTY;
4561 if (cur == NULL)
4562 return (ret);
4563 switch (cur->type) {
4564 case XML_RELAXNG_REF:
4565 case XML_RELAXNG_PARENTREF:
4566 if (flags & XML_RELAXNG_IN_LIST) {
4567 if (ctxt->error != NULL)
4568 ctxt->error(ctxt->userData,
4569 "Found forbidden pattern list//ref\n");
4570 ctxt->nbErrors++;
4571 }
4572 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4573 if (ctxt->error != NULL)
4574 ctxt->error(ctxt->userData,
4575 "Found forbidden pattern data/except//ref\n");
4576 ctxt->nbErrors++;
4577 }
4578 if (cur->depth > -4) {
4579 cur->depth = -4;
4580 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4581 cur->depth = ret - 15;
4582 } else if (cur->depth == -4) {
4583 ret = XML_RELAXNG_CONTENT_COMPLEX;
4584 } else {
4585 ret = (xmlRelaxNGContentType) cur->depth + 15;
4586 }
4587 break;
4588 case XML_RELAXNG_ELEMENT:
4589 /*
4590 * The 7.3 Attribute derivation rule for groups is plugged there
4591 */
4592 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4593 if (ctxt->error != NULL)
4594 ctxt->error(ctxt->userData,
4595 "Found forbidden pattern data/except//element(ref)\n");
4596 ctxt->nbErrors++;
4597 }
4598 if (flags & XML_RELAXNG_IN_LIST) {
4599 if (ctxt->error != NULL)
4600 ctxt->error(ctxt->userData,
4601 "Found forbidden pattern list//element(ref)\n");
4602 ctxt->nbErrors++;
4603 }
4604 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4605 if (ctxt->error != NULL)
4606 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00004607 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004608 ctxt->nbErrors++;
4609 }
4610 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4611 if (ctxt->error != NULL)
4612 ctxt->error(ctxt->userData,
4613 "Found forbidden pattern attribute//element(ref)\n");
4614 ctxt->nbErrors++;
4615 }
4616 /*
4617 * reset since in the simple form elements are only child
4618 * of grammar/define
4619 */
4620 nflags = 0;
4621 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4622 if (ret == XML_RELAXNG_CONTENT_ERROR) {
4623 if (ctxt->error != NULL)
4624 ctxt->error(ctxt->userData,
4625 "Element %s has a content type error\n",
4626 cur->name);
4627 ctxt->nbErrors++;
4628 } else {
4629 ret = XML_RELAXNG_CONTENT_COMPLEX;
4630 }
4631 break;
4632 case XML_RELAXNG_ATTRIBUTE:
4633 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4634 if (ctxt->error != NULL)
4635 ctxt->error(ctxt->userData,
4636 "Found forbidden pattern attribute//attribute\n");
4637 ctxt->nbErrors++;
4638 }
4639 if (flags & XML_RELAXNG_IN_LIST) {
4640 if (ctxt->error != NULL)
4641 ctxt->error(ctxt->userData,
4642 "Found forbidden pattern list//attribute\n");
4643 ctxt->nbErrors++;
4644 }
4645 if (flags & XML_RELAXNG_IN_OOMGROUP) {
4646 if (ctxt->error != NULL)
4647 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004648 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004649 ctxt->nbErrors++;
4650 }
4651 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
4652 if (ctxt->error != NULL)
4653 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004654 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004655 ctxt->nbErrors++;
4656 }
4657 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4658 if (ctxt->error != NULL)
4659 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004660 "Found forbidden pattern data/except//attribute\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004661 ctxt->nbErrors++;
4662 }
4663 if (flags & XML_RELAXNG_IN_START) {
4664 if (ctxt->error != NULL)
4665 ctxt->error(ctxt->userData,
4666 "Found forbidden pattern start//attribute\n");
4667 ctxt->nbErrors++;
4668 }
4669 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
4670 if (cur->ns == NULL) {
4671 if (ctxt->error != NULL)
4672 ctxt->error(ctxt->userData,
4673 "Found anyName attribute without oneOrMore ancestor\n");
4674 ctxt->nbErrors++;
4675 } else {
4676 if (ctxt->error != NULL)
4677 ctxt->error(ctxt->userData,
4678 "Found nsName attribute without oneOrMore ancestor\n");
4679 ctxt->nbErrors++;
4680 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00004681 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004682 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
4683 xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4684 ret = XML_RELAXNG_CONTENT_EMPTY;
4685 break;
4686 case XML_RELAXNG_ONEORMORE:
4687 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4688 if (ctxt->error != NULL)
4689 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004690 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004691 ctxt->nbErrors++;
4692 }
4693 if (flags & XML_RELAXNG_IN_START) {
4694 if (ctxt->error != NULL)
4695 ctxt->error(ctxt->userData,
4696 "Found forbidden pattern start//oneOrMore\n");
4697 ctxt->nbErrors++;
4698 }
4699 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
4700 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4701 ret = xmlRelaxNGGroupContentType(ret, ret);
4702 break;
4703 case XML_RELAXNG_LIST:
4704 if (flags & XML_RELAXNG_IN_LIST) {
4705 if (ctxt->error != NULL)
4706 ctxt->error(ctxt->userData,
4707 "Found forbidden pattern list//list\n");
4708 ctxt->nbErrors++;
4709 }
4710 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4711 if (ctxt->error != NULL)
4712 ctxt->error(ctxt->userData,
4713 "Found forbidden pattern data/except//list\n");
4714 ctxt->nbErrors++;
4715 }
4716 if (flags & XML_RELAXNG_IN_START) {
4717 if (ctxt->error != NULL)
4718 ctxt->error(ctxt->userData,
4719 "Found forbidden pattern start//list\n");
4720 ctxt->nbErrors++;
4721 }
4722 nflags = flags | XML_RELAXNG_IN_LIST;
4723 xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4724 ret = XML_RELAXNG_CONTENT_SIMPLE;
4725 break;
4726 case XML_RELAXNG_GROUP:
4727 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4728 if (ctxt->error != NULL)
4729 ctxt->error(ctxt->userData,
4730 "Found forbidden pattern data/except//group\n");
4731 ctxt->nbErrors++;
4732 }
4733 if (flags & XML_RELAXNG_IN_START) {
4734 if (ctxt->error != NULL)
4735 ctxt->error(ctxt->userData,
4736 "Found forbidden pattern start//group\n");
4737 ctxt->nbErrors++;
4738 }
4739 if (flags & XML_RELAXNG_IN_ONEORMORE)
4740 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
4741 else
4742 nflags = flags;
4743 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4744 tmp = xmlRelaxNGCheckRules(ctxt, cur->cont2, nflags);
4745 ret = xmlRelaxNGGroupContentType(ret, tmp);
4746 /*
4747 * The 7.3 Attribute derivation rule for groups is plugged there
4748 */
4749 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4750 break;
4751 case XML_RELAXNG_INTERLEAVE:
4752 if (flags & XML_RELAXNG_IN_LIST) {
4753 if (ctxt->error != NULL)
4754 ctxt->error(ctxt->userData,
4755 "Found forbidden pattern list//interleave\n");
4756 ctxt->nbErrors++;
4757 }
4758 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4759 if (ctxt->error != NULL)
4760 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00004761 "Found forbidden pattern data/except//interleave\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004762 ctxt->nbErrors++;
4763 }
4764 if (flags & XML_RELAXNG_IN_START) {
4765 if (ctxt->error != NULL)
4766 ctxt->error(ctxt->userData,
4767 "Found forbidden pattern start//interleave\n");
4768 ctxt->nbErrors++;
4769 }
4770 if (flags & XML_RELAXNG_IN_ONEORMORE)
4771 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
4772 else
4773 nflags = flags;
4774 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4775 tmp = xmlRelaxNGCheckRules(ctxt, cur->cont2, nflags);
4776 ret = xmlRelaxNGMaxContentType(tmp, ret);
4777 /*
4778 * The 7.3 Attribute derivation rule for groups is plugged there
4779 */
4780 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4781 xmlRelaxNGCheckInterleave(ctxt, cur);
4782 break;
4783 case XML_RELAXNG_EXCEPT:
4784 if ((cur->parent != NULL) &&
4785 (cur->parent->type == XML_RELAXNG_DATATYPE))
4786 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
4787 else
4788 nflags = flags;
4789 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags);
4790 break;
4791 case XML_RELAXNG_DATATYPE:
4792 if (flags & XML_RELAXNG_IN_START) {
4793 if (ctxt->error != NULL)
4794 ctxt->error(ctxt->userData,
4795 "Found forbidden pattern start//data\n");
4796 ctxt->nbErrors++;
4797 }
4798 xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4799 ret = XML_RELAXNG_CONTENT_SIMPLE;
4800 break;
4801 case XML_RELAXNG_VALUE:
4802 if (flags & XML_RELAXNG_IN_START) {
4803 if (ctxt->error != NULL)
4804 ctxt->error(ctxt->userData,
4805 "Found forbidden pattern start//value\n");
4806 ctxt->nbErrors++;
4807 }
4808 xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4809 ret = XML_RELAXNG_CONTENT_SIMPLE;
4810 break;
4811 case XML_RELAXNG_TEXT:
4812 if (flags & XML_RELAXNG_IN_LIST) {
4813 if (ctxt->error != NULL)
4814 ctxt->error(ctxt->userData,
4815 "Found forbidden pattern list//text\n");
4816 ctxt->nbErrors++;
4817 }
4818 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4819 if (ctxt->error != NULL)
4820 ctxt->error(ctxt->userData,
4821 "Found forbidden pattern data/except//text\n");
4822 ctxt->nbErrors++;
4823 }
4824 if (flags & XML_RELAXNG_IN_START) {
4825 if (ctxt->error != NULL)
4826 ctxt->error(ctxt->userData,
4827 "Found forbidden pattern start//text\n");
4828 ctxt->nbErrors++;
4829 }
4830 ret = XML_RELAXNG_CONTENT_COMPLEX;
4831 break;
4832 case XML_RELAXNG_EMPTY:
4833 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4834 if (ctxt->error != NULL)
4835 ctxt->error(ctxt->userData,
4836 "Found forbidden pattern data/except//empty\n");
4837 ctxt->nbErrors++;
4838 }
4839 if (flags & XML_RELAXNG_IN_START) {
4840 if (ctxt->error != NULL)
4841 ctxt->error(ctxt->userData,
4842 "Found forbidden pattern start//empty\n");
4843 ctxt->nbErrors++;
4844 }
4845 ret = XML_RELAXNG_CONTENT_EMPTY;
4846 break;
4847 case XML_RELAXNG_CHOICE:
4848 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4849 tmp = xmlRelaxNGCheckRules(ctxt, cur->cont2, flags);
4850 ret = xmlRelaxNGMaxContentType(tmp, ret);
4851 break;
4852 case XML_RELAXNG_NOT_ALLOWED:
4853 ret = XML_RELAXNG_CONTENT_EMPTY;
4854 break;
4855 case XML_RELAXNG_PARAM:
4856 ret = XML_RELAXNG_CONTENT_EMPTY;
4857 break;
4858 case XML_RELAXNG_DEF:
4859 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4860 break;
4861 case XML_RELAXNG_EXTERNALREF:
4862 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4863 break;
4864 case XML_RELAXNG_START:
4865 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags);
4866 break;
4867 case XML_RELAXNG_AFTER:
4868 ret = XML_RELAXNG_CONTENT_ERROR;
4869 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004870 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004871 return (ret);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004872}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004873
4874/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004875 * xmlRelaxNGParseGrammar:
4876 * @ctxt: a Relax-NG parser context
4877 * @nodes: grammar children nodes
4878 *
4879 * parse a Relax-NG <grammar> node
4880 *
4881 * Returns the internal xmlRelaxNGGrammarPtr built or
4882 * NULL in case of error
4883 */
4884static xmlRelaxNGGrammarPtr
4885xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4886 xmlRelaxNGGrammarPtr ret, tmp, old;
4887
Daniel Veillardc482e262003-02-26 14:48:48 +00004888#ifdef DEBUG_GRAMMAR
4889 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
4890#endif
4891
Daniel Veillard6eadf632003-01-23 18:29:16 +00004892 ret = xmlRelaxNGNewGrammar(ctxt);
4893 if (ret == NULL)
4894 return(NULL);
4895
4896 /*
4897 * Link the new grammar in the tree
4898 */
4899 ret->parent = ctxt->grammar;
4900 if (ctxt->grammar != NULL) {
4901 tmp = ctxt->grammar->children;
4902 if (tmp == NULL) {
4903 ctxt->grammar->children = ret;
4904 } else {
4905 while (tmp->next != NULL)
4906 tmp = tmp->next;
4907 tmp->next = ret;
4908 }
4909 }
4910
4911 old = ctxt->grammar;
4912 ctxt->grammar = ret;
4913 xmlRelaxNGParseGrammarContent(ctxt, nodes);
4914 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004915 if (ctxt->grammar == NULL) {
4916 if (ctxt->error != NULL)
4917 ctxt->error(ctxt->userData,
4918 "Failed to parse <grammar> content\n");
4919 ctxt->nbErrors++;
4920 } else if (ctxt->grammar->start == NULL) {
4921 if (ctxt->error != NULL)
4922 ctxt->error(ctxt->userData,
4923 "Element <grammar> has no <start>\n");
4924 ctxt->nbErrors++;
4925 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004926
4927 /*
4928 * Apply 4.17 mergingd rules to defines and starts
4929 */
4930 xmlRelaxNGCombineStart(ctxt, ret);
4931 if (ret->defs != NULL) {
4932 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
4933 ctxt);
4934 }
4935
4936 /*
4937 * link together defines and refs in this grammar
4938 */
4939 if (ret->refs != NULL) {
4940 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
4941 ctxt);
4942 }
4943 ctxt->grammar = old;
4944 return(ret);
4945}
4946
4947/**
4948 * xmlRelaxNGParseDocument:
4949 * @ctxt: a Relax-NG parser context
4950 * @node: the root node of the RelaxNG schema
4951 *
4952 * parse a Relax-NG definition resource and build an internal
4953 * xmlRelaxNG struture which can be used to validate instances.
4954 *
4955 * Returns the internal XML RelaxNG structure built or
4956 * NULL in case of error
4957 */
4958static xmlRelaxNGPtr
4959xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4960 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004961 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00004962 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004963
4964 if ((ctxt == NULL) || (node == NULL))
4965 return (NULL);
4966
4967 schema = xmlRelaxNGNewRelaxNG(ctxt);
4968 if (schema == NULL)
4969 return(NULL);
4970
Daniel Veillard276be4a2003-01-24 01:03:34 +00004971 olddefine = ctxt->define;
4972 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004973 if (IS_RELAXNG(node, "grammar")) {
4974 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4975 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00004976 xmlRelaxNGGrammarPtr tmp, ret;
4977
4978 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004979 if (schema->topgrammar == NULL) {
4980 return(schema);
4981 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004982 /*
4983 * Link the new grammar in the tree
4984 */
4985 ret->parent = ctxt->grammar;
4986 if (ctxt->grammar != NULL) {
4987 tmp = ctxt->grammar->children;
4988 if (tmp == NULL) {
4989 ctxt->grammar->children = ret;
4990 } else {
4991 while (tmp->next != NULL)
4992 tmp = tmp->next;
4993 tmp->next = ret;
4994 }
4995 }
Daniel Veillarde431a272003-01-29 23:02:33 +00004996 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00004997 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004998 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00004999 if (old != NULL)
5000 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005001 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005002 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005003 if (schema->topgrammar->start != NULL) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005004 xmlRelaxNGDefinePtr start;
5005
5006 start = schema->topgrammar->start;
5007
5008 xmlRelaxNGCheckCycles(ctxt, start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005009 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005010
5011 xmlRelaxNGSimplify(ctxt, start, NULL);
5012 xmlRelaxNGCheckRules(ctxt, start, XML_RELAXNG_IN_START);
5013 xmlRelaxNGSimplifyRefs(ctxt, start);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005014 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005015 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005016
5017#ifdef DEBUG
5018 if (schema == NULL)
5019 xmlGenericError(xmlGenericErrorContext,
5020 "xmlRelaxNGParseDocument() failed\n");
5021#endif
5022
5023 return (schema);
5024}
5025
5026/************************************************************************
5027 * *
5028 * Reading RelaxNGs *
5029 * *
5030 ************************************************************************/
5031
5032/**
5033 * xmlRelaxNGNewParserCtxt:
5034 * @URL: the location of the schema
5035 *
5036 * Create an XML RelaxNGs parse context for that file/resource expected
5037 * to contain an XML RelaxNGs file.
5038 *
5039 * Returns the parser context or NULL in case of error
5040 */
5041xmlRelaxNGParserCtxtPtr
5042xmlRelaxNGNewParserCtxt(const char *URL) {
5043 xmlRelaxNGParserCtxtPtr ret;
5044
5045 if (URL == NULL)
5046 return(NULL);
5047
5048 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5049 if (ret == NULL) {
5050 xmlGenericError(xmlGenericErrorContext,
5051 "Failed to allocate new schama parser context for %s\n", URL);
5052 return (NULL);
5053 }
5054 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5055 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005056 ret->error = xmlGenericError;
5057 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005058 return (ret);
5059}
5060
5061/**
5062 * xmlRelaxNGNewMemParserCtxt:
5063 * @buffer: a pointer to a char array containing the schemas
5064 * @size: the size of the array
5065 *
5066 * Create an XML RelaxNGs parse context for that memory buffer expected
5067 * to contain an XML RelaxNGs file.
5068 *
5069 * Returns the parser context or NULL in case of error
5070 */
5071xmlRelaxNGParserCtxtPtr
5072xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5073 xmlRelaxNGParserCtxtPtr ret;
5074
5075 if ((buffer == NULL) || (size <= 0))
5076 return(NULL);
5077
5078 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5079 if (ret == NULL) {
5080 xmlGenericError(xmlGenericErrorContext,
5081 "Failed to allocate new schama parser context\n");
5082 return (NULL);
5083 }
5084 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5085 ret->buffer = buffer;
5086 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005087 ret->error = xmlGenericError;
5088 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005089 return (ret);
5090}
5091
5092/**
5093 * xmlRelaxNGFreeParserCtxt:
5094 * @ctxt: the schema parser context
5095 *
5096 * Free the resources associated to the schema parser context
5097 */
5098void
5099xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5100 if (ctxt == NULL)
5101 return;
5102 if (ctxt->URL != NULL)
5103 xmlFree(ctxt->URL);
5104 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005105 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005106 if (ctxt->interleaves != NULL)
5107 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005108 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005109 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005110 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005111 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005112 if (ctxt->docTab != NULL)
5113 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005114 if (ctxt->incTab != NULL)
5115 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005116 if (ctxt->defTab != NULL) {
5117 int i;
5118
5119 for (i = 0;i < ctxt->defNr;i++)
5120 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5121 xmlFree(ctxt->defTab);
5122 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005123 xmlFree(ctxt);
5124}
5125
Daniel Veillard6eadf632003-01-23 18:29:16 +00005126/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005127 * xmlRelaxNGNormExtSpace:
5128 * @value: a value
5129 *
5130 * Removes the leading and ending spaces of the value
5131 * The string is modified "in situ"
5132 */
5133static void
5134xmlRelaxNGNormExtSpace(xmlChar *value) {
5135 xmlChar *start = value;
5136 xmlChar *cur = value;
5137 if (value == NULL)
5138 return;
5139
5140 while (IS_BLANK(*cur)) cur++;
5141 if (cur == start) {
5142 do {
5143 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5144 if (*cur == 0)
5145 return;
5146 start = cur;
5147 while (IS_BLANK(*cur)) cur++;
5148 if (*cur == 0) {
5149 *start = 0;
5150 return;
5151 }
5152 } while (1);
5153 } else {
5154 do {
5155 while ((*cur != 0) && (!IS_BLANK(*cur)))
5156 *start++ = *cur++;
5157 if (*cur == 0) {
5158 *start = 0;
5159 return;
5160 }
5161 /* don't try to normalize the inner spaces */
5162 while (IS_BLANK(*cur)) cur++;
5163 *start++ = *cur++;
5164 if (*cur == 0) {
5165 *start = 0;
5166 return;
5167 }
5168 } while (1);
5169 }
5170}
5171
5172/**
5173 * xmlRelaxNGCheckAttributes:
5174 * @ctxt: a Relax-NG parser context
5175 * @node: a Relax-NG node
5176 *
5177 * Check all the attributes on the given node
5178 */
5179static void
5180xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5181 xmlAttrPtr cur, next;
5182
5183 cur = node->properties;
5184 while (cur != NULL) {
5185 next = cur->next;
5186 if ((cur->ns == NULL) ||
5187 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5188 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5189 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5190 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5191 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5192 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005193 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005194 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5195 if (ctxt->error != NULL)
5196 ctxt->error(ctxt->userData,
5197 "Attribute %s is not allowed on %s\n",
5198 cur->name, node->name);
5199 ctxt->nbErrors++;
5200 }
5201 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5202 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5203 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5204 if (ctxt->error != NULL)
5205 ctxt->error(ctxt->userData,
5206 "Attribute %s is not allowed on %s\n",
5207 cur->name, node->name);
5208 ctxt->nbErrors++;
5209 }
5210 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
5211 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
5212 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
5213 if (ctxt->error != NULL)
5214 ctxt->error(ctxt->userData,
5215 "Attribute %s is not allowed on %s\n",
5216 cur->name, node->name);
5217 ctxt->nbErrors++;
5218 }
5219 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
5220 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
5221 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5222 if (ctxt->error != NULL)
5223 ctxt->error(ctxt->userData,
5224 "Attribute %s is not allowed on %s\n",
5225 cur->name, node->name);
5226 ctxt->nbErrors++;
5227 }
5228 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
5229 xmlChar *val;
5230 xmlURIPtr uri;
5231
5232 val = xmlNodeListGetString(node->doc, cur->children, 1);
5233 if (val != NULL) {
5234 if (val[0] != 0) {
5235 uri = xmlParseURI((const char *) val);
5236 if (uri == NULL) {
5237 if (ctxt->error != NULL)
5238 ctxt->error(ctxt->userData,
5239 "Attribute %s contains invalid URI %s\n",
5240 cur->name, val);
5241 ctxt->nbErrors++;
5242 } else {
5243 if (uri->scheme == NULL) {
5244 if (ctxt->error != NULL)
5245 ctxt->error(ctxt->userData,
5246 "Attribute %s URI %s is not absolute\n",
5247 cur->name, val);
5248 ctxt->nbErrors++;
5249 }
5250 if (uri->fragment != NULL) {
5251 if (ctxt->error != NULL)
5252 ctxt->error(ctxt->userData,
5253 "Attribute %s URI %s has a fragment ID\n",
5254 cur->name, val);
5255 ctxt->nbErrors++;
5256 }
5257 xmlFreeURI(uri);
5258 }
5259 }
5260 xmlFree(val);
5261 }
5262 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
5263 if (ctxt->error != NULL)
5264 ctxt->error(ctxt->userData,
5265 "Unknown attribute %s on %s\n",
5266 cur->name, node->name);
5267 ctxt->nbErrors++;
5268 }
5269 }
5270 cur = next;
5271 }
5272}
5273
5274/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005275 * xmlRelaxNGCleanupBlanks:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005276 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00005277 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00005278 *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005279 * Cleanup the subtree from unwanted nodes for parsing, i.e. foreign
5280 * namespaces and blanks nodes per rules 4.1 and 4.2
Daniel Veillard6eadf632003-01-23 18:29:16 +00005281 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005282static void
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005283xmlRelaxNGCleanupBlanks(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00005284 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005285
Daniel Veillard6eadf632003-01-23 18:29:16 +00005286 delete = NULL;
5287 cur = root;
5288 while (cur != NULL) {
5289 if (delete != NULL) {
5290 xmlUnlinkNode(delete);
5291 xmlFreeNode(delete);
5292 delete = NULL;
5293 }
5294 if (cur->type == XML_ELEMENT_NODE) {
5295 /*
5296 * Simplification 4.1. Annotations
5297 */
5298 if ((cur->ns == NULL) ||
5299 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00005300 if ((cur->parent != NULL) &&
5301 (cur->parent->type == XML_ELEMENT_NODE) &&
5302 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
5303 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
5304 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
5305 if (ctxt->error != NULL)
5306 ctxt->error(ctxt->userData,
5307 "element %s doesn't allow foreign elements\n",
5308 cur->parent->name);
5309 ctxt->nbErrors++;
5310 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005311 delete = cur;
5312 goto skip_children;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005313 }
5314 }
5315 /*
5316 * Simplification 4.2 whitespaces
5317 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00005318 else if ((cur->type == XML_TEXT_NODE) ||
5319 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005320 if (IS_BLANK_NODE(cur)) {
5321 if (cur->parent->type == XML_ELEMENT_NODE) {
5322 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
5323 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
5324 delete = cur;
5325 } else {
5326 delete = cur;
5327 goto skip_children;
5328 }
5329 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00005330 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005331 delete = cur;
5332 goto skip_children;
5333 }
5334
5335 /*
5336 * Skip to next node
5337 */
5338 if (cur->children != NULL) {
5339 if ((cur->children->type != XML_ENTITY_DECL) &&
5340 (cur->children->type != XML_ENTITY_REF_NODE) &&
5341 (cur->children->type != XML_ENTITY_NODE)) {
5342 cur = cur->children;
5343 continue;
5344 }
5345 }
5346skip_children:
5347 if (cur->next != NULL) {
5348 cur = cur->next;
5349 continue;
5350 }
5351
5352 do {
5353 cur = cur->parent;
5354 if (cur == NULL)
5355 break;
5356 if (cur == root) {
5357 cur = NULL;
5358 break;
5359 }
5360 if (cur->next != NULL) {
5361 cur = cur->next;
5362 break;
5363 }
5364 } while (cur != NULL);
5365 }
5366 if (delete != NULL) {
5367 xmlUnlinkNode(delete);
5368 xmlFreeNode(delete);
5369 delete = NULL;
5370 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00005371}
Daniel Veillard6eadf632003-01-23 18:29:16 +00005372
Daniel Veillardc5312d72003-02-21 17:14:10 +00005373/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005374 * xmlRelaxNGCleanupTree:
5375 * @ctxt: a Relax-NG parser context
5376 * @root: an xmlNodePtr subtree
5377 *
5378 * Cleanup the subtree from unwanted nodes for parsing, resolve
5379 * Include and externalRef lookups.
5380 */
5381static void
5382xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
5383 xmlNodePtr cur, delete;
5384
5385 delete = NULL;
5386 cur = root;
5387 while (cur != NULL) {
5388 if (delete != NULL) {
5389 xmlUnlinkNode(delete);
5390 xmlFreeNode(delete);
5391 delete = NULL;
5392 }
5393 if (cur->type == XML_ELEMENT_NODE) {
5394 xmlRelaxNGCleanupAttributes(ctxt, cur);
5395
5396 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
5397 xmlChar *href, *ns, *base, *URL;
5398 xmlRelaxNGDocumentPtr docu;
5399 xmlNodePtr tmp;
5400
5401 ns = xmlGetProp(cur, BAD_CAST "ns");
5402 if (ns == NULL) {
5403 tmp = cur->parent;
5404 while ((tmp != NULL) &&
5405 (tmp->type == XML_ELEMENT_NODE)) {
5406 ns = xmlGetProp(tmp, BAD_CAST "ns");
5407 if (ns != NULL)
5408 break;
5409 tmp = tmp->parent;
5410 }
5411 }
5412 href = xmlGetProp(cur, BAD_CAST "href");
5413 if (href == NULL) {
5414 if (ctxt->error != NULL)
5415 ctxt->error(ctxt->userData,
5416 "xmlRelaxNGParse: externalRef has no href attribute\n");
5417 ctxt->nbErrors++;
5418 delete = cur;
5419 goto skip_children;
5420 }
5421 base = xmlNodeGetBase(cur->doc, cur);
5422 URL = xmlBuildURI(href, base);
5423 if (URL == NULL) {
5424 if (ctxt->error != NULL)
5425 ctxt->error(ctxt->userData,
5426 "Failed to compute URL for externalRef %s\n", href);
5427 ctxt->nbErrors++;
5428 if (href != NULL)
5429 xmlFree(href);
5430 if (base != NULL)
5431 xmlFree(base);
5432 delete = cur;
5433 goto skip_children;
5434 }
5435 if (href != NULL)
5436 xmlFree(href);
5437 if (base != NULL)
5438 xmlFree(base);
5439 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
5440 if (docu == NULL) {
5441 if (ctxt->error != NULL)
5442 ctxt->error(ctxt->userData,
5443 "Failed to load externalRef %s\n", URL);
5444 ctxt->nbErrors++;
5445 xmlFree(URL);
5446 delete = cur;
5447 goto skip_children;
5448 }
5449 if (ns != NULL)
5450 xmlFree(ns);
5451 xmlFree(URL);
5452 cur->_private = docu;
5453 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5454 xmlChar *href, *ns, *base, *URL;
5455 xmlRelaxNGIncludePtr incl;
5456 xmlNodePtr tmp;
5457
5458 href = xmlGetProp(cur, BAD_CAST "href");
5459 if (href == NULL) {
5460 if (ctxt->error != NULL)
5461 ctxt->error(ctxt->userData,
5462 "xmlRelaxNGParse: include has no href attribute\n");
5463 ctxt->nbErrors++;
5464 delete = cur;
5465 goto skip_children;
5466 }
5467 base = xmlNodeGetBase(cur->doc, cur);
5468 URL = xmlBuildURI(href, base);
5469 if (URL == NULL) {
5470 if (ctxt->error != NULL)
5471 ctxt->error(ctxt->userData,
5472 "Failed to compute URL for include %s\n", href);
5473 ctxt->nbErrors++;
5474 if (href != NULL)
5475 xmlFree(href);
5476 if (base != NULL)
5477 xmlFree(base);
5478 delete = cur;
5479 goto skip_children;
5480 }
5481 if (href != NULL)
5482 xmlFree(href);
5483 if (base != NULL)
5484 xmlFree(base);
5485 ns = xmlGetProp(cur, BAD_CAST "ns");
5486 if (ns == NULL) {
5487 tmp = cur->parent;
5488 while ((tmp != NULL) &&
5489 (tmp->type == XML_ELEMENT_NODE)) {
5490 ns = xmlGetProp(tmp, BAD_CAST "ns");
5491 if (ns != NULL)
5492 break;
5493 tmp = tmp->parent;
5494 }
5495 }
5496 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5497 if (ns != NULL)
5498 xmlFree(ns);
5499 if (incl == NULL) {
5500 if (ctxt->error != NULL)
5501 ctxt->error(ctxt->userData,
5502 "Failed to load include %s\n", URL);
5503 ctxt->nbErrors++;
5504 xmlFree(URL);
5505 delete = cur;
5506 goto skip_children;
5507 }
5508 xmlFree(URL);
5509 cur->_private = incl;
5510 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5511 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
5512 xmlChar *name, *ns;
5513 xmlNodePtr text = NULL;
5514
5515 /*
5516 * Simplification 4.8. name attribute of element
5517 * and attribute elements
5518 */
5519 name = xmlGetProp(cur, BAD_CAST "name");
5520 if (name != NULL) {
5521 if (cur->children == NULL) {
5522 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5523 name);
5524 } else {
5525 xmlNodePtr node;
5526 node = xmlNewNode(cur->ns, BAD_CAST "name");
5527 if (node != NULL) {
5528 xmlAddPrevSibling(cur->children, node);
5529 text = xmlNewText(name);
5530 xmlAddChild(node, text);
5531 text = node;
5532 }
5533 }
5534 if (text == NULL) {
5535 if (ctxt->error != NULL)
5536 ctxt->error(ctxt->userData,
5537 "Failed to create a name %s element\n", name);
5538 ctxt->nbErrors++;
5539 }
5540 xmlUnsetProp(cur, BAD_CAST "name");
5541 xmlFree(name);
5542 ns = xmlGetProp(cur, BAD_CAST "ns");
5543 if (ns != NULL) {
5544 if (text != NULL) {
5545 xmlSetProp(text, BAD_CAST "ns", ns);
5546 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
5547 }
5548 xmlFree(ns);
5549 } else if (xmlStrEqual(cur->name,
5550 BAD_CAST "attribute")) {
5551 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
5552 }
5553 }
5554 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
5555 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
5556 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
5557 /*
5558 * Simplification 4.8. name attribute of element
5559 * and attribute elements
5560 */
5561 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
5562 xmlNodePtr node;
5563 xmlChar *ns = NULL;
5564
5565 node = cur->parent;
5566 while ((node != NULL) &&
5567 (node->type == XML_ELEMENT_NODE)) {
5568 ns = xmlGetProp(node, BAD_CAST "ns");
5569 if (ns != NULL) {
5570 break;
5571 }
5572 node = node->parent;
5573 }
5574 if (ns == NULL) {
5575 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
5576 } else {
5577 xmlSetProp(cur, BAD_CAST "ns", ns);
5578 xmlFree(ns);
5579 }
5580 }
5581 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5582 xmlChar *name, *local, *prefix;
5583
5584 /*
5585 * Simplification: 4.10. QNames
5586 */
5587 name = xmlNodeGetContent(cur);
5588 if (name != NULL) {
5589 local = xmlSplitQName2(name, &prefix);
5590 if (local != NULL) {
5591 xmlNsPtr ns;
5592
5593 ns = xmlSearchNs(cur->doc, cur, prefix);
5594 if (ns == NULL) {
5595 if (ctxt->error != NULL)
5596 ctxt->error(ctxt->userData,
5597 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
5598 ctxt->nbErrors++;
5599 } else {
5600 xmlSetProp(cur, BAD_CAST "ns", ns->href);
5601 xmlNodeSetContent(cur, local);
5602 }
5603 xmlFree(local);
5604 xmlFree(prefix);
5605 }
5606 xmlFree(name);
5607 }
5608 }
5609 /*
5610 * 4.16
5611 */
5612 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
5613 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5614 if (ctxt->error != NULL)
5615 ctxt->error(ctxt->userData,
5616 "Found nsName/except//nsName forbidden construct\n");
5617 ctxt->nbErrors++;
5618 }
5619 }
5620 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
5621 (cur != root)) {
5622 int oldflags = ctxt->flags;
5623
5624 /*
5625 * 4.16
5626 */
5627 if ((cur->parent != NULL) &&
5628 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
5629 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
5630 xmlRelaxNGCleanupTree(ctxt, cur);
5631 ctxt->flags = oldflags;
5632 goto skip_children;
5633 } else if ((cur->parent != NULL) &&
5634 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
5635 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
5636 xmlRelaxNGCleanupTree(ctxt, cur);
5637 ctxt->flags = oldflags;
5638 goto skip_children;
5639 }
5640 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
5641 /*
5642 * 4.16
5643 */
5644 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
5645 if (ctxt->error != NULL)
5646 ctxt->error(ctxt->userData,
5647 "Found anyName/except//anyName forbidden construct\n");
5648 ctxt->nbErrors++;
5649 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5650 if (ctxt->error != NULL)
5651 ctxt->error(ctxt->userData,
5652 "Found nsName/except//anyName forbidden construct\n");
5653 ctxt->nbErrors++;
5654 }
5655 }
5656 /*
5657 * Thisd is not an else since "include" is transformed
5658 * into a div
5659 */
5660 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
5661 xmlChar *ns;
5662 xmlNodePtr child, ins, tmp;
5663
5664 /*
5665 * implements rule 4.11
5666 */
5667
5668 ns = xmlGetProp(cur, BAD_CAST "ns");
5669
5670 child = cur->children;
5671 ins = cur;
5672 while (child != NULL) {
5673 if (ns != NULL) {
5674 if (!xmlHasProp(child, BAD_CAST "ns")) {
5675 xmlSetProp(child, BAD_CAST "ns", ns);
5676 }
5677 }
5678 tmp = child->next;
5679 xmlUnlinkNode(child);
5680 ins = xmlAddNextSibling(ins, child);
5681 child = tmp;
5682 }
5683 if (ns != NULL)
5684 xmlFree(ns);
5685 delete = cur;
5686 goto skip_children;
5687 }
5688
5689 /*
5690 * Simplifications on 4.12
5691 */
5692 if ((xmlStrEqual(cur->name, BAD_CAST "define")) ||
5693 (xmlStrEqual(cur->name, BAD_CAST "oneOrMore")) ||
5694 (xmlStrEqual(cur->name, BAD_CAST "zeroOrMore")) ||
5695 (xmlStrEqual(cur->name, BAD_CAST "optional")) ||
5696 (xmlStrEqual(cur->name, BAD_CAST "list")) ||
5697 (xmlStrEqual(cur->name, BAD_CAST "mixed"))) {
5698 if ((cur->children != NULL) &&
5699 (cur->children->next != NULL)) {
5700 xmlNodePtr group, tmp;
5701
5702 group = xmlNewNode(cur->ns, BAD_CAST "group");
5703 if (group == NULL) {
5704 if (ctxt->error != NULL)
5705 ctxt->error(ctxt->userData,
5706 "Out of memory allocating <group>\n");
5707 ctxt->nbErrors++;
5708 } else {
5709 group->children = cur->children;
5710 group->parent = cur;
5711 cur->children = group;
5712 cur->last = group;
5713 tmp = group->children;
5714 while (tmp != NULL) {
5715 tmp->parent = group;
5716 if (tmp->next == NULL)
5717 group->last = tmp;
5718 tmp = tmp->next;
5719 }
5720 }
5721 }
5722 } else if (xmlStrEqual(cur->name, BAD_CAST "element")) {
5723 xmlNodePtr tmp, group;
5724
5725 tmp = cur->children;
5726 if ((tmp != NULL) && (tmp->next != NULL)) {
5727 tmp = tmp->next;
5728 if (tmp->next != NULL) {
5729 group = xmlNewNode(cur->ns, BAD_CAST "group");
5730 if (group == NULL) {
5731 if (ctxt->error != NULL)
5732 ctxt->error(ctxt->userData,
5733 "Out of memory allocating <group>\n");
5734 ctxt->nbErrors++;
5735 } else {
5736 group->children = tmp;
5737 tmp->prev->next = group;
5738 tmp->prev = NULL;
5739 group->parent = cur;
5740 cur->last = group;
5741 while (tmp != NULL) {
5742 tmp->parent = group;
5743 if (tmp->next == NULL)
5744 group->last = tmp;
5745 tmp = tmp->next;
5746 }
5747 }
5748 }
5749 }
5750 } else if ((xmlStrEqual(cur->name, BAD_CAST "group")) ||
5751 (xmlStrEqual(cur->name, BAD_CAST "choice")) ||
5752 (xmlStrEqual(cur->name, BAD_CAST "interleave"))) {
5753 xmlNodePtr tmp, group;
5754
5755 if (cur->children == NULL) {
5756 if (ctxt->error != NULL)
5757 ctxt->error(ctxt->userData,
5758 "Patterns <%s> has no children\n", cur->name);
5759 ctxt->nbErrors++;
5760 delete = cur;
5761 goto skip_children;
5762 }
5763 /*
5764 * keep the node if cur->children->next to preserve the
5765 * bases, those will be ignored at parsing.
5766 */
5767 if ((cur->children->next != NULL) &&
5768 (cur->children->next->next != NULL)) {
5769 group = xmlNewNode(cur->ns, cur->name);
5770 if (group == NULL) {
5771 if (ctxt->error != NULL)
5772 ctxt->error(ctxt->userData,
5773 "Out of memory allocating <%s>\n");
5774 ctxt->nbErrors++;
5775 } else {
5776 tmp = cur->children->next;
5777 group->children = tmp;
5778 tmp->prev->next = group;
5779 tmp->prev = NULL;
5780 group->parent = cur;
5781 cur->last = group;
5782 while (tmp != NULL) {
5783 tmp->parent = group;
5784 if (tmp->next == NULL)
5785 group->last = tmp;
5786 tmp = tmp->next;
5787 }
5788 }
5789 }
5790 }
5791 /*
5792 * Simplifications on 4.13
5793 */
5794 if (xmlStrEqual(cur->name, BAD_CAST "mixed")) {
5795 if (cur->children == NULL) {
5796 if (ctxt->error != NULL)
5797 ctxt->error(ctxt->userData,
5798 "Mixed is empty\n");
5799 ctxt->nbErrors++;
5800 } else {
5801 xmlChar *name = (xmlChar *) cur->name;
5802 xmlNodePtr txt;
5803
5804 cur->name = xmlStrdup(BAD_CAST "interleave");
5805 if (cur->name == NULL) {
5806 if (ctxt->error != NULL)
5807 ctxt->error(ctxt->userData,
5808 "Out of memory handling <mixed>\n");
5809 ctxt->nbErrors++;
5810 cur->name = name;
5811 } else {
5812 xmlFree(name);
5813 txt = xmlNewChild(cur, cur->ns, BAD_CAST "text", NULL);
5814 if (txt == NULL) {
5815 if (ctxt->error != NULL)
5816 ctxt->error(ctxt->userData,
5817 "Out of memory handling <mixed>\n");
5818 ctxt->nbErrors++;
5819 cur->name = name;
5820 }
5821 }
5822 }
5823 }
5824 }
5825
5826 /*
5827 * Skip to next node
5828 */
5829 if (cur->children != NULL) {
5830 if ((cur->children->type != XML_ENTITY_DECL) &&
5831 (cur->children->type != XML_ENTITY_REF_NODE) &&
5832 (cur->children->type != XML_ENTITY_NODE)) {
5833 cur = cur->children;
5834 continue;
5835 }
5836 }
5837skip_children:
5838 if (cur->next != NULL) {
5839 cur = cur->next;
5840 continue;
5841 }
5842
5843 do {
5844 cur = cur->parent;
5845 if (cur == NULL)
5846 break;
5847 if (cur == root) {
5848 cur = NULL;
5849 break;
5850 }
5851 if (cur->next != NULL) {
5852 cur = cur->next;
5853 break;
5854 }
5855 } while (cur != NULL);
5856 }
5857 if (delete != NULL) {
5858 xmlUnlinkNode(delete);
5859 xmlFreeNode(delete);
5860 delete = NULL;
5861 }
5862}
5863
5864/**
Daniel Veillardc5312d72003-02-21 17:14:10 +00005865 * xmlRelaxNGCleanupDoc:
5866 * @ctxt: a Relax-NG parser context
5867 * @doc: an xmldocPtr document pointer
5868 *
5869 * Cleanup the document from unwanted nodes for parsing, resolve
5870 * Include and externalRef lookups.
5871 *
5872 * Returns the cleaned up document or NULL in case of error
5873 */
5874static xmlDocPtr
5875xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
5876 xmlNodePtr root;
5877
5878 /*
5879 * Extract the root
5880 */
5881 root = xmlDocGetRootElement(doc);
5882 if (root == NULL) {
5883 if (ctxt->error != NULL)
5884 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5885 ctxt->URL);
5886 ctxt->nbErrors++;
5887 return (NULL);
5888 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005889 xmlRelaxNGCleanupBlanks(ctxt, root);
5890 root = xmlDocGetRootElement(doc);
5891 if (root == NULL) {
5892 if (ctxt->error != NULL)
5893 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5894 ctxt->URL);
5895 ctxt->nbErrors++;
5896 return (NULL);
5897 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00005898 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005899#if 0
5900xmlDocDump(stdout, doc);
5901#endif
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005902 return(doc);
5903}
5904
5905/**
5906 * xmlRelaxNGParse:
5907 * @ctxt: a Relax-NG parser context
5908 *
5909 * parse a schema definition resource and build an internal
5910 * XML Shema struture which can be used to validate instances.
5911 * *WARNING* this interface is highly subject to change
5912 *
5913 * Returns the internal XML RelaxNG structure built from the resource or
5914 * NULL in case of error
5915 */
5916xmlRelaxNGPtr
5917xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
5918{
5919 xmlRelaxNGPtr ret = NULL;
5920 xmlDocPtr doc;
5921 xmlNodePtr root;
5922
5923 xmlRelaxNGInitTypes();
5924
5925 if (ctxt == NULL)
5926 return (NULL);
5927
5928 /*
5929 * First step is to parse the input document into an DOM/Infoset
5930 */
5931 if (ctxt->URL != NULL) {
5932 doc = xmlParseFile((const char *) ctxt->URL);
5933 if (doc == NULL) {
5934 if (ctxt->error != NULL)
5935 ctxt->error(ctxt->userData,
5936 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
5937 ctxt->nbErrors++;
5938 return (NULL);
5939 }
5940 } else if (ctxt->buffer != NULL) {
5941 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
5942 if (doc == NULL) {
5943 if (ctxt->error != NULL)
5944 ctxt->error(ctxt->userData,
5945 "xmlRelaxNGParse: could not parse schemas\n");
5946 ctxt->nbErrors++;
5947 return (NULL);
5948 }
5949 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5950 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5951 } else {
5952 if (ctxt->error != NULL)
5953 ctxt->error(ctxt->userData,
5954 "xmlRelaxNGParse: nothing to parse\n");
5955 ctxt->nbErrors++;
5956 return (NULL);
5957 }
5958 ctxt->document = doc;
5959
5960 /*
5961 * Some preprocessing of the document content
5962 */
5963 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
5964 if (doc == NULL) {
5965 xmlFreeDoc(ctxt->document);
5966 ctxt->document = NULL;
5967 return(NULL);
5968 }
5969
Daniel Veillard6eadf632003-01-23 18:29:16 +00005970 /*
5971 * Then do the parsing for good
5972 */
5973 root = xmlDocGetRootElement(doc);
5974 if (root == NULL) {
5975 if (ctxt->error != NULL)
5976 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5977 ctxt->URL);
5978 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005979 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005980 return (NULL);
5981 }
5982 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005983 if (ret == NULL) {
5984 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005985 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005986 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005987
5988 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00005989 * if there was a parsing error return NULL
5990 */
5991 if (ctxt->nbErrors > 0) {
5992 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005993 ctxt->document = NULL;
5994 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005995 return(NULL);
5996 }
5997
5998 /*
5999 * Transfer the pointer for cleanup at the schema level.
6000 */
6001 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006002 ctxt->document = NULL;
6003 ret->documents = ctxt->documents;
6004 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006005
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006006 ret->includes = ctxt->includes;
6007 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006008 ret->defNr = ctxt->defNr;
6009 ret->defTab = ctxt->defTab;
6010 ctxt->defTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006011
6012 return (ret);
6013}
6014
6015/**
6016 * xmlRelaxNGSetParserErrors:
6017 * @ctxt: a Relax-NG validation context
6018 * @err: the error callback
6019 * @warn: the warning callback
6020 * @ctx: contextual data for the callbacks
6021 *
6022 * Set the callback functions used to handle errors for a validation context
6023 */
6024void
6025xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6026 xmlRelaxNGValidityErrorFunc err,
6027 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6028 if (ctxt == NULL)
6029 return;
6030 ctxt->error = err;
6031 ctxt->warning = warn;
6032 ctxt->userData = ctx;
6033}
6034/************************************************************************
6035 * *
6036 * Dump back a compiled form *
6037 * *
6038 ************************************************************************/
6039static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6040
6041/**
6042 * xmlRelaxNGDumpDefines:
6043 * @output: the file output
6044 * @defines: a list of define structures
6045 *
6046 * Dump a RelaxNG structure back
6047 */
6048static void
6049xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6050 while (defines != NULL) {
6051 xmlRelaxNGDumpDefine(output, defines);
6052 defines = defines->next;
6053 }
6054}
6055
6056/**
6057 * xmlRelaxNGDumpDefine:
6058 * @output: the file output
6059 * @define: a define structure
6060 *
6061 * Dump a RelaxNG structure back
6062 */
6063static void
6064xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6065 if (define == NULL)
6066 return;
6067 switch(define->type) {
6068 case XML_RELAXNG_EMPTY:
6069 fprintf(output, "<empty/>\n");
6070 break;
6071 case XML_RELAXNG_NOT_ALLOWED:
6072 fprintf(output, "<notAllowed/>\n");
6073 break;
6074 case XML_RELAXNG_TEXT:
6075 fprintf(output, "<text/>\n");
6076 break;
6077 case XML_RELAXNG_ELEMENT:
6078 fprintf(output, "<element>\n");
6079 if (define->name != NULL) {
6080 fprintf(output, "<name");
6081 if (define->ns != NULL)
6082 fprintf(output, " ns=\"%s\"", define->ns);
6083 fprintf(output, ">%s</name>\n", define->name);
6084 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006085 if (define->nameClass != NULL)
6086 xmlRelaxNGDumpDefine(output, define->nameClass);
6087 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006088 fprintf(output, "</element>\n");
6089 break;
6090 case XML_RELAXNG_LIST:
6091 fprintf(output, "<list>\n");
6092 xmlRelaxNGDumpDefines(output, define->content);
6093 fprintf(output, "</list>\n");
6094 break;
6095 case XML_RELAXNG_ONEORMORE:
6096 fprintf(output, "<oneOrMore>\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006097 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006098 fprintf(output, "</oneOrMore>\n");
6099 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006100 case XML_RELAXNG_CHOICE:
6101 fprintf(output, "<choice>\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006102 xmlRelaxNGDumpDefine(output, define->content);
6103 xmlRelaxNGDumpDefine(output, define->cont2);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006104 fprintf(output, "</choice>\n");
6105 break;
6106 case XML_RELAXNG_GROUP:
6107 fprintf(output, "<group>\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006108 xmlRelaxNGDumpDefine(output, define->content);
6109 xmlRelaxNGDumpDefine(output, define->cont2);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006110 fprintf(output, "</group>\n");
6111 break;
6112 case XML_RELAXNG_INTERLEAVE:
6113 fprintf(output, "<interleave>\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006114 xmlRelaxNGDumpDefine(output, define->content);
6115 xmlRelaxNGDumpDefine(output, define->cont2);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006116 fprintf(output, "</interleave>\n");
6117 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006118 case XML_RELAXNG_ATTRIBUTE:
6119 fprintf(output, "<attribute>\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006120 if (define->name != NULL) {
6121 fprintf(output, "<name");
6122 if (define->ns != NULL)
6123 fprintf(output, " ns=\"%s\"", define->ns);
6124 fprintf(output, ">%s</name>\n", define->name);
6125 }
6126 if (define->nameClass != NULL)
6127 xmlRelaxNGDumpDefine(output, define->nameClass);
6128 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006129 fprintf(output, "</attribute>\n");
6130 break;
6131 case XML_RELAXNG_DEF:
6132 fprintf(output, "<define");
6133 if (define->name != NULL)
6134 fprintf(output, " name=\"%s\"", define->name);
6135 fprintf(output, ">\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006136 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006137 fprintf(output, "</define>\n");
6138 break;
6139 case XML_RELAXNG_REF:
6140 fprintf(output, "<ref");
6141 if (define->name != NULL)
6142 fprintf(output, " name=\"%s\"", define->name);
6143 fprintf(output, ">\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006144 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006145 fprintf(output, "</ref>\n");
6146 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006147 case XML_RELAXNG_PARENTREF:
6148 fprintf(output, "<parentRef");
6149 if (define->name != NULL)
6150 fprintf(output, " name=\"%s\"", define->name);
6151 fprintf(output, ">\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006152 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006153 fprintf(output, "</parentRef>\n");
6154 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006155 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006156 fprintf(output, "<externalRef>");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006157 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006158 fprintf(output, "</externalRef>\n");
6159 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006160 case XML_RELAXNG_AFTER:
6161 fprintf(output, "<after>");
6162 xmlRelaxNGDumpDefine(output, define->content);
6163 xmlRelaxNGDumpDefine(output, define->cont2);
6164 fprintf(output, "</after>\n");
6165 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00006166 case XML_RELAXNG_DATATYPE:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006167 fprintf(output, "<data>");
6168 fprintf(output, "</data>\n");
6169 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006170 case XML_RELAXNG_VALUE:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006171 fprintf(output, "<value>");
6172 fprintf(output, "</value>\n");
6173 break;
6174 case XML_RELAXNG_EXCEPT:
6175 fprintf(output, "<except>\n");
6176 xmlRelaxNGDumpDefine(output, define->content);
6177 fprintf(output, "</except>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006178 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006179 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006180 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006181 TODO
6182 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006183#if 0
Daniel Veillard77648bb2003-02-20 15:03:22 +00006184 case XML_RELAXNG_NOOP:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006185 xmlRelaxNGDumpDefine(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006186 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006187#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00006188 }
6189}
6190
6191/**
6192 * xmlRelaxNGDumpGrammar:
6193 * @output: the file output
6194 * @grammar: a grammar structure
6195 * @top: is this a top grammar
6196 *
6197 * Dump a RelaxNG structure back
6198 */
6199static void
6200xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6201{
6202 if (grammar == NULL)
6203 return;
6204
6205 fprintf(output, "<grammar");
6206 if (top)
6207 fprintf(output,
6208 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6209 switch(grammar->combine) {
6210 case XML_RELAXNG_COMBINE_UNDEFINED:
6211 break;
6212 case XML_RELAXNG_COMBINE_CHOICE:
6213 fprintf(output, " combine=\"choice\"");
6214 break;
6215 case XML_RELAXNG_COMBINE_INTERLEAVE:
6216 fprintf(output, " combine=\"interleave\"");
6217 break;
6218 default:
6219 fprintf(output, " <!-- invalid combine value -->");
6220 }
6221 fprintf(output, ">\n");
6222 if (grammar->start == NULL) {
6223 fprintf(output, " <!-- grammar had no start -->");
6224 } else {
6225 fprintf(output, "<start>\n");
6226 xmlRelaxNGDumpDefine(output, grammar->start);
6227 fprintf(output, "</start>\n");
6228 }
6229 /* TODO ? Dump the defines ? */
6230 fprintf(output, "</grammar>\n");
6231}
6232
6233/**
6234 * xmlRelaxNGDump:
6235 * @output: the file output
6236 * @schema: a schema structure
6237 *
6238 * Dump a RelaxNG structure back
6239 */
6240void
6241xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6242{
6243 if (schema == NULL) {
6244 fprintf(output, "RelaxNG empty or failed to compile\n");
6245 return;
6246 }
6247 fprintf(output, "RelaxNG: ");
6248 if (schema->doc == NULL) {
6249 fprintf(output, "no document\n");
6250 } else if (schema->doc->URL != NULL) {
6251 fprintf(output, "%s\n", schema->doc->URL);
6252 } else {
6253 fprintf(output, "\n");
6254 }
6255 if (schema->topgrammar == NULL) {
6256 fprintf(output, "RelaxNG has no top grammar\n");
6257 return;
6258 }
6259 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6260}
6261
Daniel Veillardfebcca42003-02-16 15:44:18 +00006262/**
6263 * xmlRelaxNGDumpTree:
6264 * @output: the file output
6265 * @schema: a schema structure
6266 *
6267 * Dump the transformed RelaxNG tree.
6268 */
6269void
6270xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6271{
6272 if (schema == NULL) {
6273 fprintf(output, "RelaxNG empty or failed to compile\n");
6274 return;
6275 }
6276 if (schema->doc == NULL) {
6277 fprintf(output, "no document\n");
6278 } else {
6279 xmlDocDump(output, schema->doc);
6280 }
6281}
6282
Daniel Veillard6eadf632003-01-23 18:29:16 +00006283/************************************************************************
6284 * *
6285 * Validation implementation *
6286 * *
6287 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006288static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6289 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006290
6291/**
6292 * xmlRelaxNGSkipIgnored:
6293 * @ctxt: a schema validation context
6294 * @node: the top node.
6295 *
6296 * Skip ignorable nodes in that context
6297 *
6298 * Returns the new sibling or NULL in case of error.
6299 */
6300static xmlNodePtr
6301xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6302 xmlNodePtr node) {
6303 /*
6304 * TODO complete and handle entities
6305 */
6306 while ((node != NULL) &&
6307 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006308 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006309 (((node->type == XML_TEXT_NODE) ||
6310 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard6eadf632003-01-23 18:29:16 +00006311 (IS_BLANK_NODE(node))))) {
6312 node = node->next;
6313 }
6314 return(node);
6315}
6316
6317/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006318 * xmlRelaxNGNormalize:
6319 * @ctxt: a schema validation context
6320 * @str: the string to normalize
6321 *
6322 * Implements the normalizeWhiteSpace( s ) function from
6323 * section 6.2.9 of the spec
6324 *
6325 * Returns the new string or NULL in case of error.
6326 */
6327static xmlChar *
6328xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6329 xmlChar *ret, *p;
6330 const xmlChar *tmp;
6331 int len;
6332
6333 if (str == NULL)
6334 return(NULL);
6335 tmp = str;
6336 while (*tmp != 0) tmp++;
6337 len = tmp - str;
6338
6339 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6340 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006341 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006342 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006343 } else {
6344 xmlGenericError(xmlGenericErrorContext,
6345 "xmlRelaxNGNormalize: out of memory\n");
6346 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006347 return(NULL);
6348 }
6349 p = ret;
6350 while (IS_BLANK(*str)) str++;
6351 while (*str != 0) {
6352 if (IS_BLANK(*str)) {
6353 while (IS_BLANK(*str)) str++;
6354 if (*str == 0)
6355 break;
6356 *p++ = ' ';
6357 } else
6358 *p++ = *str++;
6359 }
6360 *p = 0;
6361 return(ret);
6362}
6363
6364/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006365 * xmlRelaxNGValidateDatatype:
6366 * @ctxt: a Relax-NG validation context
6367 * @value: the string value
6368 * @type: the datatype definition
6369 *
6370 * Validate the given value against the dataype
6371 *
6372 * Returns 0 if the validation succeeded or an error code.
6373 */
6374static int
6375xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
6376 xmlRelaxNGDefinePtr define) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006377 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006378 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006379 void *result = NULL;
6380 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006381
6382 if ((define == NULL) || (define->data == NULL)) {
6383 return(-1);
6384 }
6385 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006386 if (lib->check != NULL) {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006387 if ((define->prop != NULL) &&
6388 (define->prop->type == XML_RELAXNG_PARAM)) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006389 ret = lib->check(lib->data, define->name, value, &result);
6390 } else {
6391 ret = lib->check(lib->data, define->name, value, NULL);
6392 }
6393 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006394 ret = -1;
6395 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006396 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006397 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6398 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006399 return(-1);
6400 } else if (ret == 1) {
6401 ret = 0;
6402 } else {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006403 VALID_ERR3(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006404 ret = -1;
6405 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006406 cur = define->prop;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006407 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6408 if (lib->facet != NULL) {
6409 tmp = lib->facet(lib->data, define->name, cur->name,
6410 cur->value, value, result);
6411 if (tmp != 0)
6412 ret = -1;
6413 }
6414 cur = cur->next;
6415 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006416 if ((ret == 0) && (define->content != NULL)) {
6417 const xmlChar *oldvalue, *oldendvalue;
6418
6419 oldvalue = ctxt->state->value;
6420 oldendvalue = ctxt->state->endvalue;
6421 ctxt->state->value = (xmlChar *) value;
6422 ctxt->state->endvalue = NULL;
6423 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6424 ctxt->state->value = (xmlChar *) oldvalue;
6425 ctxt->state->endvalue = (xmlChar *) oldendvalue;
6426 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006427 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6428 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006429 return(ret);
6430}
6431
6432/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006433 * xmlRelaxNGNextValue:
6434 * @ctxt: a Relax-NG validation context
6435 *
6436 * Skip to the next value when validating within a list
6437 *
6438 * Returns 0 if the operation succeeded or an error code.
6439 */
6440static int
6441xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
6442 xmlChar *cur;
6443
6444 cur = ctxt->state->value;
6445 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
6446 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00006447 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006448 return(0);
6449 }
6450 while (*cur != 0) cur++;
6451 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
6452 if (cur == ctxt->state->endvalue)
6453 ctxt->state->value = NULL;
6454 else
6455 ctxt->state->value = cur;
6456 return(0);
6457}
6458
6459/**
6460 * xmlRelaxNGValidateValueList:
6461 * @ctxt: a Relax-NG validation context
6462 * @defines: the list of definitions to verify
6463 *
6464 * Validate the given set of definitions for the current value
6465 *
6466 * Returns 0 if the validation succeeded or an error code.
6467 */
6468static int
6469xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
6470 xmlRelaxNGDefinePtr defines) {
6471 int ret = 0;
6472
6473 while (defines != NULL) {
6474 ret = xmlRelaxNGValidateValue(ctxt, defines);
6475 if (ret != 0)
6476 break;
6477 defines = defines->next;
6478 }
6479 return(ret);
6480}
6481
6482/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006483 * xmlRelaxNGValidateValue:
6484 * @ctxt: a Relax-NG validation context
6485 * @define: the definition to verify
6486 *
6487 * Validate the given definition for the current value
6488 *
6489 * Returns 0 if the validation succeeded or an error code.
6490 */
6491static int
6492xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6493 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00006494 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006495 xmlChar *value;
6496
6497 value = ctxt->state->value;
6498 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006499 case XML_RELAXNG_EMPTY: {
6500 if ((value != NULL) && (value[0] != 0)) {
6501 int idx = 0;
6502
6503 while (IS_BLANK(value[idx]))
6504 idx++;
6505 if (value[idx] != 0)
6506 ret = -1;
6507 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00006509 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006510 case XML_RELAXNG_TEXT:
6511 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00006512 case XML_RELAXNG_VALUE: {
6513 if (!xmlStrEqual(value, define->value)) {
6514 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006515 xmlRelaxNGTypeLibraryPtr lib;
6516
6517 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
6518 if ((lib != NULL) && (lib->comp != NULL))
6519 ret = lib->comp(lib->data, define->name, value,
6520 define->value);
6521 else
6522 ret = -1;
6523 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006524 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006525 return(-1);
6526 } else if (ret == 1) {
6527 ret = 0;
6528 } else {
6529 ret = -1;
6530 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006531 } else {
6532 xmlChar *nval, *nvalue;
6533
6534 /*
6535 * TODO: trivial optimizations are possible by
6536 * computing at compile-time
6537 */
6538 nval = xmlRelaxNGNormalize(ctxt, define->value);
6539 nvalue = xmlRelaxNGNormalize(ctxt, value);
6540
Daniel Veillardea3f3982003-01-26 19:45:18 +00006541 if ((nval == NULL) || (nvalue == NULL) ||
6542 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00006543 ret = -1;
6544 if (nval != NULL)
6545 xmlFree(nval);
6546 if (nvalue != NULL)
6547 xmlFree(nvalue);
6548 }
6549 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006550 if (ret == 0)
6551 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00006552 break;
6553 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006554 case XML_RELAXNG_DATATYPE: {
6555 ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
6556 if (ret == 0)
6557 xmlRelaxNGNextValue(ctxt);
6558
6559 break;
6560 }
6561 case XML_RELAXNG_CHOICE: {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006562 xmlChar *oldvalue;
6563
6564 oldflags = ctxt->flags;
6565 ctxt->flags |= FLAGS_IGNORABLE;
6566
6567 oldvalue = ctxt->state->value;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006568 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6569 if (ret != 0) {
6570 oldvalue = ctxt->state->value;
6571 ret = xmlRelaxNGValidateValue(ctxt, define->cont2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006572 }
6573 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006574 if (ret != 0) {
6575 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6576 xmlRelaxNGDumpValidError(ctxt);
6577 } else {
6578 ctxt->errNr = 0;
6579 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006580 if (ret == 0)
6581 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006582 break;
6583 }
6584 case XML_RELAXNG_LIST: {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006585 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00006586#ifdef DEBUG_LIST
6587 int nb_values = 0;
6588#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006589
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006590 /*
6591 * TODO: handle groups ... see 4.12 dimplification too
6592 */
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006593 oldvalue = ctxt->state->value;
6594 oldend = ctxt->state->endvalue;
6595
6596 val = xmlStrdup(oldvalue);
6597 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006598 val = xmlStrdup(BAD_CAST "");
6599 }
6600 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006601 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006602 return(-1);
6603 }
6604 cur = val;
6605 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006606 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006607 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00006608 cur++;
6609#ifdef DEBUG_LIST
6610 nb_values++;
6611#endif
6612 while (IS_BLANK(*cur))
6613 *cur++ = 0;
6614 } else
6615 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006616 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006617#ifdef DEBUG_LIST
6618 xmlGenericError(xmlGenericErrorContext,
6619 "list value: '%s' found %d items\n", oldvalue, nb_values);
6620 nb_values = 0;
6621#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006622 ctxt->state->endvalue = cur;
6623 cur = val;
6624 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006625 if ((cur == ctxt->state->endvalue) &&
6626 (!xmlRelaxNGIsNullable(define->content))) {
6627 VALID_ERR(XML_RELAXNG_ERR_LISTEMPTY);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006628 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006629 } else {
6630 ctxt->state->value = cur;
6631
6632 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6633
6634 if ((ret == 0) && (ctxt->state->value != NULL) &&
6635 (ctxt->state->value != ctxt->state->endvalue)) {
6636 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
6637 ret = -1;
6638 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006639 }
6640 xmlFree(val);
6641 ctxt->state->value = oldvalue;
6642 ctxt->state->endvalue = oldend;
6643 break;
6644 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006645 case XML_RELAXNG_ONEORMORE: {
6646 xmlChar *cur, *temp;
6647
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006648 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6649 if (ret != 0) {
6650 break;
6651 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006652
6653 oldflags = ctxt->flags;
6654 ctxt->flags |= FLAGS_IGNORABLE;
6655 cur = ctxt->state->value;
6656 temp = NULL;
6657 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
6658 (temp != cur)) {
6659 temp = cur;
6660 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6661 if (ret != 0) {
6662 ctxt->state->value = temp;
6663 ret = 0;
6664 break;
6665 }
6666 cur = ctxt->state->value;
6667 }
6668 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006669 if (ret != 0) {
6670 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6671 xmlRelaxNGDumpValidError(ctxt);
6672 } else {
6673 ctxt->errNr = 0;
6674 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006675 break;
6676 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006677 case XML_RELAXNG_EXCEPT: {
6678 xmlRelaxNGDefinePtr list;
6679
6680 list = define->content;
6681 while (list != NULL) {
6682 ret = xmlRelaxNGValidateValue(ctxt, list);
6683 if (ret == 0) {
6684 ret = -1;
6685 break;
6686 } else
6687 ret = 0;
6688 list = list->next;
6689 }
6690 break;
6691 }
Daniel Veillard463a5472003-02-27 21:30:32 +00006692 case XML_RELAXNG_DEF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006693 case XML_RELAXNG_GROUP:
6694 if (define->content != NULL)
6695 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6696 if ((ret == 0) && (define->cont2 != NULL))
6697 ret = xmlRelaxNGValidateValue(ctxt, define->cont2);
Daniel Veillardd4310742003-02-18 21:12:46 +00006698 break;
Daniel Veillard463a5472003-02-27 21:30:32 +00006699 case XML_RELAXNG_REF:
6700 case XML_RELAXNG_PARENTREF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006701 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard463a5472003-02-27 21:30:32 +00006702 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6703 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006704 default:
6705 TODO
6706 ret = -1;
6707 }
6708 return(ret);
6709}
6710
6711/**
6712 * xmlRelaxNGValidateValueContent:
6713 * @ctxt: a Relax-NG validation context
6714 * @defines: the list of definitions to verify
6715 *
6716 * Validate the given definitions for the current value
6717 *
6718 * Returns 0 if the validation succeeded or an error code.
6719 */
6720static int
6721xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
6722 xmlRelaxNGDefinePtr defines) {
6723 int ret = 0;
6724
6725 while (defines != NULL) {
6726 ret = xmlRelaxNGValidateValue(ctxt, defines);
6727 if (ret != 0)
6728 break;
6729 defines = defines->next;
6730 }
6731 return(ret);
6732}
6733
6734/**
6735 * xmlRelaxNGValidateAttribute:
6736 * @ctxt: a Relax-NG validation context
6737 * @define: the definition to verify
6738 *
6739 * Validate the given attribute definition for that node
6740 *
6741 * Returns 0 if the validation succeeded or an error code.
6742 */
6743static int
6744xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
6745 xmlRelaxNGDefinePtr define) {
6746 int ret = 0, i;
6747 xmlChar *value, *oldvalue;
6748 xmlAttrPtr prop = NULL, tmp;
6749
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006750 if (ctxt->state->nbAttrLeft <= 0)
6751 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006752 if (define->name != NULL) {
6753 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6754 tmp = ctxt->state->attrs[i];
6755 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
6756 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
6757 (tmp->ns == NULL)) ||
6758 ((tmp->ns != NULL) &&
6759 (xmlStrEqual(define->ns, tmp->ns->href)))) {
6760 prop = tmp;
6761 break;
6762 }
6763 }
6764 }
6765 if (prop != NULL) {
6766 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6767 oldvalue = ctxt->state->value;
6768 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00006769 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006770 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00006771 if (ctxt->state->value != NULL)
6772 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006773 if (value != NULL)
6774 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00006775 ctxt->state->value = oldvalue;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006776 if (ret == 0) {
6777 /*
6778 * flag the attribute as processed
6779 */
6780 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006781 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006782 }
6783 } else {
6784 ret = -1;
6785 }
6786#ifdef DEBUG
6787 xmlGenericError(xmlGenericErrorContext,
6788 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
6789#endif
6790 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006791 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6792 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00006793 if ((tmp != NULL) &&
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006794 (xmlRelaxNGNsNameMatch(ctxt, define,
6795 (xmlNodePtr)tmp, 0) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006796 prop = tmp;
6797 break;
6798 }
6799 }
6800 if (prop != NULL) {
6801 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6802 oldvalue = ctxt->state->value;
6803 ctxt->state->value = value;
6804 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00006805 if (ctxt->state->value != NULL)
6806 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006807 if (value != NULL)
6808 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00006809 ctxt->state->value = oldvalue;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006810 if (ret == 0) {
6811 /*
6812 * flag the attribute as processed
6813 */
6814 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006815 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006816 }
6817 } else {
6818 ret = -1;
6819 }
6820#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00006821 if (define->ns != NULL) {
6822 xmlGenericError(xmlGenericErrorContext,
6823 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
6824 define->ns, ret);
6825 } else {
6826 xmlGenericError(xmlGenericErrorContext,
6827 "xmlRelaxNGValidateAttribute(anyName): %d\n",
6828 ret);
6829 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00006830#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00006831 }
6832
6833 return(ret);
6834}
6835
6836/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006837 * xmlRelaxNGNodeMatchesList:
6838 * @node: the node
6839 * @list: a NULL terminated array of definitions
6840 *
6841 * Check if a node can be matched by one of the definitions
6842 *
6843 * Returns 1 if matches 0 otherwise
6844 */
6845static int
6846xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
6847 xmlRelaxNGDefinePtr cur;
6848 int i = 0;
6849
6850 if ((node == NULL) || (list == NULL))
6851 return(0);
6852
6853 cur = list[i++];
6854 while (cur != NULL) {
6855 if ((node->type == XML_ELEMENT_NODE) &&
6856 (cur->type == XML_RELAXNG_ELEMENT)) {
6857 if (cur->name == NULL) {
6858 if ((node->ns != NULL) &&
6859 (xmlStrEqual(node->ns->href, cur->ns)))
6860 return(1);
6861 } else if (xmlStrEqual(cur->name, node->name)) {
6862 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
6863 if (node->ns == NULL)
6864 return(1);
6865 } else {
6866 if ((node->ns != NULL) &&
6867 (xmlStrEqual(node->ns->href, cur->ns)))
6868 return(1);
6869 }
6870 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006871 } else if (((node->type == XML_TEXT_NODE) ||
6872 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006873 (cur->type == XML_RELAXNG_TEXT)) {
6874 return(1);
6875 }
6876 cur = list[i++];
6877 }
6878 return(0);
6879}
6880
6881/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006882 * xmlRelaxNGNsNameMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00006883 * @ctxt: a Relax-NG validation context
6884 * @define: the definition to check
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006885 * @elem: the node
6886 * @eora: element or attribute
Daniel Veillard416589a2003-02-17 17:25:42 +00006887 *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006888 * Check if the element/attribute matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00006889 *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006890 * Returns 1 if the node matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00006891 */
6892static int
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006893xmlRelaxNGNsNameMatch(xmlRelaxNGValidCtxtPtr ctxt,
6894 xmlRelaxNGDefinePtr define,
6895 xmlNodePtr elem, int eora)
6896{
Daniel Veillard416589a2003-02-17 17:25:42 +00006897 int ret, oldflags;
6898
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006899 if (define->type == XML_RELAXNG_CHOICE) {
6900 oldflags = ctxt->flags;
6901 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard416589a2003-02-17 17:25:42 +00006902
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006903 ret = xmlRelaxNGNsNameMatch(ctxt, define->content, elem, eora);
6904 if (ret == 0)
6905 ret = xmlRelaxNGNsNameMatch(ctxt, define->cont2, elem, eora);
6906 if (ret != 1) {
6907 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6908 xmlRelaxNGDumpValidError(ctxt);
6909 } else {
6910 ctxt->errNr = 0;
6911 }
6912 ctxt->flags = oldflags;
6913 return (ret);
6914 } else if ((define->type == XML_RELAXNG_ELEMENT) ||
6915 (define->type == XML_RELAXNG_ATTRIBUTE)) {
6916 if (define->name != NULL) {
6917 if (!xmlStrEqual(elem->name, define->name)) {
6918 if (eora) {
6919 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME,
6920 define->name, elem->name);
6921 } else {
6922 VALID_ERR3(XML_RELAXNG_ERR_ATTRNAME,
6923 define->name, elem->name);
6924 }
6925 return (0);
6926 }
6927 }
6928 if ((define->ns != NULL) && (define->ns[0] != 0)) {
6929 if (elem->ns == NULL) {
6930 if (eora) {
6931 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
6932 } else {
6933 VALID_ERR2(XML_RELAXNG_ERR_ATTRNONS, elem->name);
6934 }
6935 return (0);
6936 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
6937 if (eora) {
6938 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
6939 elem->name, define->ns);
6940 } else {
6941 VALID_ERR3(XML_RELAXNG_ERR_ATTRWRONGNS,
6942 elem->name, define->ns);
6943 }
6944 return (0);
6945 }
6946 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
6947 (define->name == NULL)) {
6948 if (eora) {
6949 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
6950 } else {
6951 VALID_ERR2(XML_RELAXNG_ERR_ATTREXTRANS, elem->name);
6952 }
6953 return (0);
6954 } else if ((elem->ns != NULL) && (define->name != NULL)) {
6955 if (eora) {
6956 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
6957 } else {
6958 VALID_ERR2(XML_RELAXNG_ERR_ATTREXTRANS, define->name);
6959 }
6960 return (0);
6961 }
6962 if (define->nameClass == NULL)
6963 return (1);
6964 ret = xmlRelaxNGNsNameMatch(ctxt, define->nameClass, elem, eora);
6965 } else if (define->type == XML_RELAXNG_EXCEPT) {
6966 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00006967
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006968 oldflags = ctxt->flags;
6969 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard416589a2003-02-17 17:25:42 +00006970
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006971 list = define->content;
6972 while (list != NULL) {
6973 ret = xmlRelaxNGNsNameMatch(ctxt, list, elem, eora);
6974 if (ret == 1) {
6975 ctxt->flags = oldflags;
6976 return (0);
6977 }
6978 if (ret < 0) {
6979 ctxt->flags = oldflags;
6980 return (ret);
6981 }
6982 list = list->next;
6983 }
6984 ret = 1;
6985 ctxt->flags = oldflags;
Daniel Veillard416589a2003-02-17 17:25:42 +00006986 } else {
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006987 TODO ret = -1;
Daniel Veillard416589a2003-02-17 17:25:42 +00006988 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006989 return (ret);
Daniel Veillard416589a2003-02-17 17:25:42 +00006990}
6991
6992/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006993 * xmlRelaxNGValidateNodeValue:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006994 * @ctxt: a Relax-NG validation context
6995 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006996 * @nodes: the list of nodes
Daniel Veillard6eadf632003-01-23 18:29:16 +00006997 *
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006998 * Validate the given value definition for that node (or nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00006999 *
7000 * Returns 0 if the validation succeeded or an error code.
7001 */
7002static int
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007003xmlRelaxNGValidateNodeValue(xmlRelaxNGValidCtxtPtr ctxt,
7004 xmlRelaxNGDefinePtr define,
7005 xmlNodePtr nodes) {
7006 int ret = 0;
7007 xmlChar *content = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007008
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007009 while (nodes != NULL) {
7010 if (nodes->type == XML_ELEMENT_NODE) {
7011 break;
7012 } else if ((nodes->type == XML_TEXT_NODE) ||
7013 (nodes->type == XML_CDATA_SECTION_NODE)) {
7014 content = xmlStrcat(content, nodes->content);
7015 }
7016 /* TODO: handle entities ... */
7017 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007018 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007019 if (content == NULL) {
7020 content = xmlStrdup(BAD_CAST "");
7021 if (content == NULL) {
7022 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7023 return(-1);
7024 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007025 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007026 ctxt->state->value = content;
7027 ret = xmlRelaxNGValidateValue(ctxt, define);
7028 if (ret == -1) {
7029 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007030 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007031 if (content != NULL)
7032 xmlFree(content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007033 return(ret);
7034}
7035
7036/**
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007037 * xmlRelaxNGValidateNodeList:
7038 * @ctxt: a Relax-NG validation context
7039 * @define: the definition to verify
7040 * @nodes: the list of nodes
7041 *
7042 * Validate the given value definition for that node (or nodes)
7043 *
7044 * Returns 0 if the validation succeeded or an error code.
7045 */
7046static int
7047xmlRelaxNGValidateNodeList(xmlRelaxNGValidCtxtPtr ctxt,
7048 xmlRelaxNGDefinePtr define,
7049 xmlNodePtr nodes) {
7050 int ret = 0, len;
7051 xmlChar *content = NULL;
7052
7053 while (nodes != NULL) {
7054 if (nodes->type == XML_ELEMENT_NODE) {
7055 break;
7056 } else if ((nodes->type == XML_TEXT_NODE) ||
7057 (nodes->type == XML_CDATA_SECTION_NODE)) {
7058 content = xmlStrcat(content, nodes->content);
7059 }
7060 /* TODO: handle entities ... */
7061 nodes = nodes->next;
7062 }
7063 if (content == NULL) {
7064 content = xmlStrdup(BAD_CAST "");
7065 if (content == NULL) {
7066 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7067 return(-1);
7068 }
7069 }
7070 len = xmlStrlen(content);
7071 ctxt->state->value = content;
7072 ctxt->state->endvalue = content + len;
7073 ret = xmlRelaxNGValidateValue(ctxt, define);
7074 ctxt->state->value = NULL;
7075 ctxt->state->endvalue = NULL;
7076 if (ret == -1) {
7077 VALID_ERR(XML_RELAXNG_ERR_LIST);
7078 }
7079 if (content != NULL)
7080 xmlFree(content);
7081 return(ret);
7082}
7083
7084/**
7085 * xmlRelaxNGValidateNodeDatatype:
7086 * @ctxt: a Relax-NG validation context
7087 * @define: the definition to verify
7088 * @nodes: the list of nodes
7089 *
7090 * Validate the given datatype definition for that node (or nodes)
7091 *
7092 * Returns 0 if the validation succeeded or an error code.
7093 */
7094static int
7095xmlRelaxNGValidateNodeDatatype(xmlRelaxNGValidCtxtPtr ctxt,
7096 xmlRelaxNGDefinePtr define,
7097 xmlNodePtr nodes) {
7098 int ret = 0;
7099 xmlChar *content = NULL;
7100
7101 while (nodes != NULL) {
7102 if (nodes->type == XML_ELEMENT_NODE) {
7103 break;
7104 } else if ((nodes->type == XML_TEXT_NODE) ||
7105 (nodes->type == XML_CDATA_SECTION_NODE)) {
7106 content = xmlStrcat(content, nodes->content);
7107 }
7108 /* TODO: handle entities ... */
7109 nodes = nodes->next;
7110 }
7111 if (content == NULL) {
7112 content = xmlStrdup(BAD_CAST "");
7113 if (content == NULL) {
7114 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7115 return(-1);
7116 }
7117 }
7118 ctxt->state->value = NULL;
7119 ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
7120 if (ret == -1) {
7121 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
7122 }
7123 if (content != NULL)
7124 xmlFree(content);
7125 return(ret);
7126}
7127
7128/************************************************************************
7129 * *
7130 * Derivative validation implementation *
7131 * *
7132 ************************************************************************/
7133
7134static xmlRelaxNGDefinePtr xmlRelaxNGChildDeriv(
7135 xmlRelaxNGValidCtxtPtr ctxt,
7136 xmlRelaxNGDefinePtr define,
7137 xmlNodePtr node);
7138
7139static struct _xmlRelaxNGDefine _empty = { XML_RELAXNG_EMPTY,
7140 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
7141static xmlRelaxNGDefinePtr xmlRelaxNGEmptyDeriv = &_empty;
7142static struct _xmlRelaxNGDefine _nallow = { XML_RELAXNG_NOT_ALLOWED,
7143 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
7144static xmlRelaxNGDefinePtr xmlRelaxNGNotAllowedDeriv = &_nallow;
7145
7146typedef xmlRelaxNGDefinePtr (*xmlRelaxNGDerivFunc) (
7147 xmlRelaxNGValidCtxtPtr ctxt,
7148 xmlRelaxNGDefinePtr arg1,
7149 xmlRelaxNGDefinePtr arg2);
7150
7151/**
7152 * xmlRelaxNGIsNullable:
7153 * @define: the definition to verify
7154 *
7155 * Check if a definition is nullable.
7156 *
7157 * Returns 1 if yes, 0 if no and -1 in case of error
7158 */
7159static int
7160xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
7161 int ret;
7162 if (define == NULL)
7163 return(-1);
7164
7165 if (define->flags & IS_NULLABLE)
7166 return(1);
7167 if (define->flags & IS_NOT_NULLABLE)
7168 return(0);
7169 switch (define->type) {
7170 case XML_RELAXNG_EMPTY:
7171 case XML_RELAXNG_TEXT:
7172 ret = 1; break;
7173#if 0
7174 case XML_RELAXNG_NOOP:
7175#endif
7176 case XML_RELAXNG_DEF:
7177 case XML_RELAXNG_REF:
7178 case XML_RELAXNG_EXTERNALREF:
7179 case XML_RELAXNG_PARENTREF:
7180 case XML_RELAXNG_ONEORMORE:
7181 case XML_RELAXNG_START:
7182 ret = xmlRelaxNGIsNullable(define->content);
7183 break;
7184 case XML_RELAXNG_EXCEPT:
7185 case XML_RELAXNG_NOT_ALLOWED:
7186 case XML_RELAXNG_ELEMENT:
7187 case XML_RELAXNG_DATATYPE:
7188 case XML_RELAXNG_PARAM:
7189 case XML_RELAXNG_VALUE:
7190 case XML_RELAXNG_LIST:
7191 case XML_RELAXNG_ATTRIBUTE:
7192 ret = 0; break;
7193 case XML_RELAXNG_CHOICE:
7194 ret = xmlRelaxNGIsNullable(define->cont2);
7195 if (ret != 1)
7196 ret = xmlRelaxNGIsNullable(define->content);
7197 break;
7198 case XML_RELAXNG_INTERLEAVE:
7199 case XML_RELAXNG_GROUP:
7200 ret = xmlRelaxNGIsNullable(define->content);
7201 if (ret != 0)
7202 ret = xmlRelaxNGIsNullable(define->cont2);
7203 break;
7204 default:
7205 return(-1);
7206 }
7207 if (ret == 0)
7208 define->flags |= IS_NOT_NULLABLE;
7209 if (ret == 1)
7210 define->flags |= IS_NULLABLE;
7211 return(ret);
7212}
7213
7214#if 0
7215#define DEBUG_DERIV(define) xmlRelaxNGDebugDeriv(ctxt, define, node);
7216/**
7217 * xmlRelaxNGDebugDeriv:
7218 * @ctxt: a Relax-NG validation context
7219 * @define: the current derivation
7220 * @node: the current node
7221 *
7222 * Dump some debug informations about the current derivation state
7223 */
7224static void
7225xmlRelaxNGDebugDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7226 xmlRelaxNGDefinePtr define,
7227 xmlNodePtr node) {
7228 xmlRelaxNGValidErrorContext(ctxt, node, NULL);
7229 xmlRelaxNGDumpDefine(stdout, define);
7230}
7231#endif
7232
7233/**
7234 * xmlRelaxNGNewDeriv:
7235 * @ctxt: a Relax-NG validation context
7236 * @type: the derivation type
7237 * @c1: the first children
7238 * @c2: the second children
7239 *
7240 * Build a new derivated definition at runtime.
7241 *
7242 * Returns the new definition or NULL
7243 */
7244static xmlRelaxNGDefinePtr
7245xmlRelaxNGNewDeriv(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7246 xmlRelaxNGType type,
7247 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7248 xmlRelaxNGDefinePtr def = NULL;
7249
7250 def = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
7251 if (def == NULL) {
7252 TODO
7253 return(NULL);
7254 }
7255 def->type = type;
7256 def->content = c1;
7257 def->cont2 = c2;
7258 def->flags = IS_DYNAMIC;
7259 def->depth = 1;
7260#ifdef DEBUG_REFEREENCES
7261printf("new %p:", def);
7262if (c1 != NULL) printf(" %p(%d)", c1, c1->depth); else printf(" NULL");
7263if (c2 != NULL) printf(" %p(%d)\n", c2, c2->depth); else printf(" NULL\n");
7264#endif
7265 return(def);
7266}
7267
7268#define FREE_DERIV(d) if (d->flags & IS_DYNAMIC) xmlRelaxNGFreeDeriv(ctxt, d)
7269#define REF_DERIV(d) if (d->flags & IS_DYNAMIC) d->depth++
7270#define REF_DERIV2(d) if (d->flags & IS_DYNAMIC) d->depth += 2
7271
7272/**
7273 * xmlRelaxNGFreeDeriv:
7274 * @ctxt: a Relax-NG validation context
7275 * @def: the derivation
7276 *
7277 * Discard a dynamic derivated definition at runtime.
7278 */
7279static void
7280xmlRelaxNGFreeDeriv(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7281 xmlRelaxNGDefinePtr def) {
7282 if (def == NULL)
7283 return;
7284 if (!(def->flags & IS_DYNAMIC))
7285 return;
7286
7287#ifdef DEBUG_REFEREENCES
7288printf("free %p:", def);
7289if (def->content != NULL) printf(" %p(%d)", def->content, def->content->depth); else printf(" NULL");
7290if (def->cont2 != NULL) printf(" %p(%d)\n", def->cont2, def->cont2->depth); else printf(" NULL\n");
7291#endif
7292
7293 def->depth --;
7294 if (def->depth > 0)
7295 return;
7296 if ((def->content != NULL) && (def->content->flags & IS_DYNAMIC)) {
7297 def->content->depth--;
7298 if (def->content->depth <= 0)
7299 xmlRelaxNGFreeDeriv(ctxt, def->content);
7300 }
7301 if ((def->cont2 != NULL) && (def->cont2->flags & IS_DYNAMIC)) {
7302 def->cont2->depth--;
7303 if (def->cont2->depth <= 0)
7304 xmlRelaxNGFreeDeriv(ctxt, def->cont2);
7305 }
7306 xmlFree(def);
7307}
7308
7309/**
7310 * choice:
7311 * @ctxt: a Relax-NG validation context
7312 * @c1: the first children
7313 * @c2: the second children
7314 *
7315 * Build a new choice definition at runtime.
7316 *
7317 * Returns the new definition or NULL
7318 */
7319static xmlRelaxNGDefinePtr
7320choice(xmlRelaxNGValidCtxtPtr ctxt,
7321 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7322 if (c1 == NULL) return(c2);
7323 if (c2 == NULL) return(c1);
7324 if (c1->type == XML_RELAXNG_NOT_ALLOWED)
7325 return(c2);
7326 if (c2->type == XML_RELAXNG_NOT_ALLOWED)
7327 return(c1);
7328 if ((c1->type == XML_RELAXNG_EMPTY) && (c2->type == XML_RELAXNG_EMPTY))
7329 return(xmlRelaxNGEmptyDeriv);
7330 if (c2->type == XML_RELAXNG_EMPTY)
7331 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_CHOICE, c2, c1));
7332 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_CHOICE, c1, c2));
7333}
7334
7335/**
7336 * group:
7337 * @ctxt: a Relax-NG validation context
7338 * @type: the derivation type
7339 * @c1: the first children
7340 * @c2: the second children
7341 *
7342 * Build a new group definition at runtime.
7343 *
7344 * Returns the new definition or NULL
7345 */
7346static xmlRelaxNGDefinePtr
7347group(xmlRelaxNGValidCtxtPtr ctxt,
7348 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7349 if (c1 == NULL) return(NULL);
7350 if (c2 == NULL) return(NULL);
7351 if (c1->type == XML_RELAXNG_NOT_ALLOWED) {
7352 FREE_DERIV(c2);
7353 return(xmlRelaxNGNotAllowedDeriv);
7354 }
7355 if (c2->type == XML_RELAXNG_NOT_ALLOWED) {
7356 FREE_DERIV(c1);
7357 return(xmlRelaxNGNotAllowedDeriv);
7358 }
7359 if (c1->type == XML_RELAXNG_EMPTY)
7360 return(c2);
7361 if (c2->type == XML_RELAXNG_EMPTY)
7362 return(c1);
7363 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_GROUP, c1, c2));
7364}
7365
7366static xmlRelaxNGDefinePtr
7367group_flip(xmlRelaxNGValidCtxtPtr ctxt,
7368 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7369 return(group(ctxt, c2, c1));
7370}
7371
7372/**
7373 * interleave:
7374 * @ctxt: a Relax-NG validation context
7375 * @type: the derivation type
7376 * @c1: the first children
7377 * @c2: the second children
7378 *
7379 * Build a new interleave definition at runtime.
7380 *
7381 * Returns the new definition or NULL
7382 */
7383static xmlRelaxNGDefinePtr
7384interleave(xmlRelaxNGValidCtxtPtr ctxt,
7385 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7386 if (c1 == NULL) return(NULL);
7387 if (c2 == NULL) return(NULL);
7388 if (c1->type == XML_RELAXNG_NOT_ALLOWED) {
7389 FREE_DERIV(c2);
7390 return(xmlRelaxNGNotAllowedDeriv);
7391 }
7392 if (c2->type == XML_RELAXNG_NOT_ALLOWED) {
7393 FREE_DERIV(c1);
7394 return(xmlRelaxNGNotAllowedDeriv);
7395 }
7396 if (c1->type == XML_RELAXNG_EMPTY)
7397 return(c2);
7398 if (c2->type == XML_RELAXNG_EMPTY)
7399 return(c1);
7400 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_INTERLEAVE, c1, c2));
7401}
7402
7403static xmlRelaxNGDefinePtr
7404interleave_flip(xmlRelaxNGValidCtxtPtr ctxt,
7405 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7406 return(interleave(ctxt, c2, c1));
7407}
7408
7409/**
7410 * after:
7411 * @ctxt: a Relax-NG validation context
7412 * @type: the derivation type
7413 * @c1: the first children
7414 * @c2: the second children
7415 *
7416 * Build a new after definition at runtime.
7417 *
7418 * Returns the new definition or NULL
7419 */
7420static xmlRelaxNGDefinePtr
7421after(xmlRelaxNGValidCtxtPtr ctxt,
7422 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7423 if (c1 == NULL) return(NULL);
7424 if (c2 == NULL) return(NULL);
7425 if (c1->type == XML_RELAXNG_NOT_ALLOWED) {
7426 FREE_DERIV(c2);
7427 return(xmlRelaxNGNotAllowedDeriv);
7428 }
7429 if (c2->type == XML_RELAXNG_NOT_ALLOWED) {
7430 FREE_DERIV(c1);
7431 return(xmlRelaxNGNotAllowedDeriv);
7432 }
7433 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_AFTER, c1, c2));
7434}
7435
7436static xmlRelaxNGDefinePtr
7437after_flip(xmlRelaxNGValidCtxtPtr ctxt,
7438 xmlRelaxNGDefinePtr c1, xmlRelaxNGDefinePtr c2) {
7439 return(after(ctxt, c2, c1));
7440}
7441
7442/**
7443 * oneormore:
7444 * @ctxt: a Relax-NG validation context
7445 * @type: the derivation type
7446 * @c1: the children
7447 *
7448 * Build a new oneormore definition at runtime.
7449 *
7450 * Returns the new definition or NULL
7451 */
7452static xmlRelaxNGDefinePtr
7453oneormore(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGDefinePtr c1) {
7454 if (c1 == NULL) return(NULL);
7455 if (c1->type == XML_RELAXNG_NOT_ALLOWED)
7456 return(xmlRelaxNGNotAllowedDeriv);
7457 return(xmlRelaxNGNewDeriv(ctxt, XML_RELAXNG_ONEORMORE, c1, NULL));
7458}
7459
7460/**
7461 * apply_after:
7462 * @ctxt: a Relax-NG validation context
7463 * @f: the function to apply
7464 * @arg: the definition
7465 *
7466 * Build a new oneormore definition at runtime.
7467 *
7468 * Returns the new definition or NULL
7469 */
7470static xmlRelaxNGDefinePtr
7471apply_after(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGDerivFunc f,
7472 xmlRelaxNGDefinePtr f_arg2, xmlRelaxNGDefinePtr arg) {
7473 xmlRelaxNGDefinePtr ret;
7474
7475 if (arg->type == XML_RELAXNG_NOT_ALLOWED) {
7476 ret = xmlRelaxNGNotAllowedDeriv;
7477 } else if (arg->type == XML_RELAXNG_AFTER) {
7478 REF_DERIV(f_arg2);
7479 REF_DERIV(arg->cont2);
7480 REF_DERIV(arg->content);
7481 ret = after(ctxt, arg->content, f(ctxt, f_arg2, arg->cont2));
7482 } else if (arg->type == XML_RELAXNG_CHOICE) {
7483 REF_DERIV2(f_arg2);
7484 REF_DERIV(arg->content);
7485 REF_DERIV(arg->cont2);
7486 ret = choice(ctxt,
7487 apply_after(ctxt, f, f_arg2, arg->content),
7488 apply_after(ctxt, f, f_arg2, arg->cont2));
7489 } else {
7490 fprintf(stderr, "apply_after called on %s\n", xmlRelaxNGDefName(arg));
7491 }
7492 FREE_DERIV(f_arg2);
7493 FREE_DERIV(arg);
7494 return(ret);
7495}
7496
7497/**
7498 * xmlRelaxNGChildDeriv:
7499 * @ctxt: a Relax-NG validation context
7500 * @define: the definition to verify
7501 * @node: the current node
7502 *
7503 * computes the derivation of a node
7504 *
7505 * Returns the new derivation or NULL in case of error.
7506 */
7507static xmlRelaxNGDefinePtr
7508xmlRelaxNGTextDeriv(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGDefinePtr define,
7509 xmlNodePtr node) {
7510 xmlRelaxNGDefinePtr d1, d2, ret;
7511
7512 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
7513 return(NULL);
7514 switch (define->type) {
7515 case XML_RELAXNG_EMPTY:
7516 if (((node->type == XML_TEXT_NODE) ||
7517 (node->type == XML_CDATA_SECTION_NODE)) &&
7518 (IS_BLANK_NODE(node)))
7519 ret = xmlRelaxNGEmptyDeriv;
7520 else
7521 ret = xmlRelaxNGNotAllowedDeriv;
7522 break;
7523 case XML_RELAXNG_NOT_ALLOWED:
7524 return(define);
7525 case XML_RELAXNG_TEXT:
7526 return(define);
7527 case XML_RELAXNG_CHOICE:
7528 REF_DERIV(define->content);
7529 REF_DERIV(define->cont2);
7530 d1 = xmlRelaxNGTextDeriv(ctxt, define->content, node);
7531 d2 = xmlRelaxNGTextDeriv(ctxt, define->cont2, node);
7532 ret = choice(ctxt, d1, d2);
7533 break;
7534 case XML_RELAXNG_INTERLEAVE:
7535 REF_DERIV2(define->content);
7536 REF_DERIV2(define->cont2);
7537 d1 = interleave(ctxt,
7538 xmlRelaxNGTextDeriv(ctxt, define->content, node),
7539 define->cont2);
7540 d2 = interleave(ctxt,
7541 define->content,
7542 xmlRelaxNGTextDeriv(ctxt, define->cont2, node));
7543 ret = choice(ctxt, d1, d2);
7544 break;
7545 case XML_RELAXNG_AFTER:
7546 REF_DERIV(define->content);
7547 REF_DERIV(define->cont2);
7548 ret = after(ctxt,
7549 xmlRelaxNGTextDeriv(ctxt, define->content, node),
7550 define->cont2);
7551 break;
7552 case XML_RELAXNG_GROUP:
7553 if (node->type == XML_ATTRIBUTE_NODE) {
7554 REF_DERIV2(define->content);
7555 REF_DERIV2(define->cont2);
7556 d1 = group(ctxt,
7557 xmlRelaxNGTextDeriv(ctxt, define->content, node),
7558 define->cont2);
7559 d2 = group(ctxt,
7560 define->content,
7561 xmlRelaxNGTextDeriv(ctxt, define->cont2, node));
7562 ret = choice(ctxt, d1, d2);
7563 } else {
7564 REF_DERIV(define->content);
7565 REF_DERIV(define->cont2);
7566 d1 = group(ctxt,
7567 xmlRelaxNGTextDeriv(ctxt, define->content, node),
7568 define->cont2);
7569 if (xmlRelaxNGIsNullable(define->content)) {
7570 REF_DERIV(define->cont2);
7571 ret = choice(ctxt, d1,
7572 xmlRelaxNGTextDeriv(ctxt, define->cont2, node));
7573 } else
7574 ret = d1;
7575 }
7576 break;
7577 case XML_RELAXNG_ONEORMORE:
7578 REF_DERIV2(define->content);
7579 ret = group(ctxt,
7580 xmlRelaxNGTextDeriv(ctxt, define->content, node),
7581 choice(ctxt,
7582 oneormore(ctxt, define->content),
7583 xmlRelaxNGEmptyDeriv));
7584 break;
7585 case XML_RELAXNG_DEF:
7586 case XML_RELAXNG_REF:
7587 case XML_RELAXNG_PARENTREF:
7588 case XML_RELAXNG_EXTERNALREF:
7589 return(xmlRelaxNGTextDeriv(ctxt, define->content, node));
7590 case XML_RELAXNG_LIST:
7591 if ((node->type == XML_TEXT_NODE) ||
7592 (node->type == XML_CDATA_SECTION_NODE)) {
7593 int res;
7594
7595 res = xmlRelaxNGValidateNodeList(ctxt, define, node);
7596 if (res == 0) {
7597 ret = xmlRelaxNGEmptyDeriv;
7598 } else {
7599 ret = xmlRelaxNGNotAllowedDeriv;
7600 }
7601 } else {
7602 ret = xmlRelaxNGNotAllowedDeriv;
7603 }
7604 break;
7605 case XML_RELAXNG_DATATYPE:
7606 if ((node->type == XML_TEXT_NODE) ||
7607 (node->type == XML_CDATA_SECTION_NODE)) {
7608 int res;
7609
7610 res = xmlRelaxNGValidateNodeDatatype(ctxt, define, node);
7611 if (res == 0) {
7612 ret = xmlRelaxNGEmptyDeriv;
7613 } else {
7614 ret = xmlRelaxNGNotAllowedDeriv;
7615 }
7616 } else {
7617 ret = xmlRelaxNGNotAllowedDeriv;
7618 }
7619 break;
7620 case XML_RELAXNG_VALUE:
7621 if ((node->type == XML_TEXT_NODE) ||
7622 (node->type == XML_CDATA_SECTION_NODE)) {
7623 int res;
7624
7625 res = xmlRelaxNGValidateNodeValue(ctxt, define, node);
7626 if (res == 0) {
7627 ret = xmlRelaxNGEmptyDeriv;
7628 } else {
7629 ret = xmlRelaxNGNotAllowedDeriv;
7630 }
7631 } else {
7632 ret = xmlRelaxNGNotAllowedDeriv;
7633 }
7634 break;
7635 case XML_RELAXNG_ELEMENT:
7636 ret = xmlRelaxNGNotAllowedDeriv;
7637 break;
7638 default:
7639 fprintf(stderr, "textDeriv unsupported on %s\n",
7640 xmlRelaxNGDefName(define));
7641 ret = xmlRelaxNGNotAllowedDeriv;
7642 }
7643 FREE_DERIV(define);
7644 return(ret);
7645}
7646
7647/**
7648 * xmlRelaxNGStartTagOpenDeriv:
7649 * @ctxt: a Relax-NG validation context
7650 * @define: the definition to verify
7651 * @node: the current node
7652 *
7653 * computes the start tag derivation of a node
7654 *
7655 * Returns the new derivation or NULL in case of error.
7656 */
7657static xmlRelaxNGDefinePtr
7658xmlRelaxNGStartTagOpenDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7659 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
7660 xmlRelaxNGDefinePtr d1, d2, ret;
7661
7662 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
7663 return(NULL);
7664#ifdef DEBUG
7665 printf("start_tag: node: %s\ndef : ", node->name);
7666 xmlRelaxNGDumpDefine(stdout, define);
7667#endif
7668 switch (define->type) {
7669 case XML_RELAXNG_CHOICE:
7670 REF_DERIV(define->content);
7671 REF_DERIV(define->cont2);
7672 ret = choice(ctxt,
7673 xmlRelaxNGStartTagOpenDeriv(ctxt, define->content, node),
7674 xmlRelaxNGStartTagOpenDeriv(ctxt, define->cont2, node));
7675 break;
7676 case XML_RELAXNG_INTERLEAVE:
7677 REF_DERIV2(define->content);
7678 REF_DERIV2(define->cont2);
7679 d1 = apply_after(ctxt, interleave_flip, define->cont2,
7680 xmlRelaxNGStartTagOpenDeriv(ctxt, define->content, node));
7681 d2 = apply_after(ctxt, interleave, define->content,
7682 xmlRelaxNGStartTagOpenDeriv(ctxt, define->cont2, node));
7683 ret = choice(ctxt, d1, d2);
7684 break;
7685 case XML_RELAXNG_AFTER:
7686 REF_DERIV(define->content);
7687 REF_DERIV(define->cont2);
7688 d2 = xmlRelaxNGStartTagOpenDeriv(ctxt, define->content, node);
7689 ret = apply_after(ctxt, after_flip, define->cont2, d2);
7690 break;
7691 case XML_RELAXNG_GROUP:
7692 REF_DERIV(define->content);
7693 REF_DERIV(define->cont2);
7694 d2 = xmlRelaxNGStartTagOpenDeriv(ctxt, define->content, node);
7695 d1 = apply_after(ctxt, group_flip, define->cont2, d2);
7696
7697 if (xmlRelaxNGIsNullable(define->content)) {
7698 REF_DERIV(define->cont2);
7699 ret = choice(ctxt,
7700 xmlRelaxNGStartTagOpenDeriv(ctxt, define->cont2, node),
7701 d1);
7702 } else
7703 ret = d1;
7704 break;
7705 case XML_RELAXNG_ONEORMORE:
7706 REF_DERIV2(define->content);
7707 d1 = oneormore(ctxt, define->content);
7708 d2 = choice(ctxt, d1, xmlRelaxNGEmptyDeriv);
7709 ret = apply_after(ctxt, group_flip,
7710 d2,
7711 xmlRelaxNGStartTagOpenDeriv(ctxt,
7712 define->content, node));
7713 break;
7714 case XML_RELAXNG_ELEMENT:
7715 if (xmlRelaxNGNsNameMatch(ctxt, define, node, 1) == 1) {
7716#ifdef debug
7717 printf("start_tag: matched %s\n", node->name);
7718#endif
7719 if (define->content == NULL) {
7720 /* we may have only attributes */
7721 ret = after(ctxt, xmlRelaxNGEmptyDeriv,
7722 xmlRelaxNGEmptyDeriv);
7723 } else {
7724 REF_DERIV(define->content);
7725 ret = after(ctxt, define->content, xmlRelaxNGEmptyDeriv);
7726 }
7727 } else {
7728 ret = xmlRelaxNGNotAllowedDeriv;
7729 }
7730 break;
7731 case XML_RELAXNG_DEF:
7732 case XML_RELAXNG_REF:
7733 case XML_RELAXNG_PARENTREF:
7734 case XML_RELAXNG_EXTERNALREF:
7735 return(xmlRelaxNGStartTagOpenDeriv(ctxt, define->content, node));
7736 default:
7737 ret = xmlRelaxNGNotAllowedDeriv;
7738 }
7739 FREE_DERIV(define);
7740 return(ret);
7741}
7742
7743/**
7744 * xmlRelaxNGAttDeriv:
7745 * @ctxt: a Relax-NG validation context
7746 * @define: the definition to verify
7747 * @node: the current node
7748 *
7749 * computes the start tag derivation of a node
7750 *
7751 * Returns the new derivation or NULL in case of error.
7752 */
7753static xmlRelaxNGDefinePtr
7754xmlRelaxNGAttDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7755 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
7756 xmlRelaxNGDefinePtr ret;
7757
7758 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
7759 return(NULL);
7760#ifdef DEBUG
7761 printf("att: node: %s\ndef : ", node->name);
7762 xmlRelaxNGDumpDefine(stdout, define);
7763#endif
7764 switch (define->type) {
7765 case XML_RELAXNG_CHOICE:
7766 if (node->type != XML_ATTRIBUTE_NODE)
7767 ret = xmlRelaxNGNotAllowedDeriv;
7768 else {
7769 REF_DERIV(define->content);
7770 REF_DERIV(define->cont2);
7771 ret = choice(ctxt,
7772 xmlRelaxNGAttDeriv(ctxt, define->content, node),
7773 xmlRelaxNGAttDeriv(ctxt, define->cont2, node));
7774 }
7775 break;
7776 case XML_RELAXNG_INTERLEAVE:
7777 if (node->type != XML_ATTRIBUTE_NODE)
7778 ret = xmlRelaxNGNotAllowedDeriv;
7779 else {
7780 REF_DERIV2(define->content);
7781 REF_DERIV2(define->cont2);
7782 ret = choice(ctxt,
7783 interleave(ctxt,
7784 xmlRelaxNGAttDeriv(ctxt, define->content, node),
7785 define->cont2),
7786 interleave(ctxt,
7787 define->content,
7788 xmlRelaxNGAttDeriv(ctxt, define->cont2, node)));
7789 }
7790 break;
7791 case XML_RELAXNG_AFTER:
7792 if (node->type != XML_ATTRIBUTE_NODE)
7793 ret = xmlRelaxNGNotAllowedDeriv;
7794 else {
7795 REF_DERIV(define->content);
7796 REF_DERIV(define->cont2);
7797 ret = after(ctxt,
7798 xmlRelaxNGAttDeriv(ctxt, define->content, node),
7799 define->cont2);
7800 }
7801 break;
7802 case XML_RELAXNG_GROUP:
7803 if (node->type != XML_ATTRIBUTE_NODE)
7804 ret = xmlRelaxNGNotAllowedDeriv;
7805 else {
7806 REF_DERIV2(define->content);
7807 REF_DERIV2(define->cont2);
7808 ret = choice(ctxt,
7809 group(ctxt,
7810 xmlRelaxNGAttDeriv(ctxt, define->content, node),
7811 define->cont2),
7812 group(ctxt,
7813 define->content,
7814 xmlRelaxNGAttDeriv(ctxt, define->cont2, node)));
7815 }
7816 break;
7817 case XML_RELAXNG_ONEORMORE:
7818 if (node->type != XML_ATTRIBUTE_NODE)
7819 ret = xmlRelaxNGNotAllowedDeriv;
7820 else {
7821 REF_DERIV(define->content);
7822 REF_DERIV(define);
7823 ret = group(ctxt,
7824 xmlRelaxNGAttDeriv(ctxt, define->content, node),
7825 choice(ctxt,
7826 define, xmlRelaxNGEmptyDeriv));
7827 }
7828 break;
7829 case XML_RELAXNG_DEF:
7830 case XML_RELAXNG_REF:
7831 case XML_RELAXNG_PARENTREF:
7832 case XML_RELAXNG_EXTERNALREF:
7833 return(xmlRelaxNGAttDeriv(ctxt, define->content, node));
7834 case XML_RELAXNG_ATTRIBUTE:
7835 if (node->type != XML_ATTRIBUTE_NODE)
7836 ret = xmlRelaxNGNotAllowedDeriv;
7837 else if (xmlRelaxNGNsNameMatch(ctxt, define, node, 0)) {
7838 xmlChar *value;
7839 int res;
7840
7841#ifdef DEBUG
7842 printf("attr: matched %s\n", node->name);
7843#endif
7844 ctxt->state->node = node;
7845 value = xmlNodeListGetString(node->doc, node->children, 1);
7846 ctxt->state->value = value;
7847 res = xmlRelaxNGValidateValueContent(ctxt, define->content);
7848 if (ctxt->state->value != NULL)
7849 value = ctxt->state->value;
7850 if (value != NULL)
7851 xmlFree(value);
7852 ctxt->state->value = NULL;
7853 if (res == 0) {
7854 ret = xmlRelaxNGEmptyDeriv;
7855 } else {
7856 ret = xmlRelaxNGNotAllowedDeriv;
7857 }
7858 } else
7859 ret = xmlRelaxNGNotAllowedDeriv;
7860 break;
7861 default:
7862 ret = xmlRelaxNGNotAllowedDeriv;
7863 }
7864 FREE_DERIV(define);
7865 return(ret);
7866}
7867
7868/**
7869 * xmlRelaxNGAttsDeriv:
7870 * @ctxt: a Relax-NG validation context
7871 * @define: the definition to verify
7872 * @nodes: the current attribute list
7873 *
7874 * computes the start tag derivation of a node
7875 *
7876 * Returns the new derivation or NULL in case of error.
7877 */
7878static xmlRelaxNGDefinePtr
7879xmlRelaxNGAttsDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7880 xmlRelaxNGDefinePtr define, xmlNodePtr nodes) {
7881 xmlRelaxNGDefinePtr p;
7882
7883 if (nodes == NULL)
7884 return(define);
7885 p = define;
7886 while (nodes != NULL) {
7887 if (nodes->type != XML_ATTRIBUTE_NODE)
7888 return(xmlRelaxNGNotAllowedDeriv);
7889 p = xmlRelaxNGAttDeriv(ctxt, p, nodes);
7890
7891 nodes = nodes->next;
7892 }
7893 return(p);
7894}
7895
7896/**
7897 * xmlRelaxNGEndTagDeriv:
7898 * @ctxt: a Relax-NG validation context
7899 * @define: the definition to verify
7900 * @node: the current node
7901 *
7902 * computes the start tag close derivation of a node
7903 *
7904 * Returns the new derivation or NULL in case of error.
7905 */
7906static xmlRelaxNGDefinePtr
7907xmlRelaxNGEndTagDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7908 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
7909 xmlRelaxNGDefinePtr ret;
7910
7911 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
7912 return(NULL);
7913#ifdef DEBUG
7914 printf("end_tag: node: %s\ndef : ", node->name);
7915 xmlRelaxNGDumpDefine(stdout, define);
7916#endif
7917 switch (define->type) {
7918 case XML_RELAXNG_CHOICE:
7919 REF_DERIV(define->content);
7920 REF_DERIV(define->cont2);
7921 ret = choice(ctxt,
7922 xmlRelaxNGEndTagDeriv(ctxt, define->content, node),
7923 xmlRelaxNGEndTagDeriv(ctxt, define->cont2, node));
7924 break;
7925 case XML_RELAXNG_AFTER:
7926 if (xmlRelaxNGIsNullable(define->content)) {
7927 REF_DERIV(define->cont2);
7928 ret = define->cont2;
7929 } else
7930 ret = xmlRelaxNGNotAllowedDeriv;
7931 break;
7932 case XML_RELAXNG_DEF:
7933 case XML_RELAXNG_REF:
7934 case XML_RELAXNG_PARENTREF:
7935 case XML_RELAXNG_EXTERNALREF:
7936 return(xmlRelaxNGEndTagDeriv(ctxt, define->content, node));
7937 default:
7938 ret = xmlRelaxNGNotAllowedDeriv;
7939 }
7940 FREE_DERIV(define);
7941 return(ret);
7942}
7943
7944/**
7945 * xmlRelaxNGStartTagCloseDeriv:
7946 * @ctxt: a Relax-NG validation context
7947 * @define: the definition to verify
7948 * @node: the current node
7949 *
7950 * computes the start tag close derivation of a node
7951 *
7952 * Returns the new derivation or NULL in case of error.
7953 */
7954static xmlRelaxNGDefinePtr
7955xmlRelaxNGStartTagCloseDeriv(xmlRelaxNGValidCtxtPtr ctxt,
7956 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
7957 xmlRelaxNGDefinePtr ret;
7958
7959 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
7960 return(NULL);
7961#ifdef DEBUG
7962 printf("start_tag_close: node: %s\ndef : ", node->name);
7963 xmlRelaxNGDumpDefine(stdout, define);
7964#endif
7965 switch (define->type) {
7966 case XML_RELAXNG_CHOICE:
7967 REF_DERIV(define->content);
7968 REF_DERIV(define->cont2);
7969 ret = choice(ctxt,
7970 xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node),
7971 xmlRelaxNGStartTagCloseDeriv(ctxt, define->cont2, node));
7972 break;
7973 case XML_RELAXNG_INTERLEAVE:
7974 REF_DERIV(define->content);
7975 REF_DERIV(define->cont2);
7976 ret = interleave(ctxt,
7977 xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node),
7978 xmlRelaxNGStartTagCloseDeriv(ctxt, define->cont2, node));
7979 break;
7980 case XML_RELAXNG_AFTER:
7981 REF_DERIV(define->content);
7982 REF_DERIV(define->cont2);
7983 ret = after(ctxt,
7984 xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node),
7985 define->cont2);
7986 break;
7987 case XML_RELAXNG_GROUP:
7988 REF_DERIV(define->content);
7989 REF_DERIV(define->cont2);
7990 ret = group(ctxt,
7991 xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node),
7992 xmlRelaxNGStartTagCloseDeriv(ctxt, define->cont2, node));
7993 break;
7994 case XML_RELAXNG_ONEORMORE:
7995 REF_DERIV(define->content);
7996 ret = oneormore(ctxt,
7997 xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node));
7998 break;
7999 case XML_RELAXNG_ATTRIBUTE:
8000 ret = xmlRelaxNGNotAllowedDeriv;
8001 break;
8002
8003 case XML_RELAXNG_DEF:
8004 case XML_RELAXNG_REF:
8005 case XML_RELAXNG_PARENTREF:
8006 case XML_RELAXNG_EXTERNALREF:
8007 return(xmlRelaxNGStartTagCloseDeriv(ctxt, define->content, node));
8008 default:
8009 return(define);
8010 }
8011 FREE_DERIV(define);
8012 return(ret);
8013}
8014
8015/**
8016 * xmlRelaxNGChildrenDeriv:
8017 * @ctxt: a Relax-NG validation context
8018 * @define: the definition to verify
8019 * @node: the current node
8020 *
8021 * computes the children derivation of a node
8022 *
8023 * Returns the new derivation or NULL in case of error.
8024 */
8025static xmlRelaxNGDefinePtr
8026xmlRelaxNGChildrenDeriv(xmlRelaxNGValidCtxtPtr ctxt,
8027 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
8028 xmlRelaxNGDefinePtr res = NULL;
8029 xmlNodePtr nodes;
8030
8031 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
8032 return(NULL);
8033#ifdef DEBUG
8034 printf("children: node: %s\ndef : ", node->name);
8035 xmlRelaxNGDumpDefine(stdout, define);
8036#endif
8037 nodes = node->children;
8038 if (nodes == NULL) {
8039 nodes = xmlNewText(BAD_CAST "");
8040 nodes->parent = node;
8041 REF_DERIV2(define);
8042 res = xmlRelaxNGChildDeriv(ctxt, define, nodes);
8043 res = choice(ctxt, define, res);
8044 xmlFreeNode(nodes);
8045 } else if (((nodes->type == XML_TEXT_NODE) ||
8046 (nodes->type == XML_CDATA_SECTION_NODE)) &&
8047 (nodes->next == NULL)) {
8048 REF_DERIV(define);
8049 res = xmlRelaxNGChildDeriv(ctxt, define, nodes);
8050 if (IS_BLANK_NODE(nodes)) {
8051 REF_DERIV(define);
8052 res = choice(ctxt, define, res);
8053 }
8054 } else {
8055 res = define;
8056 REF_DERIV(define);
8057 while (nodes != NULL) {
8058 nodes = xmlRelaxNGSkipIgnored(ctxt, nodes);
8059 if (nodes != NULL) {
8060#ifdef DEBUG
8061 printf("children: node: %s cur %s\ndef : ",
8062 node->name, nodes->name);
8063 xmlRelaxNGDumpDefine(stdout, res);
8064#endif
8065 res = xmlRelaxNGChildDeriv(ctxt, res, nodes);
8066 if (res == xmlRelaxNGNotAllowedDeriv)
8067 break;
8068 if ((nodes->type == XML_TEXT_NODE) ||
8069 (nodes->type == XML_CDATA_SECTION_NODE)) {
8070 /*
8071 * Adjacent text/cdata nodes are collapsed at the
8072 * text node validation test
8073 */
8074 while ((nodes != NULL) &&
8075 (nodes->type != XML_ELEMENT_NODE))
8076 nodes = nodes->next;
8077 } else {
8078 nodes = nodes->next;
8079 }
8080 }
8081 }
8082 }
8083 FREE_DERIV(define);
8084 return(res);
8085}
8086
8087
8088/**
8089 * xmlRelaxNGChildDeriv:
8090 * @ctxt: a Relax-NG validation context
8091 * @define: the definition to verify
8092 * @node: the current node
8093 *
8094 * computes the derivation of a node
8095 *
8096 * Returns the new derivation or NULL in case of error.
8097 */
8098static xmlRelaxNGDefinePtr
8099xmlRelaxNGChildDeriv(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGDefinePtr define,
8100 xmlNodePtr node) {
8101 xmlRelaxNGDefinePtr temp;
8102
8103 if ((ctxt == NULL) || (define == NULL) || (node == NULL))
8104 return(NULL);
8105#ifdef DEBUG
8106 printf("child: node: %s\ndef : ", node->name);
8107 xmlRelaxNGDumpDefine(stdout, define);
8108#endif
8109 if ((node->type == XML_TEXT_NODE) ||
8110 (node->type == XML_CDATA_SECTION_NODE))
8111 return(xmlRelaxNGTextDeriv(ctxt, define, node));
8112 else if (node->type == XML_ELEMENT_NODE) {
8113 temp = xmlRelaxNGStartTagOpenDeriv(ctxt, define, node);
8114 temp = xmlRelaxNGAttsDeriv(ctxt, temp, (xmlNodePtr) node->properties);
8115 temp = xmlRelaxNGStartTagCloseDeriv(ctxt, temp, node);
8116 temp = xmlRelaxNGChildrenDeriv(ctxt, temp, node);
8117 temp = xmlRelaxNGEndTagDeriv(ctxt, temp, node);
8118 return(temp);
8119 }
8120 TODO
8121 return(NULL);
8122}
8123
8124/**
8125 * xmlRelaxNGMatches:
8126 * @ctxt: a Relax-NG validation context
8127 * @define: the definition to verify
8128 * @node: the current node
8129 *
8130 * Check if the node matches the definition
8131 *
8132 * Returns 1 if yes, 0 if no and -1 in case of error
8133 */
8134static int
8135xmlRelaxNGMatches(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGDefinePtr define,
8136 xmlNodePtr node) {
8137 xmlRelaxNGDefinePtr deriv;
8138 int ret;
8139
8140 deriv = xmlRelaxNGChildDeriv(ctxt, define, node);
8141 ret = xmlRelaxNGIsNullable(deriv);
8142 FREE_DERIV(deriv);
8143 return(ret);
8144}
8145
8146/************************************************************************
8147 * *
8148 * Validation interfaces *
8149 * *
8150 ************************************************************************/
8151
8152/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008153 * xmlRelaxNGValidateDocument:
8154 * @ctxt: a Relax-NG validation context
8155 * @doc: the document
8156 *
8157 * Validate the given document
8158 *
8159 * Returns 0 if the validation succeeded or an error code.
8160 */
8161static int
8162xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8163 int ret;
8164 xmlRelaxNGPtr schema;
8165 xmlRelaxNGGrammarPtr grammar;
8166 xmlRelaxNGValidStatePtr state;
8167
8168 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8169 return(-1);
8170
8171 schema = ctxt->schema;
8172 grammar = schema->topgrammar;
8173 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008174 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008175 return(-1);
8176 }
8177 state = xmlRelaxNGNewValidState(ctxt, NULL);
8178 ctxt->state = state;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008179#if USE_DIRECT
Daniel Veillard6eadf632003-01-23 18:29:16 +00008180 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
8181 state = ctxt->state;
8182 if ((state != NULL) && (state->seq != NULL)) {
8183 xmlNodePtr node;
8184
8185 node = state->seq;
8186 node = xmlRelaxNGSkipIgnored(ctxt, node);
8187 if (node != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008188 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008189 ret = -1;
8190 }
8191 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008192#else
8193 ret = xmlRelaxNGMatches(ctxt, grammar->start, xmlDocGetRootElement(doc));
8194 if (ret == 1)
8195 ret = 0;
8196 else
8197 ret = -1;
8198#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008199 xmlRelaxNGFreeValidState(state);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008200 ctxt->state = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008201
8202 return(ret);
8203}
8204
Daniel Veillard6eadf632003-01-23 18:29:16 +00008205/**
8206 * xmlRelaxNGNewValidCtxt:
8207 * @schema: a precompiled XML RelaxNGs
8208 *
8209 * Create an XML RelaxNGs validation context based on the given schema
8210 *
8211 * Returns the validation context or NULL in case of error
8212 */
8213xmlRelaxNGValidCtxtPtr
8214xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8215 xmlRelaxNGValidCtxtPtr ret;
8216
8217 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8218 if (ret == NULL) {
8219 xmlGenericError(xmlGenericErrorContext,
8220 "Failed to allocate new schama validation context\n");
8221 return (NULL);
8222 }
8223 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8224 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008225 ret->error = xmlGenericError;
8226 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008227 ret->errNr = 0;
8228 ret->errMax = 0;
8229 ret->err = NULL;
8230 ret->errTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008231 return (ret);
8232}
8233
8234/**
8235 * xmlRelaxNGFreeValidCtxt:
8236 * @ctxt: the schema validation context
8237 *
8238 * Free the resources associated to the schema validation context
8239 */
8240void
8241xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
8242 if (ctxt == NULL)
8243 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008244 if (ctxt->errTab != NULL)
8245 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008246 xmlFree(ctxt);
8247}
8248
8249/**
8250 * xmlRelaxNGSetValidErrors:
8251 * @ctxt: a Relax-NG validation context
8252 * @err: the error function
8253 * @warn: the warning function
8254 * @ctx: the functions context
8255 *
8256 * Set the error and warning callback informations
8257 */
8258void
8259xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8260 xmlRelaxNGValidityErrorFunc err,
8261 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8262 if (ctxt == NULL)
8263 return;
8264 ctxt->error = err;
8265 ctxt->warning = warn;
8266 ctxt->userData = ctx;
8267}
8268
8269/**
8270 * xmlRelaxNGValidateDoc:
8271 * @ctxt: a Relax-NG validation context
8272 * @doc: a parsed document tree
8273 *
8274 * Validate a document tree in memory.
8275 *
8276 * Returns 0 if the document is valid, a positive error code
8277 * number otherwise and -1 in case of internal or API error.
8278 */
8279int
8280xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8281 int ret;
8282
8283 if ((ctxt == NULL) || (doc == NULL))
8284 return(-1);
8285
8286 ctxt->doc = doc;
8287
8288 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008289 /*
8290 * TODO: build error codes
8291 */
8292 if (ret == -1)
8293 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008294 return(ret);
8295}
8296
8297#endif /* LIBXML_SCHEMAS_ENABLED */
8298