blob: 6b382f41c3784376b220f2ce57910597b373da4a [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 Veillardfd573f12003-03-16 17:52:32 +000015 * - report better mem allocations at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000016 */
17
Daniel Veillard6eadf632003-01-23 18:29:16 +000018#define IN_LIBXML
19#include "libxml.h"
20
21#ifdef LIBXML_SCHEMAS_ENABLED
22
23#include <string.h>
24#include <stdio.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/parser.h>
27#include <libxml/parserInternals.h>
28#include <libxml/hash.h>
29#include <libxml/uri.h>
30
31#include <libxml/relaxng.h>
32
33#include <libxml/xmlschemastypes.h>
34#include <libxml/xmlautomata.h>
35#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000036#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000037
38/*
39 * The Relax-NG namespace
40 */
41static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
42 "http://relaxng.org/ns/structure/1.0";
43
44#define IS_RELAXNG(node, type) \
45 ((node != NULL) && (node->ns != NULL) && \
46 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
47 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
48
49
Daniel Veillard952379b2003-03-17 15:37:12 +000050/* #define DEBUG 1 */
Daniel Veillardc482e262003-02-26 14:48:48 +000051/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
53/* #define DEBUG_TYPE 1 */
54/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000055/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000056/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000057/* #define DEBUG_INCLUDE */
Daniel Veillard6eadf632003-01-23 18:29:16 +000058
59#define UNBOUNDED (1 << 30)
60#define TODO \
61 xmlGenericError(xmlGenericErrorContext, \
62 "Unimplemented block at %s:%d\n", \
63 __FILE__, __LINE__);
64
65typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
66typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
67
68typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
69typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
70
Daniel Veillardd41f4f42003-01-29 21:07:52 +000071typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
72typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
73
Daniel Veillarda9d912d2003-02-01 17:43:10 +000074typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
75typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
76
Daniel Veillard6eadf632003-01-23 18:29:16 +000077typedef enum {
78 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
79 XML_RELAXNG_COMBINE_CHOICE, /* choice */
80 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
81} xmlRelaxNGCombine;
82
Daniel Veillard4c5cf702003-02-21 15:40:34 +000083typedef enum {
84 XML_RELAXNG_CONTENT_ERROR = -1,
85 XML_RELAXNG_CONTENT_EMPTY = 0,
86 XML_RELAXNG_CONTENT_SIMPLE,
87 XML_RELAXNG_CONTENT_COMPLEX
88} xmlRelaxNGContentType;
89
Daniel Veillard6eadf632003-01-23 18:29:16 +000090typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
91typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
92
93struct _xmlRelaxNGGrammar {
94 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
95 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
96 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
97 xmlRelaxNGDefinePtr start; /* <start> content */
98 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +000099 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000100 xmlHashTablePtr defs; /* define* */
101 xmlHashTablePtr refs; /* references */
102};
103
104
Daniel Veillard6eadf632003-01-23 18:29:16 +0000105typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000106 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000107 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
108 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000109 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000110 XML_RELAXNG_TEXT, /* textual content */
111 XML_RELAXNG_ELEMENT, /* an element */
112 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000113 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
115 XML_RELAXNG_LIST, /* a list of patterns */
116 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
117 XML_RELAXNG_DEF, /* a definition */
118 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000119 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000120 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000121 XML_RELAXNG_OPTIONAL, /* optional patterns */
122 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000123 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
124 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
125 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000126 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000127 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000128} xmlRelaxNGType;
129
Daniel Veillardfd573f12003-03-16 17:52:32 +0000130#define IS_NULLABLE 1
131#define IS_NOT_NULLABLE 2
132#define IS_INDETERMINIST 4
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000133
Daniel Veillard6eadf632003-01-23 18:29:16 +0000134struct _xmlRelaxNGDefine {
135 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000136 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000137 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000138 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000139 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000140 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000141 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000142 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000143 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000144 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000145 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000146 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000147 short depth; /* used for the cycle detection */
148 short flags; /* define related flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000149};
150
151/**
152 * _xmlRelaxNG:
153 *
154 * A RelaxNGs definition
155 */
156struct _xmlRelaxNG {
157 xmlRelaxNGGrammarPtr topgrammar;
158 xmlDocPtr doc;
159
160 xmlHashTablePtr defs; /* define */
161 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000162 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
163 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000164 int defNr; /* number of defines used */
165 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000166 void *_private; /* unused by the library for users or bindings */
167};
168
Daniel Veillard77648bb2003-02-20 15:03:22 +0000169#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
170#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
171#define XML_RELAXNG_IN_LIST (1 << 2)
172#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
173#define XML_RELAXNG_IN_START (1 << 4)
174#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
175#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
176#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000177#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
178#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000179
180struct _xmlRelaxNGParserCtxt {
181 void *userData; /* user specific data block */
182 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
183 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000184 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000185
186 xmlRelaxNGPtr schema; /* The schema in use */
187 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000188 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000189 int flags; /* parser flags */
190 int nbErrors; /* number of errors at parse time */
191 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000192 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000193 xmlRelaxNGDefinePtr def; /* the current define */
194
195 int nbInterleaves;
196 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000197
Daniel Veillardc482e262003-02-26 14:48:48 +0000198 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
199 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000201 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000202
Daniel Veillard419a7682003-02-03 23:22:49 +0000203 int defNr; /* number of defines used */
204 int defMax; /* number of defines aloocated */
205 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
206
Daniel Veillard6eadf632003-01-23 18:29:16 +0000207 const char *buffer;
208 int size;
209
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000210 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000211 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000212 int docNr; /* Depth of the parsing stack */
213 int docMax; /* Max depth of the parsing stack */
214 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000215
216 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000217 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000218 int incNr; /* Depth of the include parsing stack */
219 int incMax; /* Max depth of the parsing stack */
220 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000221};
222
223#define FLAGS_IGNORABLE 1
224#define FLAGS_NEGATIVE 2
225
226/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000227 * xmlRelaxNGInterleaveGroup:
228 *
229 * A RelaxNGs partition set associated to lists of definitions
230 */
231typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
232typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
233struct _xmlRelaxNGInterleaveGroup {
234 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
235 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000236 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000237};
238
239/**
240 * xmlRelaxNGPartitions:
241 *
242 * A RelaxNGs partition associated to an interleave group
243 */
244typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
245typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
246struct _xmlRelaxNGPartition {
247 int nbgroups; /* number of groups in the partitions */
248 xmlRelaxNGInterleaveGroupPtr *groups;
249};
250
251/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000252 * xmlRelaxNGValidState:
253 *
254 * A RelaxNGs validation state
255 */
256#define MAX_ATTR 20
257typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
258typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
259struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000260 xmlNodePtr node; /* the current node */
261 xmlNodePtr seq; /* the sequence of children left to validate */
262 int nbAttrs; /* the number of attributes */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000263 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000264 xmlChar *value; /* the value when operating on string */
265 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000266 xmlAttrPtr attrs[1]; /* the array of attributes */
267};
268
269/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000270 * xmlRelaxNGStates:
271 *
272 * A RelaxNGs container for validation state
273 */
274typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
275typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
276struct _xmlRelaxNGStates {
277 int nbState; /* the number of states */
278 int maxState; /* the size of the array */
279 xmlRelaxNGValidStatePtr *tabState;
280};
281
282/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000283 * xmlRelaxNGValidError:
284 *
285 * A RelaxNGs validation error
286 */
287typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
288typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
289struct _xmlRelaxNGValidError {
290 xmlRelaxNGValidErr err; /* the error number */
291 xmlNodePtr node; /* the current node */
292 xmlNodePtr seq; /* the current child */
293 const xmlChar * arg1; /* first arg */
294 const xmlChar * arg2; /* second arg */
295};
296
297/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000298 * xmlRelaxNGValidCtxt:
299 *
300 * A RelaxNGs validation context
301 */
302
303struct _xmlRelaxNGValidCtxt {
304 void *userData; /* user specific data block */
305 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
306 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
307
308 xmlRelaxNGPtr schema; /* The schema in use */
309 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000310 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000311 int depth; /* validation depth */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000312
313 /*
314 * Errors accumulated in branches may have to be stacked to be
315 * provided back when it's sure they affect validation.
316 */
317 xmlRelaxNGValidErrorPtr err; /* Last error */
318 int errNr; /* Depth of the error stack */
319 int errMax; /* Max depth of the error stack */
320 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000321
Daniel Veillardfd573f12003-03-16 17:52:32 +0000322 xmlRelaxNGValidStatePtr state; /* the current validation state */
323 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000324};
325
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000326/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000327 * xmlRelaxNGInclude:
328 *
329 * Structure associated to a RelaxNGs document element
330 */
331struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000332 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000333 xmlChar *href; /* the normalized href value */
334 xmlDocPtr doc; /* the associated XML document */
335 xmlRelaxNGDefinePtr content;/* the definitions */
336 xmlRelaxNGPtr schema; /* the schema */
337};
338
339/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000340 * xmlRelaxNGDocument:
341 *
342 * Structure associated to a RelaxNGs document element
343 */
344struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000345 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000346 xmlChar *href; /* the normalized href value */
347 xmlDocPtr doc; /* the associated XML document */
348 xmlRelaxNGDefinePtr content;/* the definitions */
349 xmlRelaxNGPtr schema; /* the schema */
350};
351
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000352
Daniel Veillard6eadf632003-01-23 18:29:16 +0000353/************************************************************************
354 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000355 * Preliminary type checking interfaces *
356 * *
357 ************************************************************************/
358/**
359 * xmlRelaxNGTypeHave:
360 * @data: data needed for the library
361 * @type: the type name
362 * @value: the value to check
363 *
364 * Function provided by a type library to check if a type is exported
365 *
366 * Returns 1 if yes, 0 if no and -1 in case of error.
367 */
368typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
369
370/**
371 * xmlRelaxNGTypeCheck:
372 * @data: data needed for the library
373 * @type: the type name
374 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000375 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000376 *
377 * Function provided by a type library to check if a value match a type
378 *
379 * Returns 1 if yes, 0 if no and -1 in case of error.
380 */
381typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000382 const xmlChar *value, void **result);
383
384/**
385 * xmlRelaxNGFacetCheck:
386 * @data: data needed for the library
387 * @type: the type name
388 * @facet: the facet name
389 * @val: the facet value
390 * @strval: the string value
391 * @value: the value to check
392 *
393 * Function provided by a type library to check a value facet
394 *
395 * Returns 1 if yes, 0 if no and -1 in case of error.
396 */
397typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
398 const xmlChar *facet, const xmlChar *val,
399 const xmlChar *strval, void *value);
400
401/**
402 * xmlRelaxNGTypeFree:
403 * @data: data needed for the library
404 * @result: the value to free
405 *
406 * Function provided by a type library to free a returned result
407 */
408typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000409
410/**
411 * xmlRelaxNGTypeCompare:
412 * @data: data needed for the library
413 * @type: the type name
414 * @value1: the first value
415 * @value2: the second value
416 *
417 * Function provided by a type library to compare two values accordingly
418 * to a type.
419 *
420 * Returns 1 if yes, 0 if no and -1 in case of error.
421 */
422typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
423 const xmlChar *value1,
424 const xmlChar *value2);
425typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
426typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
427struct _xmlRelaxNGTypeLibrary {
428 const xmlChar *namespace; /* the datatypeLibrary value */
429 void *data; /* data needed for the library */
430 xmlRelaxNGTypeHave have; /* the export function */
431 xmlRelaxNGTypeCheck check; /* the checking function */
432 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000433 xmlRelaxNGFacetCheck facet; /* the facet check function */
434 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000435};
436
437/************************************************************************
438 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000439 * Allocation functions *
440 * *
441 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000442static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
443static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000444static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000445static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000446static int xmlRelaxNGEqualValidState(
447 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
448 xmlRelaxNGValidStatePtr state1,
449 xmlRelaxNGValidStatePtr state2);
450static void xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000451
452/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000453 * xmlRelaxNGFreeDocument:
454 * @docu: a document structure
455 *
456 * Deallocate a RelaxNG document structure.
457 */
458static void
459xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
460{
461 if (docu == NULL)
462 return;
463
464 if (docu->href != NULL)
465 xmlFree(docu->href);
466 if (docu->doc != NULL)
467 xmlFreeDoc(docu->doc);
468 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000469 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000470 xmlFree(docu);
471}
472
473/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000474 * xmlRelaxNGFreeDocumentList:
475 * @docu: a list of document structure
476 *
477 * Deallocate a RelaxNG document structures.
478 */
479static void
480xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
481{
482 xmlRelaxNGDocumentPtr next;
483 while (docu != NULL) {
484 next = docu->next;
485 xmlRelaxNGFreeDocument(docu);
486 docu = next;
487 }
488}
489
490/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000491 * xmlRelaxNGFreeInclude:
492 * @incl: a include structure
493 *
494 * Deallocate a RelaxNG include structure.
495 */
496static void
497xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
498{
499 if (incl == NULL)
500 return;
501
502 if (incl->href != NULL)
503 xmlFree(incl->href);
504 if (incl->doc != NULL)
505 xmlFreeDoc(incl->doc);
506 if (incl->schema != NULL)
507 xmlRelaxNGFree(incl->schema);
508 xmlFree(incl);
509}
510
511/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000512 * xmlRelaxNGFreeIncludeList:
513 * @incl: a include structure list
514 *
515 * Deallocate a RelaxNG include structure.
516 */
517static void
518xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
519{
520 xmlRelaxNGIncludePtr next;
521 while (incl != NULL) {
522 next = incl->next;
523 xmlRelaxNGFreeInclude(incl);
524 incl = next;
525 }
526}
527
528/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000529 * xmlRelaxNGNewRelaxNG:
530 * @ctxt: a Relax-NG validation context (optional)
531 *
532 * Allocate a new RelaxNG structure.
533 *
534 * Returns the newly allocated structure or NULL in case or error
535 */
536static xmlRelaxNGPtr
537xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
538{
539 xmlRelaxNGPtr ret;
540
541 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
542 if (ret == NULL) {
543 if ((ctxt != NULL) && (ctxt->error != NULL))
544 ctxt->error(ctxt->userData, "Out of memory\n");
545 ctxt->nbErrors++;
546 return (NULL);
547 }
548 memset(ret, 0, sizeof(xmlRelaxNG));
549
550 return (ret);
551}
552
553/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000554 * xmlRelaxNGFreeInnerSchema:
555 * @schema: a schema structure
556 *
557 * Deallocate a RelaxNG schema structure.
558 */
559static void
560xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
561{
562 if (schema == NULL)
563 return;
564
565 if (schema->doc != NULL)
566 xmlFreeDoc(schema->doc);
567 if (schema->defTab != NULL) {
568 int i;
569
570 for (i = 0;i < schema->defNr;i++)
571 xmlRelaxNGFreeDefine(schema->defTab[i]);
572 xmlFree(schema->defTab);
573 }
574
575 xmlFree(schema);
576}
577
578/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000579 * xmlRelaxNGFree:
580 * @schema: a schema structure
581 *
582 * Deallocate a RelaxNG structure.
583 */
584void
585xmlRelaxNGFree(xmlRelaxNGPtr schema)
586{
587 if (schema == NULL)
588 return;
589
Daniel Veillard6eadf632003-01-23 18:29:16 +0000590 if (schema->topgrammar != NULL)
591 xmlRelaxNGFreeGrammar(schema->topgrammar);
592 if (schema->doc != NULL)
593 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000594 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000595 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000596 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000597 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000598 if (schema->defTab != NULL) {
599 int i;
600
601 for (i = 0;i < schema->defNr;i++)
602 xmlRelaxNGFreeDefine(schema->defTab[i]);
603 xmlFree(schema->defTab);
604 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000605
606 xmlFree(schema);
607}
608
609/**
610 * xmlRelaxNGNewGrammar:
611 * @ctxt: a Relax-NG validation context (optional)
612 *
613 * Allocate a new RelaxNG grammar.
614 *
615 * Returns the newly allocated structure or NULL in case or error
616 */
617static xmlRelaxNGGrammarPtr
618xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
619{
620 xmlRelaxNGGrammarPtr ret;
621
622 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
623 if (ret == NULL) {
624 if ((ctxt != NULL) && (ctxt->error != NULL))
625 ctxt->error(ctxt->userData, "Out of memory\n");
626 ctxt->nbErrors++;
627 return (NULL);
628 }
629 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
630
631 return (ret);
632}
633
634/**
635 * xmlRelaxNGFreeGrammar:
636 * @grammar: a grammar structure
637 *
638 * Deallocate a RelaxNG grammar structure.
639 */
640static void
641xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
642{
643 if (grammar == NULL)
644 return;
645
Daniel Veillardc482e262003-02-26 14:48:48 +0000646 if (grammar->children != NULL) {
647 xmlRelaxNGFreeGrammar(grammar->children);
648 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000649 if (grammar->next != NULL) {
650 xmlRelaxNGFreeGrammar(grammar->next);
651 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000652 if (grammar->refs != NULL) {
653 xmlHashFree(grammar->refs, NULL);
654 }
655 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000656 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000657 }
658
659 xmlFree(grammar);
660}
661
662/**
663 * xmlRelaxNGNewDefine:
664 * @ctxt: a Relax-NG validation context
665 * @node: the node in the input document.
666 *
667 * Allocate a new RelaxNG define.
668 *
669 * Returns the newly allocated structure or NULL in case or error
670 */
671static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000672xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
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 Veillard6eadf632003-01-23 18:29:16 +0000711 return (ret);
712}
713
714/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000715 * xmlRelaxNGFreePartition:
716 * @partitions: a partition set structure
717 *
718 * Deallocate RelaxNG partition set structures.
719 */
720static void
721xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
722 xmlRelaxNGInterleaveGroupPtr group;
723 int j;
724
725 if (partitions != NULL) {
726 if (partitions->groups != NULL) {
727 for (j = 0;j < partitions->nbgroups;j++) {
728 group = partitions->groups[j];
729 if (group != NULL) {
730 if (group->defs != NULL)
731 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000732 if (group->attrs != NULL)
733 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000734 xmlFree(group);
735 }
736 }
737 xmlFree(partitions->groups);
738 }
739 xmlFree(partitions);
740 }
741}
742/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000743 * xmlRelaxNGFreeDefine:
744 * @define: a define structure
745 *
746 * Deallocate a RelaxNG define structure.
747 */
748static void
749xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
750{
751 if (define == NULL)
752 return;
753
Daniel Veillard419a7682003-02-03 23:22:49 +0000754 if ((define->data != NULL) &&
755 (define->type == XML_RELAXNG_INTERLEAVE))
756 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000757 if (define->name != NULL)
758 xmlFree(define->name);
759 if (define->ns != NULL)
760 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000761 if (define->value != NULL)
762 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000763 xmlFree(define);
764}
765
766/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000767 * xmlRelaxNGNewStates:
768 * @ctxt: a Relax-NG validation context
769 * @size: the default size for the container
770 *
771 * Allocate a new RelaxNG validation state container
772 * TODO: keep a pool in the ctxt
773 *
774 * Returns the newly allocated structure or NULL in case or error
775 */
776static xmlRelaxNGStatesPtr
777xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
778{
779 xmlRelaxNGStatesPtr ret;
780
781 if (size < 16) size = 16;
782
783 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
784 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
785 if (ret == NULL) {
786 if ((ctxt != NULL) && (ctxt->error != NULL))
787 ctxt->error(ctxt->userData, "Out of memory\n");
788 return (NULL);
789 }
790 ret->nbState = 0;
791 ret->maxState = size;
792 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
793 (size) * sizeof(xmlRelaxNGValidStatePtr));
794 if (ret->tabState == NULL) {
795 if ((ctxt != NULL) && (ctxt->error != NULL))
796 ctxt->error(ctxt->userData, "Out of memory\n");
797 xmlFree(ret->tabState);
798 return (NULL);
799 }
800 return(ret);
801}
802
803/**
804 * xmlRelaxNGAddState:
805 * @ctxt: a Relax-NG validation context
806 * @states: the states container
807 * @state: the validation state
808 *
809 * Add a RelaxNG validation state to the container
810 *
811 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
812 */
813static int
814xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
815 xmlRelaxNGValidStatePtr state)
816{
817 int i;
818
819 if (state == NULL) {
820 return(-1);
821 }
822 if (states->nbState >= states->maxState) {
823 xmlRelaxNGValidStatePtr *tmp;
824 int size;
825
826 size = states->maxState * 2;
827 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
828 (size) * sizeof(xmlRelaxNGValidStatePtr));
829 if (tmp == NULL) {
830 if ((ctxt != NULL) && (ctxt->error != NULL))
831 ctxt->error(ctxt->userData, "Out of memory\n");
832 return(-1);
833 }
834 states->tabState = tmp;
835 states->maxState = size;
836 }
837 for (i = 0;i < states->nbState;i++) {
838 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
839 xmlRelaxNGFreeValidState(state);
840 return(0);
841 }
842 }
843 states->tabState[states->nbState++] = state;
844 return(1);
845}
846
847/**
848 * xmlRelaxNGFreeStates:
849 * @ctxt: a Relax-NG validation context
850 * @states: teh container
851 *
852 * Free a RelaxNG validation state container
853 * TODO: keep a pool in the ctxt
854 */
855static void
856xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
857 xmlRelaxNGStatesPtr states)
858{
859 if (states != NULL) {
860 xmlFree(states->tabState);
861 xmlFree(states);
862 }
863}
864
865/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000866 * xmlRelaxNGNewValidState:
867 * @ctxt: a Relax-NG validation context
868 * @node: the current node or NULL for the document
869 *
870 * Allocate a new RelaxNG validation state
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000871 * TODO: keep a pool in the ctxt
Daniel Veillard6eadf632003-01-23 18:29:16 +0000872 *
873 * Returns the newly allocated structure or NULL in case or error
874 */
875static xmlRelaxNGValidStatePtr
876xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
877{
878 xmlRelaxNGValidStatePtr ret;
879 xmlAttrPtr attr;
880 xmlAttrPtr attrs[MAX_ATTR];
881 int nbAttrs = 0;
882 xmlNodePtr root = NULL;
883
884 if (node == NULL) {
885 root = xmlDocGetRootElement(ctxt->doc);
886 if (root == NULL)
887 return(NULL);
888 } else {
889 attr = node->properties;
890 while (attr != NULL) {
891 if (nbAttrs < MAX_ATTR)
892 attrs[nbAttrs++] = attr;
893 else
894 nbAttrs++;
895 attr = attr->next;
896 }
897 }
898
899 if (nbAttrs < MAX_ATTR)
900 attrs[nbAttrs] = NULL;
901 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
902 nbAttrs * sizeof(xmlAttrPtr));
903 if (ret == NULL) {
904 if ((ctxt != NULL) && (ctxt->error != NULL))
905 ctxt->error(ctxt->userData, "Out of memory\n");
906 return (NULL);
907 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000908 ret->value = NULL;
909 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000910 if (node == NULL) {
911 ret->node = (xmlNodePtr) ctxt->doc;
912 ret->seq = root;
913 ret->nbAttrs = 0;
914 } else {
915 ret->node = node;
916 ret->seq = node->children;
917 ret->nbAttrs = nbAttrs;
918 if (nbAttrs > 0) {
919 if (nbAttrs < MAX_ATTR) {
920 memcpy(&(ret->attrs[0]), attrs,
921 sizeof(xmlAttrPtr) * (nbAttrs + 1));
922 } else {
923 attr = node->properties;
924 nbAttrs = 0;
925 while (attr != NULL) {
926 ret->attrs[nbAttrs++] = attr;
927 attr = attr->next;
928 }
929 ret->attrs[nbAttrs] = NULL;
930 }
931 }
932 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000933 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000934 return (ret);
935}
936
937/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000938 * xmlRelaxNGCopyValidState:
939 * @ctxt: a Relax-NG validation context
940 * @state: a validation state
941 *
942 * Copy the validation state
943 *
944 * Returns the newly allocated structure or NULL in case or error
945 */
946static xmlRelaxNGValidStatePtr
947xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
948 xmlRelaxNGValidStatePtr state)
949{
950 xmlRelaxNGValidStatePtr ret;
951 unsigned int size;
952
953 if (state == NULL)
954 return(NULL);
955
956 size = sizeof(xmlRelaxNGValidState) +
957 state->nbAttrs * sizeof(xmlAttrPtr);
958 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size);
959 if (ret == NULL) {
960 if ((ctxt != NULL) && (ctxt->error != NULL))
961 ctxt->error(ctxt->userData, "Out of memory\n");
962 return (NULL);
963 }
964 memcpy(ret, state, size);
965 return(ret);
966}
967
968/**
969 * xmlRelaxNGEqualValidState:
970 * @ctxt: a Relax-NG validation context
971 * @state1: a validation state
972 * @state2: a validation state
973 *
974 * Compare the validation states for equality
975 *
976 * Returns 1 if equald, 0 otherwise
977 */
978static int
979xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
980 xmlRelaxNGValidStatePtr state1,
981 xmlRelaxNGValidStatePtr state2)
982{
983 int i;
984
985 if ((state1 == NULL) || (state2 == NULL))
986 return(0);
987 if (state1 == state2)
988 return(1);
989 if (state1->node != state2->node)
990 return(0);
991 if (state1->seq != state2->seq)
992 return(0);
993 if (state1->nbAttrLeft != state2->nbAttrLeft)
994 return(0);
995 if (state1->nbAttrs != state2->nbAttrs)
996 return(0);
997 if (state1->endvalue != state2->endvalue)
998 return(0);
999 if ((state1->value != state2->value) &&
1000 (!xmlStrEqual(state1->value, state2->value)))
1001 return(0);
1002 for (i = 0;i < state1->nbAttrs;i++) {
1003 if (state1->attrs[i] != state2->attrs[i])
1004 return(0);
1005 }
1006 return(1);
1007}
1008
1009/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001010 * xmlRelaxNGFreeValidState:
1011 * @state: a validation state structure
1012 *
1013 * Deallocate a RelaxNG validation state structure.
Daniel Veillardfd573f12003-03-16 17:52:32 +00001014 * TODO: keep a pool in the ctxt
Daniel Veillard6eadf632003-01-23 18:29:16 +00001015 */
1016static void
1017xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
1018{
1019 if (state == NULL)
1020 return;
1021
1022 xmlFree(state);
1023}
1024
1025/************************************************************************
1026 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001027 * Document functions *
1028 * *
1029 ************************************************************************/
1030static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1031 xmlDocPtr doc);
1032
1033/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001034 * xmlRelaxNGIncludePush:
1035 * @ctxt: the parser context
1036 * @value: the element doc
1037 *
1038 * Pushes a new include on top of the include stack
1039 *
1040 * Returns 0 in case of error, the index in the stack otherwise
1041 */
1042static int
1043xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1044 xmlRelaxNGIncludePtr value)
1045{
1046 if (ctxt->incTab == NULL) {
1047 ctxt->incMax = 4;
1048 ctxt->incNr = 0;
1049 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1050 ctxt->incMax * sizeof(ctxt->incTab[0]));
1051 if (ctxt->incTab == NULL) {
1052 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1053 return (0);
1054 }
1055 }
1056 if (ctxt->incNr >= ctxt->incMax) {
1057 ctxt->incMax *= 2;
1058 ctxt->incTab =
1059 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1060 ctxt->incMax *
1061 sizeof(ctxt->incTab[0]));
1062 if (ctxt->incTab == NULL) {
1063 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1064 return (0);
1065 }
1066 }
1067 ctxt->incTab[ctxt->incNr] = value;
1068 ctxt->inc = value;
1069 return (ctxt->incNr++);
1070}
1071
1072/**
1073 * xmlRelaxNGIncludePop:
1074 * @ctxt: the parser context
1075 *
1076 * Pops the top include from the include stack
1077 *
1078 * Returns the include just removed
1079 */
1080static xmlRelaxNGIncludePtr
1081xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1082{
1083 xmlRelaxNGIncludePtr ret;
1084
1085 if (ctxt->incNr <= 0)
1086 return (0);
1087 ctxt->incNr--;
1088 if (ctxt->incNr > 0)
1089 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1090 else
1091 ctxt->inc = NULL;
1092 ret = ctxt->incTab[ctxt->incNr];
1093 ctxt->incTab[ctxt->incNr] = 0;
1094 return (ret);
1095}
1096
1097/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001098 * xmlRelaxNGRemoveRedefine:
1099 * @ctxt: the parser context
1100 * @URL: the normalized URL
1101 * @target: the included target
1102 * @name: the define name to eliminate
1103 *
1104 * Applies the elimination algorithm of 4.7
1105 *
1106 * Returns 0 in case of error, 1 in case of success.
1107 */
1108static int
1109xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1110 const xmlChar *URL ATTRIBUTE_UNUSED,
1111 xmlNodePtr target, const xmlChar *name) {
1112 int found = 0;
1113 xmlNodePtr tmp, tmp2;
1114 xmlChar *name2;
1115
1116#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001117 if (name == NULL)
1118 xmlGenericError(xmlGenericErrorContext,
1119 "Elimination of <include> start from %s\n", URL);
1120 else
1121 xmlGenericError(xmlGenericErrorContext,
1122 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001123#endif
1124 tmp = target;
1125 while (tmp != NULL) {
1126 tmp2 = tmp->next;
1127 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1128 found = 1;
1129 xmlUnlinkNode(tmp);
1130 xmlFreeNode(tmp);
1131 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1132 name2 = xmlGetProp(tmp, BAD_CAST "name");
1133 xmlRelaxNGNormExtSpace(name2);
1134 if (name2 != NULL) {
1135 if (xmlStrEqual(name, name2)) {
1136 found = 1;
1137 xmlUnlinkNode(tmp);
1138 xmlFreeNode(tmp);
1139 }
1140 xmlFree(name2);
1141 }
1142 } else if (IS_RELAXNG(tmp, "include")) {
1143 xmlChar *href = NULL;
1144 xmlRelaxNGDocumentPtr inc = tmp->_private;
1145
1146 if ((inc != NULL) && (inc->doc != NULL) &&
1147 (inc->doc->children != NULL)) {
1148
1149 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1150#ifdef DEBUG_INCLUDE
1151 href = xmlGetProp(tmp, BAD_CAST "href");
1152#endif
1153 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1154 inc->doc->children->children, name) == 1) {
1155 found = 1;
1156 }
1157 if (href != NULL)
1158 xmlFree(href);
1159 }
1160 }
1161 }
1162 tmp = tmp2;
1163 }
1164 return(found);
1165}
1166
1167/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001168 * xmlRelaxNGLoadInclude:
1169 * @ctxt: the parser context
1170 * @URL: the normalized URL
1171 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001172 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001173 *
1174 * First lookup if the document is already loaded into the parser context,
1175 * check against recursion. If not found the resource is loaded and
1176 * the content is preprocessed before being returned back to the caller.
1177 *
1178 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1179 */
1180static xmlRelaxNGIncludePtr
1181xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001182 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001183 xmlRelaxNGIncludePtr ret = NULL;
1184 xmlDocPtr doc;
1185 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001186 xmlNodePtr root, cur;
1187
1188#ifdef DEBUG_INCLUDE
1189 xmlGenericError(xmlGenericErrorContext,
1190 "xmlRelaxNGLoadInclude(%s)\n", URL);
1191#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001192
1193 /*
1194 * check against recursion in the stack
1195 */
1196 for (i = 0;i < ctxt->incNr;i++) {
1197 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1198 if (ctxt->error != NULL)
1199 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001200 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001201 URL);
1202 ctxt->nbErrors++;
1203 return(NULL);
1204 }
1205 }
1206
1207 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001208 * load the document
1209 */
1210 doc = xmlParseFile((const char *) URL);
1211 if (doc == NULL) {
1212 if (ctxt->error != NULL)
1213 ctxt->error(ctxt->userData,
1214 "xmlRelaxNG: could not load %s\n", URL);
1215 ctxt->nbErrors++;
1216 return (NULL);
1217 }
1218
Daniel Veillard5add8682003-03-10 13:13:58 +00001219#ifdef DEBUG_INCLUDE
1220 xmlGenericError(xmlGenericErrorContext,
1221 "Parsed %s Okay\n", URL);
1222#endif
1223
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001224 /*
1225 * Allocate the document structures and register it first.
1226 */
1227 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1228 if (ret == NULL) {
1229 if (ctxt->error != NULL)
1230 ctxt->error(ctxt->userData,
1231 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1232 ctxt->nbErrors++;
1233 xmlFreeDoc(doc);
1234 return (NULL);
1235 }
1236 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1237 ret->doc = doc;
1238 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001239 ret->next = ctxt->includes;
1240 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001241
1242 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001243 * transmit the ns if needed
1244 */
1245 if (ns != NULL) {
1246 root = xmlDocGetRootElement(doc);
1247 if (root != NULL) {
1248 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1249 xmlSetProp(root, BAD_CAST"ns", ns);
1250 }
1251 }
1252 }
1253
1254 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001255 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001256 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001257 xmlRelaxNGIncludePush(ctxt, ret);
1258
1259 /*
1260 * Some preprocessing of the document content, this include recursing
1261 * in the include stack.
1262 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001263#ifdef DEBUG_INCLUDE
1264 xmlGenericError(xmlGenericErrorContext,
1265 "cleanup of %s\n", URL);
1266#endif
1267
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001268 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1269 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001270 ctxt->inc = NULL;
1271 return(NULL);
1272 }
1273
1274 /*
1275 * Pop up the include from the stack
1276 */
1277 xmlRelaxNGIncludePop(ctxt);
1278
Daniel Veillard5add8682003-03-10 13:13:58 +00001279#ifdef DEBUG_INCLUDE
1280 xmlGenericError(xmlGenericErrorContext,
1281 "Checking of %s\n", URL);
1282#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001283 /*
1284 * Check that the top element is a grammar
1285 */
1286 root = xmlDocGetRootElement(doc);
1287 if (root == NULL) {
1288 if (ctxt->error != NULL)
1289 ctxt->error(ctxt->userData,
1290 "xmlRelaxNG: included document is empty %s\n", URL);
1291 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001292 return (NULL);
1293 }
1294 if (!IS_RELAXNG(root, "grammar")) {
1295 if (ctxt->error != NULL)
1296 ctxt->error(ctxt->userData,
1297 "xmlRelaxNG: included document %s root is not a grammar\n",
1298 URL);
1299 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001300 return (NULL);
1301 }
1302
1303 /*
1304 * Elimination of redefined rules in the include.
1305 */
1306 cur = node->children;
1307 while (cur != NULL) {
1308 if (IS_RELAXNG(cur, "start")) {
1309 int found = 0;
1310
Daniel Veillard5add8682003-03-10 13:13:58 +00001311 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001312 if (!found) {
1313 if (ctxt->error != NULL)
1314 ctxt->error(ctxt->userData,
1315 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1316 URL);
1317 ctxt->nbErrors++;
1318 }
1319 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001320 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001321
1322 name = xmlGetProp(cur, BAD_CAST "name");
1323 if (name == NULL) {
1324 if (ctxt->error != NULL)
1325 ctxt->error(ctxt->userData,
1326 "xmlRelaxNG: include %s has define without name\n",
1327 URL);
1328 ctxt->nbErrors++;
1329 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001330 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001331
Daniel Veillardd2298792003-02-14 16:54:11 +00001332 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001333 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1334 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001335 if (!found) {
1336 if (ctxt->error != NULL)
1337 ctxt->error(ctxt->userData,
1338 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1339 URL, name);
1340 ctxt->nbErrors++;
1341 }
1342 xmlFree(name);
1343 }
1344 }
1345 cur = cur->next;
1346 }
1347
1348
1349 return(ret);
1350}
1351
1352/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001353 * xmlRelaxNGValidErrorPush:
1354 * @ctxt: the validation context
1355 * @err: the error code
1356 * @arg1: the first string argument
1357 * @arg2: the second string argument
1358 *
1359 * Pushes a new error on top of the error stack
1360 *
1361 * Returns 0 in case of error, the index in the stack otherwise
1362 */
1363static int
1364xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1365 const xmlChar *arg1, const xmlChar *arg2)
1366{
1367 xmlRelaxNGValidErrorPtr cur;
1368 if (ctxt->errTab == NULL) {
1369 ctxt->errMax = 8;
1370 ctxt->errNr = 0;
1371 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1372 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1373 if (ctxt->errTab == NULL) {
1374 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1375 return (0);
1376 }
1377 }
1378 if (ctxt->errNr >= ctxt->errMax) {
1379 ctxt->errMax *= 2;
1380 ctxt->errTab =
1381 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1382 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1383 if (ctxt->errTab == NULL) {
1384 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1385 return (0);
1386 }
1387 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001388 if ((ctxt->err != NULL) &&
1389 (ctxt->err->node == ctxt->state->node) &&
1390 (ctxt->err->err == err))
1391 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001392 cur = &ctxt->errTab[ctxt->errNr];
1393 cur->err = err;
1394 cur->arg1 = arg1;
1395 cur->arg2 = arg2;
1396 if (ctxt->state != NULL) {
1397 cur->node = ctxt->state->node;
1398 cur->seq = ctxt->state->seq;
1399 } else {
1400 cur->node = NULL;
1401 cur->seq = NULL;
1402 }
1403 ctxt->err = cur;
1404 return (ctxt->errNr++);
1405}
1406
1407/**
1408 * xmlRelaxNGValidErrorPop:
1409 * @ctxt: the validation context
1410 *
1411 * Pops the top error from the error stack
1412 *
1413 * Returns the error just removed
1414 */
1415static xmlRelaxNGValidErrorPtr
1416xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1417{
1418 xmlRelaxNGValidErrorPtr ret;
1419
1420 if (ctxt->errNr <= 0)
1421 return (NULL);
1422 ctxt->errNr--;
1423 if (ctxt->errNr > 0)
1424 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1425 else
1426 ctxt->err = NULL;
1427 ret = &ctxt->errTab[ctxt->errNr];
1428 return (ret);
1429}
1430
Daniel Veillard42f12e92003-03-07 18:32:59 +00001431/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001432 * xmlRelaxNGDocumentPush:
1433 * @ctxt: the parser context
1434 * @value: the element doc
1435 *
1436 * Pushes a new doc on top of the doc stack
1437 *
1438 * Returns 0 in case of error, the index in the stack otherwise
1439 */
1440static int
1441xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1442 xmlRelaxNGDocumentPtr value)
1443{
1444 if (ctxt->docTab == NULL) {
1445 ctxt->docMax = 4;
1446 ctxt->docNr = 0;
1447 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1448 ctxt->docMax * sizeof(ctxt->docTab[0]));
1449 if (ctxt->docTab == NULL) {
1450 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1451 return (0);
1452 }
1453 }
1454 if (ctxt->docNr >= ctxt->docMax) {
1455 ctxt->docMax *= 2;
1456 ctxt->docTab =
1457 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1458 ctxt->docMax *
1459 sizeof(ctxt->docTab[0]));
1460 if (ctxt->docTab == NULL) {
1461 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1462 return (0);
1463 }
1464 }
1465 ctxt->docTab[ctxt->docNr] = value;
1466 ctxt->doc = value;
1467 return (ctxt->docNr++);
1468}
1469
1470/**
1471 * xmlRelaxNGDocumentPop:
1472 * @ctxt: the parser context
1473 *
1474 * Pops the top doc from the doc stack
1475 *
1476 * Returns the doc just removed
1477 */
1478static xmlRelaxNGDocumentPtr
1479xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1480{
1481 xmlRelaxNGDocumentPtr ret;
1482
1483 if (ctxt->docNr <= 0)
1484 return (0);
1485 ctxt->docNr--;
1486 if (ctxt->docNr > 0)
1487 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1488 else
1489 ctxt->doc = NULL;
1490 ret = ctxt->docTab[ctxt->docNr];
1491 ctxt->docTab[ctxt->docNr] = 0;
1492 return (ret);
1493}
1494
1495/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001496 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001497 * @ctxt: the parser context
1498 * @URL: the normalized URL
1499 * @ns: the inherited ns if any
1500 *
1501 * First lookup if the document is already loaded into the parser context,
1502 * check against recursion. If not found the resource is loaded and
1503 * the content is preprocessed before being returned back to the caller.
1504 *
1505 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1506 */
1507static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001508xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001509 const xmlChar *ns) {
1510 xmlRelaxNGDocumentPtr ret = NULL;
1511 xmlDocPtr doc;
1512 xmlNodePtr root;
1513 int i;
1514
1515 /*
1516 * check against recursion in the stack
1517 */
1518 for (i = 0;i < ctxt->docNr;i++) {
1519 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1520 if (ctxt->error != NULL)
1521 ctxt->error(ctxt->userData,
1522 "Detected an externalRef recursion for %s\n",
1523 URL);
1524 ctxt->nbErrors++;
1525 return(NULL);
1526 }
1527 }
1528
1529 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001530 * load the document
1531 */
1532 doc = xmlParseFile((const char *) URL);
1533 if (doc == NULL) {
1534 if (ctxt->error != NULL)
1535 ctxt->error(ctxt->userData,
1536 "xmlRelaxNG: could not load %s\n", URL);
1537 ctxt->nbErrors++;
1538 return (NULL);
1539 }
1540
1541 /*
1542 * Allocate the document structures and register it first.
1543 */
1544 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1545 if (ret == NULL) {
1546 if (ctxt->error != NULL)
1547 ctxt->error(ctxt->userData,
1548 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1549 ctxt->nbErrors++;
1550 xmlFreeDoc(doc);
1551 return (NULL);
1552 }
1553 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1554 ret->doc = doc;
1555 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001556 ret->next = ctxt->documents;
1557 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001558
1559 /*
1560 * transmit the ns if needed
1561 */
1562 if (ns != NULL) {
1563 root = xmlDocGetRootElement(doc);
1564 if (root != NULL) {
1565 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1566 xmlSetProp(root, BAD_CAST"ns", ns);
1567 }
1568 }
1569 }
1570
1571 /*
1572 * push it on the stack and register it in the hash table
1573 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001574 xmlRelaxNGDocumentPush(ctxt, ret);
1575
1576 /*
1577 * Some preprocessing of the document content
1578 */
1579 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1580 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001581 ctxt->doc = NULL;
1582 return(NULL);
1583 }
1584
1585 xmlRelaxNGDocumentPop(ctxt);
1586
1587 return(ret);
1588}
1589
1590/************************************************************************
1591 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001592 * Error functions *
1593 * *
1594 ************************************************************************/
1595
Daniel Veillard42f12e92003-03-07 18:32:59 +00001596#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL);
1597#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL);
1598#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001599
Daniel Veillardfd573f12003-03-16 17:52:32 +00001600#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001601static const char *
1602xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1603 if (def == NULL)
1604 return("none");
1605 switch(def->type) {
1606 case XML_RELAXNG_EMPTY: return("empty");
1607 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1608 case XML_RELAXNG_EXCEPT: return("except");
1609 case XML_RELAXNG_TEXT: return("text");
1610 case XML_RELAXNG_ELEMENT: return("element");
1611 case XML_RELAXNG_DATATYPE: return("datatype");
1612 case XML_RELAXNG_VALUE: return("value");
1613 case XML_RELAXNG_LIST: return("list");
1614 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1615 case XML_RELAXNG_DEF: return("def");
1616 case XML_RELAXNG_REF: return("ref");
1617 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1618 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001619 case XML_RELAXNG_OPTIONAL: return("optional");
1620 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001621 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1622 case XML_RELAXNG_CHOICE: return("choice");
1623 case XML_RELAXNG_GROUP: return("group");
1624 case XML_RELAXNG_INTERLEAVE: return("interleave");
1625 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001626 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001627 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001628 }
1629 return("unknown");
1630}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001631#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001632
Daniel Veillard6eadf632003-01-23 18:29:16 +00001633/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001634 * xmlRelaxNGGetErrorString:
1635 * @err: the error code
1636 * @arg1: the first string argument
1637 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001638 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001639 * computes a formatted error string for the given error code and args
1640 *
1641 * Returns the error string, it must be deallocated by the caller
1642 */
1643static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001644xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1645 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001646 char msg[1000];
1647
1648 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001649 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001650 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001651 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001652
1653 msg[0] = 0;
1654 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001655 case XML_RELAXNG_OK:
1656 return(NULL);
1657 case XML_RELAXNG_ERR_MEMORY:
1658 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001659 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001660 snprintf(msg, 1000, "failed to validate type %s", arg1);
1661 break;
1662 case XML_RELAXNG_ERR_TYPEVAL:
1663 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1664 break;
1665 case XML_RELAXNG_ERR_TYPECMP:
1666 snprintf(msg, 1000, "failed to compare type %s", arg1);
1667 break;
1668 case XML_RELAXNG_ERR_NOSTATE:
1669 return(xmlCharStrdup("Internal error: no state"));
1670 case XML_RELAXNG_ERR_NODEFINE:
1671 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001672 case XML_RELAXNG_ERR_INTERNAL:
1673 snprintf(msg, 1000, "Internal error: %s", arg1);
1674 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001675 case XML_RELAXNG_ERR_LISTEXTRA:
1676 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1677 break;
1678 case XML_RELAXNG_ERR_INTERNODATA:
1679 return(xmlCharStrdup("Internal: interleave block has no data"));
1680 case XML_RELAXNG_ERR_INTERSEQ:
1681 return(xmlCharStrdup("Invalid sequence in interleave"));
1682 case XML_RELAXNG_ERR_INTEREXTRA:
1683 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1684 break;
1685 case XML_RELAXNG_ERR_ELEMNAME:
1686 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1687 break;
1688 case XML_RELAXNG_ERR_ELEMNONS:
1689 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1690 break;
1691 case XML_RELAXNG_ERR_ELEMWRONGNS:
1692 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1693 arg1, arg2);
1694 break;
1695 case XML_RELAXNG_ERR_ELEMEXTRANS:
1696 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1697 break;
1698 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1699 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1700 break;
1701 case XML_RELAXNG_ERR_NOELEM:
1702 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1703 break;
1704 case XML_RELAXNG_ERR_NOTELEM:
1705 return(xmlCharStrdup("Expecting an element got text"));
1706 case XML_RELAXNG_ERR_ATTRVALID:
1707 snprintf(msg, 1000, "Element %s failed to validate attributes",
1708 arg1);
1709 break;
1710 case XML_RELAXNG_ERR_CONTENTVALID:
1711 snprintf(msg, 1000, "Element %s failed to validate content",
1712 arg1);
1713 break;
1714 case XML_RELAXNG_ERR_EXTRACONTENT:
1715 snprintf(msg, 1000, "Element %s has extra content: %s",
1716 arg1, arg2);
1717 break;
1718 case XML_RELAXNG_ERR_INVALIDATTR:
1719 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1720 arg1, arg2);
1721 break;
1722 case XML_RELAXNG_ERR_DATAELEM:
1723 snprintf(msg, 1000, "Datatype element %s has child elements",
1724 arg1);
1725 break;
1726 case XML_RELAXNG_ERR_VALELEM:
1727 snprintf(msg, 1000, "Value element %s has child elements",
1728 arg1);
1729 break;
1730 case XML_RELAXNG_ERR_LISTELEM:
1731 snprintf(msg, 1000, "List element %s has child elements",
1732 arg1);
1733 break;
1734 case XML_RELAXNG_ERR_DATATYPE:
1735 snprintf(msg, 1000, "Error validating datatype %s",
1736 arg1);
1737 break;
1738 case XML_RELAXNG_ERR_VALUE:
1739 snprintf(msg, 1000, "Error validating value %s",
1740 arg1);
1741 break;
1742 case XML_RELAXNG_ERR_LIST:
1743 return(xmlCharStrdup("Error validating list"));
1744 case XML_RELAXNG_ERR_NOGRAMMAR:
1745 return(xmlCharStrdup("No top grammar defined"));
1746 case XML_RELAXNG_ERR_EXTRADATA:
1747 return(xmlCharStrdup("Extra data in the document"));
1748 default:
1749 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001750 }
1751 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001752 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001753 }
1754 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001755 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001756}
1757
1758/**
1759 * xmlRelaxNGValidErrorContext:
1760 * @ctxt: the validation context
1761 * @node: the node
1762 * @child: the node child generating the problem.
1763 *
1764 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001765 */
1766static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001767xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1768 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001769{
1770 int line = 0;
1771 const xmlChar *file = NULL;
1772 const xmlChar *name = NULL;
1773 const char *type = "error";
1774
1775 if ((ctxt == NULL) || (ctxt->error == NULL))
1776 return;
1777
1778 if (child != NULL)
1779 node = child;
1780
1781 if (node != NULL) {
1782 if ((node->type == XML_DOCUMENT_NODE) ||
1783 (node->type == XML_HTML_DOCUMENT_NODE)) {
1784 xmlDocPtr doc = (xmlDocPtr) node;
1785
1786 file = doc->URL;
1787 } else {
1788 /*
1789 * Try to find contextual informations to report
1790 */
1791 if (node->type == XML_ELEMENT_NODE) {
1792 line = (int) node->content;
1793 } else if ((node->prev != NULL) &&
1794 (node->prev->type == XML_ELEMENT_NODE)) {
1795 line = (int) node->prev->content;
1796 } else if ((node->parent != NULL) &&
1797 (node->parent->type == XML_ELEMENT_NODE)) {
1798 line = (int) node->parent->content;
1799 }
1800 if ((node->doc != NULL) && (node->doc->URL != NULL))
1801 file = node->doc->URL;
1802 if (node->name != NULL)
1803 name = node->name;
1804 }
1805 }
1806
Daniel Veillard42f12e92003-03-07 18:32:59 +00001807 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001808
1809 if ((file != NULL) && (line != 0) && (name != NULL))
1810 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1811 type, file, line, name);
1812 else if ((file != NULL) && (name != NULL))
1813 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1814 type, file, name);
1815 else if ((file != NULL) && (line != 0))
1816 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1817 else if (file != NULL)
1818 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1819 else if (name != NULL)
1820 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1821 else
1822 ctxt->error(ctxt->userData, "%s\n", type);
1823}
Daniel Veillard42f12e92003-03-07 18:32:59 +00001824
1825/**
1826 * xmlRelaxNGShowValidError:
1827 * @ctxt: the validation context
1828 * @err: the error number
1829 * @node: the node
1830 * @child: the node child generating the problem.
1831 * @arg1: the first argument
1832 * @arg2: the second argument
1833 *
1834 * Show a validation error.
1835 */
1836static void
1837xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1838 xmlNodePtr node, xmlNodePtr child,
1839 const xmlChar *arg1, const xmlChar *arg2)
1840{
1841 xmlChar *msg;
1842
1843 if (ctxt->error == NULL)
1844 return;
1845
1846 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
1847 if (msg == NULL)
1848 return;
1849
1850 xmlRelaxNGValidErrorContext(ctxt, node, child);
1851 ctxt->error(ctxt->userData, "%s\n", msg);
1852 xmlFree(msg);
1853}
1854
1855/**
1856 * xmlRelaxNGDumpValidError:
1857 * @ctxt: the validation context
1858 *
1859 * Show all validation error over a given index.
1860 */
1861static void
1862xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
1863 int i;
1864 xmlRelaxNGValidErrorPtr err;
1865
1866 for (i = 0;i < ctxt->errNr;i++) {
1867 err = &ctxt->errTab[i];
1868 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
1869 err->arg1, err->arg2);
1870 }
1871 ctxt->errNr = 0;
1872}
1873/**
1874 * xmlRelaxNGAddValidError:
1875 * @ctxt: the validation context
1876 * @err: the error number
1877 * @arg1: the first argument
1878 * @arg2: the second argument
1879 *
1880 * Register a validation error, either generating it if it's sure
1881 * or stacking it for later handling if unsure.
1882 */
1883static void
1884xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1885 const xmlChar *arg1, const xmlChar *arg2)
1886{
1887 if ((ctxt == NULL) || (ctxt->error == NULL))
1888 return;
1889
1890 /*
1891 * generate the error directly
1892 */
1893 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
1894 xmlNodePtr node, seq;
1895 /*
1896 * Flush first any stacked error which might be the
1897 * real cause of the problem.
1898 */
1899 if (ctxt->errNr != 0)
1900 xmlRelaxNGDumpValidError(ctxt);
1901 if (ctxt->state != NULL) {
1902 node = ctxt->state->node;
1903 seq = ctxt->state->seq;
1904 } else {
1905 node = seq = NULL;
1906 }
1907 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
1908 }
1909 /*
1910 * Stack the error for later processing if needed
1911 */
1912 else {
1913 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2);
1914 }
1915}
1916
Daniel Veillard6eadf632003-01-23 18:29:16 +00001917
1918/************************************************************************
1919 * *
1920 * Type library hooks *
1921 * *
1922 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00001923static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1924 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001925
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001926/**
1927 * xmlRelaxNGSchemaTypeHave:
1928 * @data: data needed for the library
1929 * @type: the type name
1930 *
1931 * Check if the given type is provided by
1932 * the W3C XMLSchema Datatype library.
1933 *
1934 * Returns 1 if yes, 0 if no and -1 in case of error.
1935 */
1936static int
1937xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001938 const xmlChar *type) {
1939 xmlSchemaTypePtr typ;
1940
1941 if (type == NULL)
1942 return(-1);
1943 typ = xmlSchemaGetPredefinedType(type,
1944 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1945 if (typ == NULL)
1946 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001947 return(1);
1948}
1949
1950/**
1951 * xmlRelaxNGSchemaTypeCheck:
1952 * @data: data needed for the library
1953 * @type: the type name
1954 * @value: the value to check
1955 *
1956 * Check if the given type and value are validated by
1957 * the W3C XMLSchema Datatype library.
1958 *
1959 * Returns 1 if yes, 0 if no and -1 in case of error.
1960 */
1961static int
1962xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001963 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001964 const xmlChar *value,
1965 void **result) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001966 xmlSchemaTypePtr typ;
1967 int ret;
1968
1969 /*
1970 * TODO: the type should be cached ab provided back, interface subject
1971 * to changes.
1972 * TODO: handle facets, may require an additional interface and keep
1973 * the value returned from the validation.
1974 */
1975 if ((type == NULL) || (value == NULL))
1976 return(-1);
1977 typ = xmlSchemaGetPredefinedType(type,
1978 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1979 if (typ == NULL)
1980 return(-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001981 ret = xmlSchemaValidatePredefinedType(typ, value,
1982 (xmlSchemaValPtr *) result);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001983 if (ret == 0)
1984 return(1);
1985 if (ret > 0)
1986 return(0);
1987 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001988}
1989
1990/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00001991 * xmlRelaxNGSchemaFacetCheck:
1992 * @data: data needed for the library
1993 * @type: the type name
1994 * @facet: the facet name
1995 * @val: the facet value
1996 * @strval: the string value
1997 * @value: the value to check
1998 *
1999 * Function provided by a type library to check a value facet
2000 *
2001 * Returns 1 if yes, 0 if no and -1 in case of error.
2002 */
2003static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002004xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002005 const xmlChar *facetname, const xmlChar *val,
2006 const xmlChar *strval, void *value) {
2007 xmlSchemaFacetPtr facet;
2008 xmlSchemaTypePtr typ;
2009 int ret;
2010
2011 if ((type == NULL) || (strval == NULL))
2012 return(-1);
2013 typ = xmlSchemaGetPredefinedType(type,
2014 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2015 if (typ == NULL)
2016 return(-1);
2017
2018 facet = xmlSchemaNewFacet();
2019 if (facet == NULL)
2020 return(-1);
2021
2022 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2023 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2024 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2025 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2026 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2027 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2028 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2029 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2030 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2031 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2032 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2033 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2034 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2035 facet->type = XML_SCHEMA_FACET_PATTERN;
2036 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2037 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2038 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2039 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2040 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2041 facet->type = XML_SCHEMA_FACET_LENGTH;
2042 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2043 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2044 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2045 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2046 } else {
2047 xmlSchemaFreeFacet(facet);
2048 return(-1);
2049 }
2050 facet->value = xmlStrdup(val);
2051 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2052 if (ret != 0) {
2053 xmlSchemaFreeFacet(facet);
2054 return(-1);
2055 }
2056 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2057 xmlSchemaFreeFacet(facet);
2058 if (ret != 0)
2059 return(-1);
2060 return(0);
2061}
2062
2063/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002064 * xmlRelaxNGSchemaTypeCompare:
2065 * @data: data needed for the library
2066 * @type: the type name
2067 * @value1: the first value
2068 * @value2: the second value
2069 *
2070 * Compare two values accordingly a type from the W3C XMLSchema
2071 * Datatype library.
2072 *
2073 * Returns 1 if yes, 0 if no and -1 in case of error.
2074 */
2075static int
2076xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2077 const xmlChar *type ATTRIBUTE_UNUSED,
2078 const xmlChar *value1 ATTRIBUTE_UNUSED,
2079 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2080 TODO
2081 return(1);
2082}
2083
2084/**
2085 * xmlRelaxNGDefaultTypeHave:
2086 * @data: data needed for the library
2087 * @type: the type name
2088 *
2089 * Check if the given type is provided by
2090 * the default datatype library.
2091 *
2092 * Returns 1 if yes, 0 if no and -1 in case of error.
2093 */
2094static int
2095xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2096 if (type == NULL)
2097 return(-1);
2098 if (xmlStrEqual(type, BAD_CAST "string"))
2099 return(1);
2100 if (xmlStrEqual(type, BAD_CAST "token"))
2101 return(1);
2102 return(0);
2103}
2104
2105/**
2106 * xmlRelaxNGDefaultTypeCheck:
2107 * @data: data needed for the library
2108 * @type: the type name
2109 * @value: the value to check
2110 *
2111 * Check if the given type and value are validated by
2112 * the default datatype library.
2113 *
2114 * Returns 1 if yes, 0 if no and -1 in case of error.
2115 */
2116static int
2117xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2118 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002119 const xmlChar *value ATTRIBUTE_UNUSED,
2120 void **result ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002121 if (value == NULL)
2122 return(-1);
2123 if (xmlStrEqual(type, BAD_CAST "string"))
2124 return(1);
2125 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002126 return(1);
2127 }
2128
2129 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002130}
2131
2132/**
2133 * xmlRelaxNGDefaultTypeCompare:
2134 * @data: data needed for the library
2135 * @type: the type name
2136 * @value1: the first value
2137 * @value2: the second value
2138 *
2139 * Compare two values accordingly a type from the default
2140 * datatype library.
2141 *
2142 * Returns 1 if yes, 0 if no and -1 in case of error.
2143 */
2144static int
2145xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2146 const xmlChar *type ATTRIBUTE_UNUSED,
2147 const xmlChar *value1 ATTRIBUTE_UNUSED,
2148 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002149 int ret = -1;
2150
2151 if (xmlStrEqual(type, BAD_CAST "string")) {
2152 ret = xmlStrEqual(value1, value2);
2153 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2154 if (!xmlStrEqual(value1, value2)) {
2155 xmlChar *nval, *nvalue;
2156
2157 /*
2158 * TODO: trivial optimizations are possible by
2159 * computing at compile-time
2160 */
2161 nval = xmlRelaxNGNormalize(NULL, value1);
2162 nvalue = xmlRelaxNGNormalize(NULL, value2);
2163
Daniel Veillardd4310742003-02-18 21:12:46 +00002164 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002165 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002166 else if (xmlStrEqual(nval, nvalue))
2167 ret = 1;
2168 else
2169 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002170 if (nval != NULL)
2171 xmlFree(nval);
2172 if (nvalue != NULL)
2173 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002174 } else
2175 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002176 }
2177 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002178}
2179
2180static int xmlRelaxNGTypeInitialized = 0;
2181static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2182
2183/**
2184 * xmlRelaxNGFreeTypeLibrary:
2185 * @lib: the type library structure
2186 * @namespace: the URI bound to the library
2187 *
2188 * Free the structure associated to the type library
2189 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002190static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002191xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2192 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2193 if (lib == NULL)
2194 return;
2195 if (lib->namespace != NULL)
2196 xmlFree((xmlChar *)lib->namespace);
2197 xmlFree(lib);
2198}
2199
2200/**
2201 * xmlRelaxNGRegisterTypeLibrary:
2202 * @namespace: the URI bound to the library
2203 * @data: data associated to the library
2204 * @have: the provide function
2205 * @check: the checking function
2206 * @comp: the comparison function
2207 *
2208 * Register a new type library
2209 *
2210 * Returns 0 in case of success and -1 in case of error.
2211 */
2212static int
2213xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2214 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002215 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2216 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002217 xmlRelaxNGTypeLibraryPtr lib;
2218 int ret;
2219
2220 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2221 (check == NULL) || (comp == NULL))
2222 return(-1);
2223 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2224 xmlGenericError(xmlGenericErrorContext,
2225 "Relax-NG types library '%s' already registered\n",
2226 namespace);
2227 return(-1);
2228 }
2229 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2230 if (lib == NULL) {
2231 xmlGenericError(xmlGenericErrorContext,
2232 "Relax-NG types library '%s' malloc() failed\n",
2233 namespace);
2234 return (-1);
2235 }
2236 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2237 lib->namespace = xmlStrdup(namespace);
2238 lib->data = data;
2239 lib->have = have;
2240 lib->comp = comp;
2241 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002242 lib->facet = facet;
2243 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002244 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2245 if (ret < 0) {
2246 xmlGenericError(xmlGenericErrorContext,
2247 "Relax-NG types library failed to register '%s'\n",
2248 namespace);
2249 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2250 return(-1);
2251 }
2252 return(0);
2253}
2254
2255/**
2256 * xmlRelaxNGInitTypes:
2257 *
2258 * Initilize the default type libraries.
2259 *
2260 * Returns 0 in case of success and -1 in case of error.
2261 */
2262static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002263xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002264 if (xmlRelaxNGTypeInitialized != 0)
2265 return(0);
2266 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2267 if (xmlRelaxNGRegisteredTypes == NULL) {
2268 xmlGenericError(xmlGenericErrorContext,
2269 "Failed to allocate sh table for Relax-NG types\n");
2270 return(-1);
2271 }
2272 xmlRelaxNGRegisterTypeLibrary(
2273 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2274 NULL,
2275 xmlRelaxNGSchemaTypeHave,
2276 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002277 xmlRelaxNGSchemaTypeCompare,
2278 xmlRelaxNGSchemaFacetCheck,
2279 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002280 xmlRelaxNGRegisterTypeLibrary(
2281 xmlRelaxNGNs,
2282 NULL,
2283 xmlRelaxNGDefaultTypeHave,
2284 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002285 xmlRelaxNGDefaultTypeCompare,
2286 NULL,
2287 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002288 xmlRelaxNGTypeInitialized = 1;
2289 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002290}
2291
2292/**
2293 * xmlRelaxNGCleanupTypes:
2294 *
2295 * Cleanup the default Schemas type library associated to RelaxNG
2296 */
2297void
2298xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002299 if (xmlRelaxNGTypeInitialized == 0)
2300 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002301 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002302 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2303 xmlRelaxNGFreeTypeLibrary);
2304 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002305}
2306
2307/************************************************************************
2308 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002309 * Compiling element content into regexp *
2310 * *
2311 * Sometime the element content can be compiled into a pure regexp, *
2312 * This allows a faster execution and streamability at that level *
2313 * *
2314 ************************************************************************/
2315
2316/**
2317 * xmlRelaxNGIsCompileable:
2318 * @define: the definition to check
2319 *
2320 * Check if a definition is nullable.
2321 *
2322 * Returns 1 if yes, 0 if no and -1 in case of error
2323 */
2324static int
2325xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2326 if (def == NULL) {
2327 return(-1);
2328 }
2329 switch(def->type) {
2330 case XML_RELAXNG_REF:
2331 case XML_RELAXNG_EXTERNALREF:
2332 case XML_RELAXNG_PARENTREF:
2333 case XML_RELAXNG_NOOP:
2334 case XML_RELAXNG_START:
2335 return(xmlRelaxNGIsCompileable(def->content));
2336 case XML_RELAXNG_TEXT:
2337 case XML_RELAXNG_DATATYPE:
2338 case XML_RELAXNG_LIST:
2339 case XML_RELAXNG_PARAM:
2340 case XML_RELAXNG_VALUE:
2341
2342 case XML_RELAXNG_EMPTY:
2343 case XML_RELAXNG_ELEMENT:
2344 return(1);
2345 case XML_RELAXNG_OPTIONAL:
2346 case XML_RELAXNG_ZEROORMORE:
2347 case XML_RELAXNG_ONEORMORE:
2348 case XML_RELAXNG_CHOICE:
2349 case XML_RELAXNG_GROUP:
2350 case XML_RELAXNG_DEF: {
2351 xmlRelaxNGDefinePtr list;
2352 int ret;
2353
2354 list = def->content;
2355 while (list != NULL) {
2356 ret = xmlRelaxNGIsCompileable(list);
2357 if (ret != 1)
2358 return(ret);
2359 list = list->next;
2360 }
2361 return(1);
2362 }
2363 case XML_RELAXNG_EXCEPT:
2364 case XML_RELAXNG_ATTRIBUTE:
2365 case XML_RELAXNG_INTERLEAVE:
2366 return(0);
2367 case XML_RELAXNG_NOT_ALLOWED:
2368 return(-1);
2369 }
2370 return(-1);
2371}
2372
2373/************************************************************************
2374 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002375 * Parsing functions *
2376 * *
2377 ************************************************************************/
2378
2379static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2380 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2381static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2382 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2383static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002384 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002385static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2386 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002387static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2388 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002389static int xmlRelaxNGParseGrammarContent(
2390 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002391static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2392 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2393 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002394static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2395 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002396static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2397 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002398
2399
2400#define IS_BLANK_NODE(n) \
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002401 ((((n)->type == XML_TEXT_NODE) || \
2402 ((n)->type == XML_CDATA_SECTION_NODE)) && \
2403 (xmlRelaxNGIsBlank((n)->content)))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002404
2405/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002406 * xmlRelaxNGIsNullable:
2407 * @define: the definition to verify
2408 *
2409 * Check if a definition is nullable.
2410 *
2411 * Returns 1 if yes, 0 if no and -1 in case of error
2412 */
2413static int
2414xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2415 int ret;
2416 if (define == NULL)
2417 return(-1);
2418
2419 if (define->flags & IS_NULLABLE)
2420 return(1);
2421 if (define->flags & IS_NOT_NULLABLE)
2422 return(0);
2423 switch (define->type) {
2424 case XML_RELAXNG_EMPTY:
2425 case XML_RELAXNG_TEXT:
2426 ret = 1; break;
2427 case XML_RELAXNG_NOOP:
2428 case XML_RELAXNG_DEF:
2429 case XML_RELAXNG_REF:
2430 case XML_RELAXNG_EXTERNALREF:
2431 case XML_RELAXNG_PARENTREF:
2432 case XML_RELAXNG_ONEORMORE:
2433 ret = xmlRelaxNGIsNullable(define->content);
2434 break;
2435 case XML_RELAXNG_EXCEPT:
2436 case XML_RELAXNG_NOT_ALLOWED:
2437 case XML_RELAXNG_ELEMENT:
2438 case XML_RELAXNG_DATATYPE:
2439 case XML_RELAXNG_PARAM:
2440 case XML_RELAXNG_VALUE:
2441 case XML_RELAXNG_LIST:
2442 case XML_RELAXNG_ATTRIBUTE:
2443 ret = 0; break;
2444 case XML_RELAXNG_CHOICE: {
2445 xmlRelaxNGDefinePtr list = define->content;
2446
2447 while (list != NULL) {
2448 ret = xmlRelaxNGIsNullable(list);
2449 if (ret != 0)
2450 goto done;
2451 list = list->next;
2452 }
2453 ret = 0; break;
2454 }
2455 case XML_RELAXNG_START:
2456 case XML_RELAXNG_INTERLEAVE:
2457 case XML_RELAXNG_GROUP: {
2458 xmlRelaxNGDefinePtr list = define->content;
2459
2460 while (list != NULL) {
2461 ret = xmlRelaxNGIsNullable(list);
2462 if (ret != 1)
2463 goto done;
2464 list = list->next;
2465 }
2466 return(1);
2467 }
2468 default:
2469 return(-1);
2470 }
2471done:
2472 if (ret == 0)
2473 define->flags |= IS_NOT_NULLABLE;
2474 if (ret == 1)
2475 define->flags |= IS_NULLABLE;
2476 return(ret);
2477}
2478
2479/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002480 * xmlRelaxNGIsBlank:
2481 * @str: a string
2482 *
2483 * Check if a string is ignorable c.f. 4.2. Whitespace
2484 *
2485 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2486 */
2487static int
2488xmlRelaxNGIsBlank(xmlChar *str) {
2489 if (str == NULL)
2490 return(1);
2491 while (*str != 0) {
2492 if (!(IS_BLANK(*str))) return(0);
2493 str++;
2494 }
2495 return(1);
2496}
2497
Daniel Veillard6eadf632003-01-23 18:29:16 +00002498/**
2499 * xmlRelaxNGGetDataTypeLibrary:
2500 * @ctxt: a Relax-NG parser context
2501 * @node: the current data or value element
2502 *
2503 * Applies algorithm from 4.3. datatypeLibrary attribute
2504 *
2505 * Returns the datatypeLibary value or NULL if not found
2506 */
2507static xmlChar *
2508xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2509 xmlNodePtr node) {
2510 xmlChar *ret, *escape;
2511
Daniel Veillard6eadf632003-01-23 18:29:16 +00002512 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2513 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2514 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002515 if (ret[0] == 0) {
2516 xmlFree(ret);
2517 return(NULL);
2518 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002519 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002520 if (escape == NULL) {
2521 return(ret);
2522 }
2523 xmlFree(ret);
2524 return(escape);
2525 }
2526 }
2527 node = node->parent;
2528 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002529 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2530 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002531 if (ret[0] == 0) {
2532 xmlFree(ret);
2533 return(NULL);
2534 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002535 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2536 if (escape == NULL) {
2537 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002538 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002539 xmlFree(ret);
2540 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002541 }
2542 node = node->parent;
2543 }
2544 return(NULL);
2545}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002546
2547/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002548 * xmlRelaxNGParseValue:
2549 * @ctxt: a Relax-NG parser context
2550 * @node: the data node.
2551 *
2552 * parse the content of a RelaxNG value node.
2553 *
2554 * Returns the definition pointer or NULL in case of error
2555 */
2556static xmlRelaxNGDefinePtr
2557xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2558 xmlRelaxNGDefinePtr def = NULL;
2559 xmlRelaxNGTypeLibraryPtr lib;
2560 xmlChar *type;
2561 xmlChar *library;
2562 int tmp;
2563
Daniel Veillardfd573f12003-03-16 17:52:32 +00002564 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002565 if (def == NULL)
2566 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002567 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002568
2569 type = xmlGetProp(node, BAD_CAST "type");
2570 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002571 xmlRelaxNGNormExtSpace(type);
2572 if (xmlValidateNCName(type, 0)) {
2573 if (ctxt->error != NULL)
2574 ctxt->error(ctxt->userData,
2575 "value type '%s' is not an NCName\n",
2576 type);
2577 ctxt->nbErrors++;
2578 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002579 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2580 if (library == NULL)
2581 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2582
2583 def->name = type;
2584 def->ns = library;
2585
2586 lib = (xmlRelaxNGTypeLibraryPtr)
2587 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2588 if (lib == NULL) {
2589 if (ctxt->error != NULL)
2590 ctxt->error(ctxt->userData,
2591 "Use of unregistered type library '%s'\n",
2592 library);
2593 ctxt->nbErrors++;
2594 def->data = NULL;
2595 } else {
2596 def->data = lib;
2597 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002598 if (ctxt->error != NULL)
2599 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002600 "Internal error with type library '%s': no 'have'\n",
2601 library);
2602 ctxt->nbErrors++;
2603 } else {
2604 tmp = lib->have(lib->data, def->name);
2605 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002606 if (ctxt->error != NULL)
2607 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002608 "Error type '%s' is not exported by type library '%s'\n",
2609 def->name, library);
2610 ctxt->nbErrors++;
2611 }
2612 }
2613 }
2614 }
2615 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002616 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002617 } else if (((node->children->type != XML_TEXT_NODE) &&
2618 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002619 (node->children->next != NULL)) {
2620 if (ctxt->error != NULL)
2621 ctxt->error(ctxt->userData,
2622 "Expecting a single text value for <value>content\n");
2623 ctxt->nbErrors++;
2624 } else {
2625 def->value = xmlNodeGetContent(node);
2626 if (def->value == NULL) {
2627 if (ctxt->error != NULL)
2628 ctxt->error(ctxt->userData,
2629 "Element <value> has no content\n");
2630 ctxt->nbErrors++;
2631 }
2632 }
2633 /* TODO check ahead of time that the value is okay per the type */
2634 return(def);
2635}
2636
2637/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002638 * xmlRelaxNGParseData:
2639 * @ctxt: a Relax-NG parser context
2640 * @node: the data node.
2641 *
2642 * parse the content of a RelaxNG data node.
2643 *
2644 * Returns the definition pointer or NULL in case of error
2645 */
2646static xmlRelaxNGDefinePtr
2647xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002648 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002649 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002650 xmlRelaxNGTypeLibraryPtr lib;
2651 xmlChar *type;
2652 xmlChar *library;
2653 xmlNodePtr content;
2654 int tmp;
2655
2656 type = xmlGetProp(node, BAD_CAST "type");
2657 if (type == NULL) {
2658 if (ctxt->error != NULL)
2659 ctxt->error(ctxt->userData,
2660 "data has no type\n");
2661 ctxt->nbErrors++;
2662 return(NULL);
2663 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002664 xmlRelaxNGNormExtSpace(type);
2665 if (xmlValidateNCName(type, 0)) {
2666 if (ctxt->error != NULL)
2667 ctxt->error(ctxt->userData,
2668 "data type '%s' is not an NCName\n",
2669 type);
2670 ctxt->nbErrors++;
2671 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002672 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2673 if (library == NULL)
2674 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2675
Daniel Veillardfd573f12003-03-16 17:52:32 +00002676 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002677 if (def == NULL) {
2678 xmlFree(type);
2679 return(NULL);
2680 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002681 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002682 def->name = type;
2683 def->ns = library;
2684
2685 lib = (xmlRelaxNGTypeLibraryPtr)
2686 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2687 if (lib == NULL) {
2688 if (ctxt->error != NULL)
2689 ctxt->error(ctxt->userData,
2690 "Use of unregistered type library '%s'\n",
2691 library);
2692 ctxt->nbErrors++;
2693 def->data = NULL;
2694 } else {
2695 def->data = lib;
2696 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002697 if (ctxt->error != NULL)
2698 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002699 "Internal error with type library '%s': no 'have'\n",
2700 library);
2701 ctxt->nbErrors++;
2702 } else {
2703 tmp = lib->have(lib->data, def->name);
2704 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002705 if (ctxt->error != NULL)
2706 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002707 "Error type '%s' is not exported by type library '%s'\n",
2708 def->name, library);
2709 ctxt->nbErrors++;
2710 }
2711 }
2712 }
2713 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002714
2715 /*
2716 * Handle optional params
2717 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002718 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002719 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2720 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002721 if (xmlStrEqual(library,
2722 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2723 if (ctxt->error != NULL)
2724 ctxt->error(ctxt->userData,
2725 "Type library '%s' does not allow type parameters\n",
2726 library);
2727 ctxt->nbErrors++;
2728 content = content->next;
2729 while ((content != NULL) &&
2730 (xmlStrEqual(content->name, BAD_CAST "param")))
2731 content = content->next;
2732 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002733 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002734 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002735 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002736 param->name = xmlGetProp(content, BAD_CAST "name");
2737 if (param->name == NULL) {
2738 if (ctxt->error != NULL)
2739 ctxt->error(ctxt->userData,
2740 "param has no name\n");
2741 ctxt->nbErrors++;
2742 }
2743 param->value = xmlNodeGetContent(content);
2744 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002745 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002746 } else {
2747 lastparam->next = param;
2748 lastparam = param;
2749 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002750 if (lib != NULL) {
2751 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002752 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002753 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002754 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002755 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002756 /*
2757 * Handle optional except
2758 */
2759 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2760 xmlNodePtr child;
2761 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2762
Daniel Veillardfd573f12003-03-16 17:52:32 +00002763 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00002764 if (except == NULL) {
2765 return(def);
2766 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002767 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00002768 child = content->children;
2769 if (last == NULL) {
2770 def->content = except;
2771 } else {
2772 last->next = except;
2773 }
2774 if (child == NULL) {
2775 if (ctxt->error != NULL)
2776 ctxt->error(ctxt->userData,
2777 "except has no content\n");
2778 ctxt->nbErrors++;
2779 }
2780 while (child != NULL) {
2781 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2782 if (tmp2 != NULL) {
2783 if (last2 == NULL) {
2784 except->content = last2 = tmp2;
2785 } else {
2786 last2->next = tmp2;
2787 last2 = tmp2;
2788 }
2789 }
2790 child = child->next;
2791 }
2792 content = content->next;
2793 }
2794 /*
2795 * Check there is no unhandled data
2796 */
2797 if (content != NULL) {
2798 if (ctxt->error != NULL)
2799 ctxt->error(ctxt->userData,
2800 "Element data has unexpected content %s\n", content->name);
2801 ctxt->nbErrors++;
2802 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002803
2804 return(def);
2805}
2806
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002807static const xmlChar *invalidName = BAD_CAST "\1";
2808
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002809/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002810 * xmlRelaxNGCompareNameClasses:
2811 * @defs1: the first element/attribute defs
2812 * @defs2: the second element/attribute defs
2813 * @name: the restriction on the name
2814 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002815 *
2816 * Compare the 2 lists of element definitions. The comparison is
2817 * that if both lists do not accept the same QNames, it returns 1
2818 * If the 2 lists can accept the same QName the comparison returns 0
2819 *
2820 * Returns 1 disttinct, 0 if equal
2821 */
2822static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002823xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2824 xmlRelaxNGDefinePtr def2) {
2825 int ret = 1;
2826 xmlNode node;
2827 xmlNs ns;
2828 xmlRelaxNGValidCtxt ctxt;
2829 ctxt.flags = FLAGS_IGNORABLE;
2830
Daniel Veillard42f12e92003-03-07 18:32:59 +00002831 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
2832
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002833 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2834 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2835 if (def2->type == XML_RELAXNG_TEXT)
2836 return(1);
2837 if (def1->name != NULL) {
2838 node.name = def1->name;
2839 } else {
2840 node.name = invalidName;
2841 }
2842 node.ns = &ns;
2843 if (def1->ns != NULL) {
2844 if (def1->ns[0] == 0) {
2845 node.ns = NULL;
2846 } else {
2847 ns.href = def1->ns;
2848 }
2849 } else {
2850 ns.href = invalidName;
2851 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002852 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002853 if (def1->nameClass != NULL) {
2854 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2855 } else {
2856 ret = 0;
2857 }
2858 } else {
2859 ret = 1;
2860 }
2861 } else if (def1->type == XML_RELAXNG_TEXT) {
2862 if (def2->type == XML_RELAXNG_TEXT)
2863 return(0);
2864 return(1);
2865 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002866 TODO
2867 ret = 0;
2868 } else {
2869 TODO
2870 ret = 0;
2871 }
2872 if (ret == 0)
2873 return(ret);
2874 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2875 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2876 if (def2->name != NULL) {
2877 node.name = def2->name;
2878 } else {
2879 node.name = invalidName;
2880 }
2881 node.ns = &ns;
2882 if (def2->ns != NULL) {
2883 if (def2->ns[0] == 0) {
2884 node.ns = NULL;
2885 } else {
2886 ns.href = def2->ns;
2887 }
2888 } else {
2889 ns.href = invalidName;
2890 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002891 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002892 if (def2->nameClass != NULL) {
2893 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2894 } else {
2895 ret = 0;
2896 }
2897 } else {
2898 ret = 1;
2899 }
2900 } else {
2901 TODO
2902 ret = 0;
2903 }
2904
2905 return(ret);
2906}
2907
2908/**
2909 * xmlRelaxNGCompareElemDefLists:
2910 * @ctxt: a Relax-NG parser context
2911 * @defs1: the first list of element/attribute defs
2912 * @defs2: the second list of element/attribute defs
2913 *
2914 * Compare the 2 lists of element or attribute definitions. The comparison
2915 * is that if both lists do not accept the same QNames, it returns 1
2916 * If the 2 lists can accept the same QName the comparison returns 0
2917 *
2918 * Returns 1 disttinct, 0 if equal
2919 */
2920static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002921xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2922 xmlRelaxNGDefinePtr *def1,
2923 xmlRelaxNGDefinePtr *def2) {
2924 xmlRelaxNGDefinePtr *basedef2 = def2;
2925
Daniel Veillard154877e2003-01-30 12:17:05 +00002926 if ((def1 == NULL) || (def2 == NULL))
2927 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002928 if ((*def1 == NULL) || (*def2 == NULL))
2929 return(1);
2930 while (*def1 != NULL) {
2931 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002932 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2933 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002934 def2++;
2935 }
2936 def2 = basedef2;
2937 def1++;
2938 }
2939 return(1);
2940}
2941
2942/**
2943 * xmlRelaxNGGetElements:
2944 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002945 * @def: the definition definition
2946 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002947 *
2948 * Compute the list of top elements a definition can generate
2949 *
2950 * Returns a list of elements or NULL if none was found.
2951 */
2952static xmlRelaxNGDefinePtr *
2953xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002954 xmlRelaxNGDefinePtr def,
2955 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002956 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002957 int len = 0;
2958 int max = 0;
2959
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002960 /*
2961 * Don't run that check in case of error. Infinite recursion
2962 * becomes possible.
2963 */
2964 if (ctxt->nbErrors != 0)
2965 return(NULL);
2966
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002967 parent = NULL;
2968 cur = def;
2969 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002970 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
2971 (cur->type == XML_RELAXNG_TEXT))) ||
2972 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002973 if (ret == NULL) {
2974 max = 10;
2975 ret = (xmlRelaxNGDefinePtr *)
2976 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
2977 if (ret == NULL) {
2978 if (ctxt->error != NULL)
2979 ctxt->error(ctxt->userData,
2980 "Out of memory in element search\n");
2981 ctxt->nbErrors++;
2982 return(NULL);
2983 }
2984 } else if (max <= len) {
2985 max *= 2;
2986 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
2987 if (ret == NULL) {
2988 if (ctxt->error != NULL)
2989 ctxt->error(ctxt->userData,
2990 "Out of memory in element search\n");
2991 ctxt->nbErrors++;
2992 return(NULL);
2993 }
2994 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00002995 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002996 ret[len] = NULL;
2997 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
2998 (cur->type == XML_RELAXNG_INTERLEAVE) ||
2999 (cur->type == XML_RELAXNG_GROUP) ||
3000 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003001 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3002 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003003 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003004 (cur->type == XML_RELAXNG_REF) ||
3005 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003006 /*
3007 * Don't go within elements or attributes or string values.
3008 * Just gather the element top list
3009 */
3010 if (cur->content != NULL) {
3011 parent = cur;
3012 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003013 tmp = cur;
3014 while (tmp != NULL) {
3015 tmp->parent = parent;
3016 tmp = tmp->next;
3017 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003018 continue;
3019 }
3020 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003021 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003022 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003023 if (cur->next != NULL) {
3024 cur = cur->next;
3025 continue;
3026 }
3027 do {
3028 cur = cur->parent;
3029 if (cur == NULL) break;
3030 if (cur == def) return(ret);
3031 if (cur->next != NULL) {
3032 cur = cur->next;
3033 break;
3034 }
3035 } while (cur != NULL);
3036 }
3037 return(ret);
3038}
3039
3040/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003041 * xmlRelaxNGCheckChoiceDeterminism:
3042 * @ctxt: a Relax-NG parser context
3043 * @def: the choice definition
3044 *
3045 * Also used to find indeterministic pattern in choice
3046 */
3047static void
3048xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3049 xmlRelaxNGDefinePtr def) {
3050 xmlRelaxNGDefinePtr **list;
3051 xmlRelaxNGDefinePtr cur;
3052 int nbchild = 0, i, j, ret;
3053 int is_nullable = 0;
3054 int is_indeterminist = 0;
3055
3056 if ((def == NULL) ||
3057 (def->type != XML_RELAXNG_CHOICE))
3058 return;
3059
3060 /*
3061 * Don't run that check in case of error. Infinite recursion
3062 * becomes possible.
3063 */
3064 if (ctxt->nbErrors != 0)
3065 return;
3066
3067 is_nullable = xmlRelaxNGIsNullable(def);
3068
3069 cur = def->content;
3070 while (cur != NULL) {
3071 nbchild++;
3072 cur = cur->next;
3073 }
3074
3075 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3076 sizeof(xmlRelaxNGDefinePtr *));
3077 if (list == NULL) {
3078 if (ctxt->error != NULL)
3079 ctxt->error(ctxt->userData,
3080 "Out of memory in choice computation\n");
3081 ctxt->nbErrors++;
3082 return;
3083 }
3084 i = 0;
3085 cur = def->content;
3086 while (cur != NULL) {
3087 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
3088 i++;
3089 cur = cur->next;
3090 }
3091
3092 for (i = 0;i < nbchild;i++) {
3093 if (list[i] == NULL)
3094 continue;
3095 for (j = 0;j < i;j++) {
3096 if (list[j] == NULL)
3097 continue;
3098 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3099 if (ret == 0) {
3100 is_indeterminist = 1;
3101 }
3102 }
3103 }
3104 for (i = 0;i < nbchild;i++) {
3105 if (list[i] != NULL)
3106 xmlFree(list[i]);
3107 }
3108
3109 xmlFree(list);
3110 if (is_indeterminist) {
3111 def->flags |= IS_INDETERMINIST;
3112 }
3113}
3114
3115/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003116 * xmlRelaxNGCheckGroupAttrs:
3117 * @ctxt: a Relax-NG parser context
3118 * @def: the group definition
3119 *
3120 * Detects violations of rule 7.3
3121 */
3122static void
3123xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3124 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003125 xmlRelaxNGDefinePtr **list;
3126 xmlRelaxNGDefinePtr cur;
3127 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003128
3129 if ((def == NULL) ||
3130 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003131 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003132 return;
3133
3134 /*
3135 * Don't run that check in case of error. Infinite recursion
3136 * becomes possible.
3137 */
3138 if (ctxt->nbErrors != 0)
3139 return;
3140
Daniel Veillardfd573f12003-03-16 17:52:32 +00003141 cur = def->attrs;
3142 while (cur != NULL) {
3143 nbchild++;
3144 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003145 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003146 cur = def->content;
3147 while (cur != NULL) {
3148 nbchild++;
3149 cur = cur->next;
3150 }
3151
3152 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3153 sizeof(xmlRelaxNGDefinePtr *));
3154 if (list == NULL) {
3155 if (ctxt->error != NULL)
3156 ctxt->error(ctxt->userData,
3157 "Out of memory in group computation\n");
3158 ctxt->nbErrors++;
3159 return;
3160 }
3161 i = 0;
3162 cur = def->attrs;
3163 while (cur != NULL) {
3164 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3165 i++;
3166 cur = cur->next;
3167 }
3168 cur = def->content;
3169 while (cur != NULL) {
3170 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3171 i++;
3172 cur = cur->next;
3173 }
3174
3175 for (i = 0;i < nbchild;i++) {
3176 if (list[i] == NULL)
3177 continue;
3178 for (j = 0;j < i;j++) {
3179 if (list[j] == NULL)
3180 continue;
3181 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3182 if (ret == 0) {
3183 if (ctxt->error != NULL)
3184 ctxt->error(ctxt->userData,
3185 "Attributes conflicts in group\n");
3186 ctxt->nbErrors++;
3187 }
3188 }
3189 }
3190 for (i = 0;i < nbchild;i++) {
3191 if (list[i] != NULL)
3192 xmlFree(list[i]);
3193 }
3194
3195 xmlFree(list);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003196}
3197
3198/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003199 * xmlRelaxNGComputeInterleaves:
3200 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003201 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003202 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003203 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003204 * A lot of work for preprocessing interleave definitions
3205 * is potentially needed to get a decent execution speed at runtime
3206 * - trying to get a total order on the element nodes generated
3207 * by the interleaves, order the list of interleave definitions
3208 * following that order.
3209 * - if <text/> is used to handle mixed content, it is better to
3210 * flag this in the define and simplify the runtime checking
3211 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003212 */
3213static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003214xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3215 xmlRelaxNGParserCtxtPtr ctxt,
3216 xmlChar *name ATTRIBUTE_UNUSED) {
3217 xmlRelaxNGDefinePtr cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003218
Daniel Veillardfd573f12003-03-16 17:52:32 +00003219 xmlRelaxNGPartitionPtr partitions = NULL;
3220 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3221 xmlRelaxNGInterleaveGroupPtr group;
3222 int i,j,ret;
3223 int nbgroups = 0;
3224 int nbchild = 0;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003225
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003226 /*
3227 * Don't run that check in case of error. Infinite recursion
3228 * becomes possible.
3229 */
3230 if (ctxt->nbErrors != 0)
3231 return;
3232
Daniel Veillardfd573f12003-03-16 17:52:32 +00003233#ifdef DEBUG_INTERLEAVE
3234 xmlGenericError(xmlGenericErrorContext,
3235 "xmlRelaxNGComputeInterleaves(%s)\n",
3236 name);
3237#endif
3238 cur = def->content;
3239 while (cur != NULL) {
3240 nbchild++;
3241 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003242 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003243
3244#ifdef DEBUG_INTERLEAVE
3245 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3246#endif
3247 groups = (xmlRelaxNGInterleaveGroupPtr *)
3248 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3249 if (groups == NULL)
3250 goto error;
3251 cur = def->content;
3252 while (cur != NULL) {
3253 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3254 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3255 if (groups[nbgroups] == NULL)
3256 goto error;
3257 groups[nbgroups]->rule = cur;
3258 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3259 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3260 nbgroups++;
3261 cur = cur->next;
3262 }
3263#ifdef DEBUG_INTERLEAVE
3264 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3265#endif
3266
3267 /*
3268 * Let's check that all rules makes a partitions according to 7.4
3269 */
3270 partitions = (xmlRelaxNGPartitionPtr)
3271 xmlMalloc(sizeof(xmlRelaxNGPartition));
3272 if (partitions == NULL)
3273 goto error;
3274 partitions->nbgroups = nbgroups;
3275 for (i = 0;i < nbgroups;i++) {
3276 group = groups[i];
3277 for (j = i+1;j < nbgroups;j++) {
3278 if (groups[j] == NULL)
3279 continue;
3280 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3281 groups[j]->defs);
3282 if (ret == 0) {
3283 if (ctxt->error != NULL)
3284 ctxt->error(ctxt->userData,
3285 "Element or text conflicts in interleave\n");
3286 ctxt->nbErrors++;
3287 }
3288 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3289 groups[j]->attrs);
3290 if (ret == 0) {
3291 if (ctxt->error != NULL)
3292 ctxt->error(ctxt->userData,
3293 "Attributes conflicts in interleave\n");
3294 ctxt->nbErrors++;
3295 }
3296 }
3297 }
3298 partitions->groups = groups;
3299
3300 /*
3301 * and save the partition list back in the def
3302 */
3303 def->data = partitions;
3304 return;
3305
3306error:
3307 if (ctxt->error != NULL)
3308 ctxt->error(ctxt->userData,
3309 "Out of memory in interleave computation\n");
3310 ctxt->nbErrors++;
3311 if (groups != NULL) {
3312 for (i = 0;i < nbgroups;i++)
3313 if (groups[i] != NULL) {
3314 if (groups[i]->defs != NULL)
3315 xmlFree(groups[i]->defs);
3316 xmlFree(groups[i]);
3317 }
3318 xmlFree(groups);
3319 }
3320 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003321}
3322
3323/**
3324 * xmlRelaxNGParseInterleave:
3325 * @ctxt: a Relax-NG parser context
3326 * @node: the data node.
3327 *
3328 * parse the content of a RelaxNG interleave node.
3329 *
3330 * Returns the definition pointer or NULL in case of error
3331 */
3332static xmlRelaxNGDefinePtr
3333xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3334 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003335 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003336 xmlNodePtr child;
3337
Daniel Veillardfd573f12003-03-16 17:52:32 +00003338 def = xmlRelaxNGNewDefine(ctxt, node);
3339 if (def == NULL) {
3340 return(NULL);
3341 }
3342 def->type = XML_RELAXNG_INTERLEAVE;
3343
3344 if (ctxt->interleaves == NULL)
3345 ctxt->interleaves = xmlHashCreate(10);
3346 if (ctxt->interleaves == NULL) {
3347 if (ctxt->error != NULL)
3348 ctxt->error(ctxt->userData,
3349 "Failed to create interleaves hash table\n");
3350 ctxt->nbErrors++;
3351 } else {
3352 char name[32];
3353
3354 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3355 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3356 if (ctxt->error != NULL)
3357 ctxt->error(ctxt->userData,
3358 "Failed to add %s to hash table\n", name);
3359 ctxt->nbErrors++;
3360 }
3361 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003362 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003363 if (child == NULL) {
3364 if (ctxt->error != NULL)
3365 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3366 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003367 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003368 while (child != NULL) {
3369 if (IS_RELAXNG(child, "element")) {
3370 cur = xmlRelaxNGParseElement(ctxt, child);
3371 } else {
3372 cur = xmlRelaxNGParsePattern(ctxt, child);
3373 }
3374 if (cur != NULL) {
3375 cur->parent = def;
3376 if (last == NULL) {
3377 def->content = last = cur;
3378 } else {
3379 last->next = cur;
3380 last = cur;
3381 }
3382 }
3383 child = child->next;
3384 }
3385
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003386 return(def);
3387}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003388
3389/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003390 * xmlRelaxNGParseInclude:
3391 * @ctxt: a Relax-NG parser context
3392 * @node: the include node
3393 *
3394 * Integrate the content of an include node in the current grammar
3395 *
3396 * Returns 0 in case of success or -1 in case of error
3397 */
3398static int
3399xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3400 xmlRelaxNGIncludePtr incl;
3401 xmlNodePtr root;
3402 int ret = 0, tmp;
3403
3404 incl = node->_private;
3405 if (incl == NULL) {
3406 if (ctxt->error != NULL)
3407 ctxt->error(ctxt->userData,
3408 "Include node has no data\n");
3409 ctxt->nbErrors++;
3410 return(-1);
3411 }
3412 root = xmlDocGetRootElement(incl->doc);
3413 if (root == NULL) {
3414 if (ctxt->error != NULL)
3415 ctxt->error(ctxt->userData,
3416 "Include document is empty\n");
3417 ctxt->nbErrors++;
3418 return(-1);
3419 }
3420 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3421 if (ctxt->error != NULL)
3422 ctxt->error(ctxt->userData,
3423 "Include document root is not a grammar\n");
3424 ctxt->nbErrors++;
3425 return(-1);
3426 }
3427
3428 /*
3429 * Merge the definition from both the include and the internal list
3430 */
3431 if (root->children != NULL) {
3432 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3433 if (tmp != 0)
3434 ret = -1;
3435 }
3436 if (node->children != NULL) {
3437 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3438 if (tmp != 0)
3439 ret = -1;
3440 }
3441 return(ret);
3442}
3443
3444/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003445 * xmlRelaxNGParseDefine:
3446 * @ctxt: a Relax-NG parser context
3447 * @node: the define node
3448 *
3449 * parse the content of a RelaxNG define element node.
3450 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003451 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003452 */
3453static int
3454xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3455 xmlChar *name;
3456 int ret = 0, tmp;
3457 xmlRelaxNGDefinePtr def;
3458 const xmlChar *olddefine;
3459
3460 name = xmlGetProp(node, BAD_CAST "name");
3461 if (name == NULL) {
3462 if (ctxt->error != NULL)
3463 ctxt->error(ctxt->userData,
3464 "define has no name\n");
3465 ctxt->nbErrors++;
3466 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003467 xmlRelaxNGNormExtSpace(name);
3468 if (xmlValidateNCName(name, 0)) {
3469 if (ctxt->error != NULL)
3470 ctxt->error(ctxt->userData,
3471 "define name '%s' is not an NCName\n",
3472 name);
3473 ctxt->nbErrors++;
3474 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003475 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003476 if (def == NULL) {
3477 xmlFree(name);
3478 return(-1);
3479 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003480 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003481 def->name = name;
3482 if (node->children == NULL) {
3483 if (ctxt->error != NULL)
3484 ctxt->error(ctxt->userData,
3485 "define has no children\n");
3486 ctxt->nbErrors++;
3487 } else {
3488 olddefine = ctxt->define;
3489 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003490 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003491 ctxt->define = olddefine;
3492 }
3493 if (ctxt->grammar->defs == NULL)
3494 ctxt->grammar->defs = xmlHashCreate(10);
3495 if (ctxt->grammar->defs == NULL) {
3496 if (ctxt->error != NULL)
3497 ctxt->error(ctxt->userData,
3498 "Could not create definition hash\n");
3499 ctxt->nbErrors++;
3500 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003501 } else {
3502 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3503 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003504 xmlRelaxNGDefinePtr prev;
3505
3506 prev = xmlHashLookup(ctxt->grammar->defs, name);
3507 if (prev == NULL) {
3508 if (ctxt->error != NULL)
3509 ctxt->error(ctxt->userData,
3510 "Internal error on define aggregation of %s\n",
3511 name);
3512 ctxt->nbErrors++;
3513 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003514 } else {
3515 while (prev->nextHash != NULL)
3516 prev = prev->nextHash;
3517 prev->nextHash = def;
3518 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003519 }
3520 }
3521 }
3522 return(ret);
3523}
3524
3525/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003526 * xmlRelaxNGProcessExternalRef:
3527 * @ctxt: the parser context
3528 * @node: the externlRef node
3529 *
3530 * Process and compile an externlRef node
3531 *
3532 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3533 */
3534static xmlRelaxNGDefinePtr
3535xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3536 xmlRelaxNGDocumentPtr docu;
3537 xmlNodePtr root, tmp;
3538 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003539 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003540 xmlRelaxNGDefinePtr def;
3541
3542 docu = node->_private;
3543 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003544 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003545 if (def == NULL)
3546 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003547 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003548
3549 if (docu->content == NULL) {
3550 /*
3551 * Then do the parsing for good
3552 */
3553 root = xmlDocGetRootElement(docu->doc);
3554 if (root == NULL) {
3555 if (ctxt->error != NULL)
3556 ctxt->error(ctxt->userData,
3557 "xmlRelaxNGParse: %s is empty\n",
3558 ctxt->URL);
3559 ctxt->nbErrors++;
3560 return (NULL);
3561 }
3562 /*
3563 * ns transmission rules
3564 */
3565 ns = xmlGetProp(root, BAD_CAST "ns");
3566 if (ns == NULL) {
3567 tmp = node;
3568 while ((tmp != NULL) &&
3569 (tmp->type == XML_ELEMENT_NODE)) {
3570 ns = xmlGetProp(tmp, BAD_CAST "ns");
3571 if (ns != NULL) {
3572 break;
3573 }
3574 tmp = tmp->parent;
3575 }
3576 if (ns != NULL) {
3577 xmlSetProp(root, BAD_CAST "ns", ns);
3578 newNs = 1;
3579 xmlFree(ns);
3580 }
3581 } else {
3582 xmlFree(ns);
3583 }
3584
3585 /*
3586 * Parsing to get a precompiled schemas.
3587 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003588 oldflags = ctxt->flags;
3589 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003590 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003591 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003592 if ((docu->schema != NULL) &&
3593 (docu->schema->topgrammar != NULL)) {
3594 docu->content = docu->schema->topgrammar->start;
3595 }
3596
3597 /*
3598 * the externalRef may be reused in a different ns context
3599 */
3600 if (newNs == 1) {
3601 xmlUnsetProp(root, BAD_CAST "ns");
3602 }
3603 }
3604 def->content = docu->content;
3605 } else {
3606 def = NULL;
3607 }
3608 return(def);
3609}
3610
3611/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003612 * xmlRelaxNGParsePattern:
3613 * @ctxt: a Relax-NG parser context
3614 * @node: the pattern node.
3615 *
3616 * parse the content of a RelaxNG pattern node.
3617 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003618 * Returns the definition pointer or NULL in case of error or if no
3619 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003620 */
3621static xmlRelaxNGDefinePtr
3622xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3623 xmlRelaxNGDefinePtr def = NULL;
3624
Daniel Veillardd2298792003-02-14 16:54:11 +00003625 if (node == NULL) {
3626 return(NULL);
3627 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003628 if (IS_RELAXNG(node, "element")) {
3629 def = xmlRelaxNGParseElement(ctxt, node);
3630 } else if (IS_RELAXNG(node, "attribute")) {
3631 def = xmlRelaxNGParseAttribute(ctxt, node);
3632 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003633 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003634 if (def == NULL)
3635 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003636 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003637 if (node->children != NULL) {
3638 if (ctxt->error != NULL)
3639 ctxt->error(ctxt->userData, "empty: had a child node\n");
3640 ctxt->nbErrors++;
3641 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003642 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003643 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003644 if (def == NULL)
3645 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003646 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003647 if (node->children != NULL) {
3648 if (ctxt->error != NULL)
3649 ctxt->error(ctxt->userData, "text: had a child node\n");
3650 ctxt->nbErrors++;
3651 }
3652 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003653 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003654 if (def == NULL)
3655 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003656 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003657 if (node->children == NULL) {
3658 if (ctxt->error != NULL)
3659 ctxt->error(ctxt->userData,
3660 "Element %s is empty\n", node->name);
3661 ctxt->nbErrors++;
3662 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003663 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003664 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003665 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003666 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003667 if (def == NULL)
3668 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003669 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003670 if (node->children == NULL) {
3671 if (ctxt->error != NULL)
3672 ctxt->error(ctxt->userData,
3673 "Element %s is empty\n", node->name);
3674 ctxt->nbErrors++;
3675 } else {
3676 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3677 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003678 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003679 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003680 if (def == NULL)
3681 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003682 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003683 if (node->children == NULL) {
3684 if (ctxt->error != NULL)
3685 ctxt->error(ctxt->userData,
3686 "Element %s is empty\n", node->name);
3687 ctxt->nbErrors++;
3688 } else {
3689 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3690 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003691 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003692 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003693 if (def == NULL)
3694 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003695 def->type = XML_RELAXNG_CHOICE;
3696 if (node->children == NULL) {
3697 if (ctxt->error != NULL)
3698 ctxt->error(ctxt->userData,
3699 "Element %s is empty\n", node->name);
3700 ctxt->nbErrors++;
3701 } else {
3702 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3703 }
3704 } else if (IS_RELAXNG(node, "group")) {
3705 def = xmlRelaxNGNewDefine(ctxt, node);
3706 if (def == NULL)
3707 return(NULL);
3708 def->type = XML_RELAXNG_GROUP;
3709 if (node->children == NULL) {
3710 if (ctxt->error != NULL)
3711 ctxt->error(ctxt->userData,
3712 "Element %s is empty\n", node->name);
3713 ctxt->nbErrors++;
3714 } else {
3715 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3716 }
3717 } else if (IS_RELAXNG(node, "ref")) {
3718 def = xmlRelaxNGNewDefine(ctxt, node);
3719 if (def == NULL)
3720 return(NULL);
3721 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003722 def->name = xmlGetProp(node, BAD_CAST "name");
3723 if (def->name == NULL) {
3724 if (ctxt->error != NULL)
3725 ctxt->error(ctxt->userData,
3726 "ref has no name\n");
3727 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003728 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003729 xmlRelaxNGNormExtSpace(def->name);
3730 if (xmlValidateNCName(def->name, 0)) {
3731 if (ctxt->error != NULL)
3732 ctxt->error(ctxt->userData,
3733 "ref name '%s' is not an NCName\n",
3734 def->name);
3735 ctxt->nbErrors++;
3736 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003737 }
3738 if (node->children != NULL) {
3739 if (ctxt->error != NULL)
3740 ctxt->error(ctxt->userData,
3741 "ref is not empty\n");
3742 ctxt->nbErrors++;
3743 }
3744 if (ctxt->grammar->refs == NULL)
3745 ctxt->grammar->refs = xmlHashCreate(10);
3746 if (ctxt->grammar->refs == NULL) {
3747 if (ctxt->error != NULL)
3748 ctxt->error(ctxt->userData,
3749 "Could not create references hash\n");
3750 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003751 def = NULL;
3752 } else {
3753 int tmp;
3754
3755 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
3756 if (tmp < 0) {
3757 xmlRelaxNGDefinePtr prev;
3758
3759 prev = (xmlRelaxNGDefinePtr)
3760 xmlHashLookup(ctxt->grammar->refs, def->name);
3761 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003762 if (def->name != NULL) {
3763 if (ctxt->error != NULL)
3764 ctxt->error(ctxt->userData,
3765 "Error refs definitions '%s'\n",
3766 def->name);
3767 } else {
3768 if (ctxt->error != NULL)
3769 ctxt->error(ctxt->userData,
3770 "Error refs definitions\n");
3771 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003772 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003773 def = NULL;
3774 } else {
3775 def->nextHash = prev->nextHash;
3776 prev->nextHash = def;
3777 }
3778 }
3779 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003780 } else if (IS_RELAXNG(node, "data")) {
3781 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003782 } else if (IS_RELAXNG(node, "value")) {
3783 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003784 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003785 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003786 if (def == NULL)
3787 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003788 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00003789 if (node->children == NULL) {
3790 if (ctxt->error != NULL)
3791 ctxt->error(ctxt->userData,
3792 "Element %s is empty\n", node->name);
3793 ctxt->nbErrors++;
3794 } else {
3795 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3796 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003797 } else if (IS_RELAXNG(node, "interleave")) {
3798 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003799 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003800 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003801 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003802 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003803 if (def == NULL)
3804 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003805 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003806 if (node->children != NULL) {
3807 if (ctxt->error != NULL)
3808 ctxt->error(ctxt->userData,
3809 "xmlRelaxNGParse: notAllowed element is not empty\n");
3810 ctxt->nbErrors++;
3811 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003812 } else if (IS_RELAXNG(node, "grammar")) {
3813 xmlRelaxNGGrammarPtr grammar, old;
3814 xmlRelaxNGGrammarPtr oldparent;
3815
Daniel Veillardc482e262003-02-26 14:48:48 +00003816#ifdef DEBUG_GRAMMAR
3817 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
3818#endif
3819
Daniel Veillard419a7682003-02-03 23:22:49 +00003820 oldparent = ctxt->parentgrammar;
3821 old = ctxt->grammar;
3822 ctxt->parentgrammar = old;
3823 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
3824 if (old != NULL) {
3825 ctxt->grammar = old;
3826 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00003827#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00003828 if (grammar != NULL) {
3829 grammar->next = old->next;
3830 old->next = grammar;
3831 }
Daniel Veillardc482e262003-02-26 14:48:48 +00003832#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00003833 }
3834 if (grammar != NULL)
3835 def = grammar->start;
3836 else
3837 def = NULL;
3838 } else if (IS_RELAXNG(node, "parentRef")) {
3839 if (ctxt->parentgrammar == NULL) {
3840 if (ctxt->error != NULL)
3841 ctxt->error(ctxt->userData,
3842 "Use of parentRef without a parent grammar\n");
3843 ctxt->nbErrors++;
3844 return(NULL);
3845 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003846 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00003847 if (def == NULL)
3848 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003849 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00003850 def->name = xmlGetProp(node, BAD_CAST "name");
3851 if (def->name == NULL) {
3852 if (ctxt->error != NULL)
3853 ctxt->error(ctxt->userData,
3854 "parentRef has no name\n");
3855 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00003856 } else {
3857 xmlRelaxNGNormExtSpace(def->name);
3858 if (xmlValidateNCName(def->name, 0)) {
3859 if (ctxt->error != NULL)
3860 ctxt->error(ctxt->userData,
3861 "parentRef name '%s' is not an NCName\n",
3862 def->name);
3863 ctxt->nbErrors++;
3864 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003865 }
3866 if (node->children != NULL) {
3867 if (ctxt->error != NULL)
3868 ctxt->error(ctxt->userData,
3869 "parentRef is not empty\n");
3870 ctxt->nbErrors++;
3871 }
3872 if (ctxt->parentgrammar->refs == NULL)
3873 ctxt->parentgrammar->refs = xmlHashCreate(10);
3874 if (ctxt->parentgrammar->refs == NULL) {
3875 if (ctxt->error != NULL)
3876 ctxt->error(ctxt->userData,
3877 "Could not create references hash\n");
3878 ctxt->nbErrors++;
3879 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003880 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00003881 int tmp;
3882
3883 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3884 if (tmp < 0) {
3885 xmlRelaxNGDefinePtr prev;
3886
3887 prev = (xmlRelaxNGDefinePtr)
3888 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3889 if (prev == NULL) {
3890 if (ctxt->error != NULL)
3891 ctxt->error(ctxt->userData,
3892 "Internal error parentRef definitions '%s'\n",
3893 def->name);
3894 ctxt->nbErrors++;
3895 def = NULL;
3896 } else {
3897 def->nextHash = prev->nextHash;
3898 prev->nextHash = def;
3899 }
3900 }
3901 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003902 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003903 if (node->children == NULL) {
3904 if (ctxt->error != NULL)
3905 ctxt->error(ctxt->userData,
3906 "Mixed is empty\n");
3907 ctxt->nbErrors++;
3908 def = NULL;
3909 } else {
3910 def = xmlRelaxNGParseInterleave(ctxt, node);
3911 if (def != NULL) {
3912 xmlRelaxNGDefinePtr tmp;
3913
3914 if ((def->content != NULL) && (def->content->next != NULL)) {
3915 tmp = xmlRelaxNGNewDefine(ctxt, node);
3916 if (tmp != NULL) {
3917 tmp->type = XML_RELAXNG_GROUP;
3918 tmp->content = def->content;
3919 def->content = tmp;
3920 }
3921 }
3922
3923 tmp = xmlRelaxNGNewDefine(ctxt, node);
3924 if (tmp == NULL)
3925 return(def);
3926 tmp->type = XML_RELAXNG_TEXT;
3927 tmp->next = def->content;
3928 def->content = tmp;
3929 }
3930 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003931 } else {
3932 if (ctxt->error != NULL)
3933 ctxt->error(ctxt->userData,
3934 "Unexpected node %s is not a pattern\n",
3935 node->name);
3936 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003937 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003938 }
3939 return(def);
3940}
3941
3942/**
3943 * xmlRelaxNGParseAttribute:
3944 * @ctxt: a Relax-NG parser context
3945 * @node: the element node
3946 *
3947 * parse the content of a RelaxNG attribute node.
3948 *
3949 * Returns the definition pointer or NULL in case of error.
3950 */
3951static xmlRelaxNGDefinePtr
3952xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003953 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003954 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003955 int old_flags;
3956
Daniel Veillardfd573f12003-03-16 17:52:32 +00003957 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003958 if (ret == NULL)
3959 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003960 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003961 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003962 child = node->children;
3963 if (child == NULL) {
3964 if (ctxt->error != NULL)
3965 ctxt->error(ctxt->userData,
3966 "xmlRelaxNGParseattribute: attribute has no children\n");
3967 ctxt->nbErrors++;
3968 return(ret);
3969 }
3970 old_flags = ctxt->flags;
3971 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003972 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3973 if (cur != NULL)
3974 child = child->next;
3975
Daniel Veillardd2298792003-02-14 16:54:11 +00003976 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00003977 cur = xmlRelaxNGParsePattern(ctxt, child);
3978 if (cur != NULL) {
3979 switch (cur->type) {
3980 case XML_RELAXNG_EMPTY:
3981 case XML_RELAXNG_NOT_ALLOWED:
3982 case XML_RELAXNG_TEXT:
3983 case XML_RELAXNG_ELEMENT:
3984 case XML_RELAXNG_DATATYPE:
3985 case XML_RELAXNG_VALUE:
3986 case XML_RELAXNG_LIST:
3987 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00003988 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003989 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003990 case XML_RELAXNG_DEF:
3991 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003992 case XML_RELAXNG_ZEROORMORE:
3993 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00003994 case XML_RELAXNG_CHOICE:
3995 case XML_RELAXNG_GROUP:
3996 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00003997 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00003998 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003999 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004000 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004001 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004002 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004003 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004004 if (ctxt->error != NULL)
4005 ctxt->error(ctxt->userData,
4006 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004007 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004008 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004009 case XML_RELAXNG_NOOP:
4010 TODO
4011 if (ctxt->error != NULL)
4012 ctxt->error(ctxt->userData,
4013 "Internal error, noop found\n");
4014 ctxt->nbErrors++;
4015 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004016 }
4017 }
4018 child = child->next;
4019 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004020 if (child != NULL) {
4021 if (ctxt->error != NULL)
4022 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4023 ctxt->nbErrors++;
4024 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004025 ctxt->flags = old_flags;
4026 return(ret);
4027}
4028
4029/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004030 * xmlRelaxNGParseExceptNameClass:
4031 * @ctxt: a Relax-NG parser context
4032 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004033 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004034 *
4035 * parse the content of a RelaxNG nameClass node.
4036 *
4037 * Returns the definition pointer or NULL in case of error.
4038 */
4039static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004040xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4041 xmlNodePtr node, int attr) {
4042 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4043 xmlNodePtr child;
4044
Daniel Veillardd2298792003-02-14 16:54:11 +00004045 if (!IS_RELAXNG(node, "except")) {
4046 if (ctxt->error != NULL)
4047 ctxt->error(ctxt->userData,
4048 "Expecting an except node\n");
4049 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004050 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004051 }
4052 if (node->next != NULL) {
4053 if (ctxt->error != NULL)
4054 ctxt->error(ctxt->userData,
4055 "exceptNameClass allows only a single except node\n");
4056 ctxt->nbErrors++;
4057 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004058 if (node->children == NULL) {
4059 if (ctxt->error != NULL)
4060 ctxt->error(ctxt->userData,
4061 "except has no content\n");
4062 ctxt->nbErrors++;
4063 return(NULL);
4064 }
4065
Daniel Veillardfd573f12003-03-16 17:52:32 +00004066 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004067 if (ret == NULL)
4068 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004069 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004070 child = node->children;
4071 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004072 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004073 if (cur == NULL)
4074 break;
4075 if (attr)
4076 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004077 else
4078 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004079
Daniel Veillard419a7682003-02-03 23:22:49 +00004080 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004081 if (last == NULL) {
4082 ret->content = cur;
4083 } else {
4084 last->next = cur;
4085 }
4086 last = cur;
4087 }
4088 child = child->next;
4089 }
4090
4091 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004092}
4093
4094/**
4095 * xmlRelaxNGParseNameClass:
4096 * @ctxt: a Relax-NG parser context
4097 * @node: the nameClass node
4098 * @def: the current definition
4099 *
4100 * parse the content of a RelaxNG nameClass node.
4101 *
4102 * Returns the definition pointer or NULL in case of error.
4103 */
4104static xmlRelaxNGDefinePtr
4105xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4106 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004107 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004108 xmlChar *val;
4109
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004110 ret = def;
4111 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4112 (IS_RELAXNG(node, "nsName"))) {
4113 if ((def->type != XML_RELAXNG_ELEMENT) &&
4114 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004115 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004116 if (ret == NULL)
4117 return(NULL);
4118 ret->parent = def;
4119 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4120 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004121 else
4122 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004123 }
4124 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004125 if (IS_RELAXNG(node, "name")) {
4126 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004127 xmlRelaxNGNormExtSpace(val);
4128 if (xmlValidateNCName(val, 0)) {
4129 if (ctxt->error != NULL) {
4130 if (node->parent != NULL)
4131 ctxt->error(ctxt->userData,
4132 "Element %s name '%s' is not an NCName\n",
4133 node->parent->name, val);
4134 else
4135 ctxt->error(ctxt->userData,
4136 "name '%s' is not an NCName\n",
4137 val);
4138 }
4139 ctxt->nbErrors++;
4140 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004141 ret->name = val;
4142 val = xmlGetProp(node, BAD_CAST "ns");
4143 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004144 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4145 (val != NULL) &&
4146 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4147 ctxt->error(ctxt->userData,
4148 "Attribute with namespace '%s' is not allowed\n",
4149 val);
4150 ctxt->nbErrors++;
4151 }
4152 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4153 (val != NULL) &&
4154 (val[0] == 0) &&
4155 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4156 ctxt->error(ctxt->userData,
4157 "Attribute with QName 'xmlns' is not allowed\n",
4158 val);
4159 ctxt->nbErrors++;
4160 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004161 } else if (IS_RELAXNG(node, "anyName")) {
4162 ret->name = NULL;
4163 ret->ns = NULL;
4164 if (node->children != NULL) {
4165 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004166 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4167 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004168 }
4169 } else if (IS_RELAXNG(node, "nsName")) {
4170 ret->name = NULL;
4171 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4172 if (ret->ns == NULL) {
4173 if (ctxt->error != NULL)
4174 ctxt->error(ctxt->userData,
4175 "nsName has no ns attribute\n");
4176 ctxt->nbErrors++;
4177 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004178 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4179 (ret->ns != NULL) &&
4180 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4181 ctxt->error(ctxt->userData,
4182 "Attribute with namespace '%s' is not allowed\n",
4183 ret->ns);
4184 ctxt->nbErrors++;
4185 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004186 if (node->children != NULL) {
4187 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004188 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4189 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004190 }
4191 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004192 xmlNodePtr child;
4193 xmlRelaxNGDefinePtr last = NULL;
4194
4195 ret = xmlRelaxNGNewDefine(ctxt, node);
4196 if (ret == NULL)
4197 return(NULL);
4198 ret->parent = def;
4199 ret->type = XML_RELAXNG_CHOICE;
4200
Daniel Veillardd2298792003-02-14 16:54:11 +00004201 if (node->children == NULL) {
4202 if (ctxt->error != NULL)
4203 ctxt->error(ctxt->userData,
4204 "Element choice is empty\n");
4205 ctxt->nbErrors++;
4206 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004207
4208 child = node->children;
4209 while (child != NULL) {
4210 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4211 if (tmp != NULL) {
4212 if (last == NULL) {
4213 last = ret->nameClass = tmp;
4214 } else {
4215 last->next = tmp;
4216 last = tmp;
4217 }
4218 }
4219 child = child->next;
4220 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004221 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004222 } else {
4223 if (ctxt->error != NULL)
4224 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004225 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004226 node->name);
4227 ctxt->nbErrors++;
4228 return(NULL);
4229 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004230 if (ret != def) {
4231 if (def->nameClass == NULL) {
4232 def->nameClass = ret;
4233 } else {
4234 tmp = def->nameClass;
4235 while (tmp->next != NULL) {
4236 tmp = tmp->next;
4237 }
4238 tmp->next = ret;
4239 }
4240 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004241 return(ret);
4242}
4243
4244/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004245 * xmlRelaxNGParseElement:
4246 * @ctxt: a Relax-NG parser context
4247 * @node: the element node
4248 *
4249 * parse the content of a RelaxNG element node.
4250 *
4251 * Returns the definition pointer or NULL in case of error.
4252 */
4253static xmlRelaxNGDefinePtr
4254xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4255 xmlRelaxNGDefinePtr ret, cur, last;
4256 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004257 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004258
Daniel Veillardfd573f12003-03-16 17:52:32 +00004259 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004260 if (ret == NULL)
4261 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004262 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004263 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004264 child = node->children;
4265 if (child == NULL) {
4266 if (ctxt->error != NULL)
4267 ctxt->error(ctxt->userData,
4268 "xmlRelaxNGParseElement: element has no children\n");
4269 ctxt->nbErrors++;
4270 return(ret);
4271 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004272 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4273 if (cur != NULL)
4274 child = child->next;
4275
Daniel Veillard6eadf632003-01-23 18:29:16 +00004276 if (child == NULL) {
4277 if (ctxt->error != NULL)
4278 ctxt->error(ctxt->userData,
4279 "xmlRelaxNGParseElement: element has no content\n");
4280 ctxt->nbErrors++;
4281 return(ret);
4282 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004283 olddefine = ctxt->define;
4284 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004285 last = NULL;
4286 while (child != NULL) {
4287 cur = xmlRelaxNGParsePattern(ctxt, child);
4288 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004289 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004290 switch (cur->type) {
4291 case XML_RELAXNG_EMPTY:
4292 case XML_RELAXNG_NOT_ALLOWED:
4293 case XML_RELAXNG_TEXT:
4294 case XML_RELAXNG_ELEMENT:
4295 case XML_RELAXNG_DATATYPE:
4296 case XML_RELAXNG_VALUE:
4297 case XML_RELAXNG_LIST:
4298 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004299 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004300 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004301 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004302 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004303 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004304 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004305 case XML_RELAXNG_CHOICE:
4306 case XML_RELAXNG_GROUP:
4307 case XML_RELAXNG_INTERLEAVE:
4308 if (last == NULL) {
4309 ret->content = last = cur;
4310 } else {
4311 if ((last->type == XML_RELAXNG_ELEMENT) &&
4312 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004313 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004314 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004315 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004316 ret->content->content = last;
4317 } else {
4318 ret->content = last;
4319 }
4320 }
4321 last->next = cur;
4322 last = cur;
4323 }
4324 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004325 case XML_RELAXNG_ATTRIBUTE:
4326 cur->next = ret->attrs;
4327 ret->attrs = cur;
4328 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004329 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004330 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004331 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004332 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004333 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004334 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004335 case XML_RELAXNG_NOOP:
4336 TODO
4337 if (ctxt->error != NULL)
4338 ctxt->error(ctxt->userData,
4339 "Internal error, noop found\n");
4340 ctxt->nbErrors++;
4341 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004342 }
4343 }
4344 child = child->next;
4345 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004346 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004347 return(ret);
4348}
4349
4350/**
4351 * xmlRelaxNGParsePatterns:
4352 * @ctxt: a Relax-NG parser context
4353 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004354 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004355 *
4356 * parse the content of a RelaxNG start node.
4357 *
4358 * Returns the definition pointer or NULL in case of error.
4359 */
4360static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004361xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4362 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004363 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004364
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004365 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004366 while (nodes != NULL) {
4367 if (IS_RELAXNG(nodes, "element")) {
4368 cur = xmlRelaxNGParseElement(ctxt, nodes);
4369 if (def == NULL) {
4370 def = last = cur;
4371 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004372 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4373 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004374 def = xmlRelaxNGNewDefine(ctxt, nodes);
4375 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004376 def->content = last;
4377 }
4378 last->next = cur;
4379 last = cur;
4380 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004381 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004382 } else {
4383 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004384 if (cur != NULL) {
4385 if (def == NULL) {
4386 def = last = cur;
4387 } else {
4388 last->next = cur;
4389 last = cur;
4390 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004391 }
4392 }
4393 nodes = nodes->next;
4394 }
4395 return(def);
4396}
4397
4398/**
4399 * xmlRelaxNGParseStart:
4400 * @ctxt: a Relax-NG parser context
4401 * @nodes: start children nodes
4402 *
4403 * parse the content of a RelaxNG start node.
4404 *
4405 * Returns 0 in case of success, -1 in case of error
4406 */
4407static int
4408xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4409 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004410 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004411
Daniel Veillardd2298792003-02-14 16:54:11 +00004412 if (nodes == NULL) {
4413 if (ctxt->error != NULL)
4414 ctxt->error(ctxt->userData,
4415 "start has no children\n");
4416 ctxt->nbErrors++;
4417 return(-1);
4418 }
4419 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004420 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004421 if (def == NULL)
4422 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004423 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004424 if (nodes->children != NULL) {
4425 if (ctxt->error != NULL)
4426 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004427 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004428 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004429 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004430 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004431 if (def == NULL)
4432 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004433 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004434 if (nodes->children != NULL) {
4435 if (ctxt->error != NULL)
4436 ctxt->error(ctxt->userData,
4437 "element notAllowed is not empty\n");
4438 ctxt->nbErrors++;
4439 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004440 } else {
4441 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004442 }
4443 if (ctxt->grammar->start != NULL) {
4444 last = ctxt->grammar->start;
4445 while (last->next != NULL)
4446 last = last->next;
4447 last->next = def;
4448 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004449 ctxt->grammar->start = def;
4450 }
4451 nodes = nodes->next;
4452 if (nodes != NULL) {
4453 if (ctxt->error != NULL)
4454 ctxt->error(ctxt->userData,
4455 "start more than one children\n");
4456 ctxt->nbErrors++;
4457 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004458 }
4459 return(ret);
4460}
4461
4462/**
4463 * xmlRelaxNGParseGrammarContent:
4464 * @ctxt: a Relax-NG parser context
4465 * @nodes: grammar children nodes
4466 *
4467 * parse the content of a RelaxNG grammar node.
4468 *
4469 * Returns 0 in case of success, -1 in case of error
4470 */
4471static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004472xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004473{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004474 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004475
4476 if (nodes == NULL) {
4477 if (ctxt->error != NULL)
4478 ctxt->error(ctxt->userData,
4479 "grammar has no children\n");
4480 ctxt->nbErrors++;
4481 return(-1);
4482 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004483 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004484 if (IS_RELAXNG(nodes, "start")) {
4485 if (nodes->children == NULL) {
4486 if (ctxt->error != NULL)
4487 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004488 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004489 ctxt->nbErrors++;
4490 } else {
4491 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4492 if (tmp != 0)
4493 ret = -1;
4494 }
4495 } else if (IS_RELAXNG(nodes, "define")) {
4496 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4497 if (tmp != 0)
4498 ret = -1;
4499 } else if (IS_RELAXNG(nodes, "include")) {
4500 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4501 if (tmp != 0)
4502 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004503 } else {
4504 if (ctxt->error != NULL)
4505 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004506 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004507 ctxt->nbErrors++;
4508 ret = -1;
4509 }
4510 nodes = nodes->next;
4511 }
4512 return (ret);
4513}
4514
4515/**
4516 * xmlRelaxNGCheckReference:
4517 * @ref: the ref
4518 * @ctxt: a Relax-NG parser context
4519 * @name: the name associated to the defines
4520 *
4521 * Applies the 4.17. combine attribute rule for all the define
4522 * element of a given grammar using the same name.
4523 */
4524static void
4525xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4526 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4527 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004528 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004529
4530 grammar = ctxt->grammar;
4531 if (grammar == NULL) {
4532 if (ctxt->error != NULL)
4533 ctxt->error(ctxt->userData,
4534 "Internal error: no grammar in CheckReference %s\n",
4535 name);
4536 ctxt->nbErrors++;
4537 return;
4538 }
4539 if (ref->content != NULL) {
4540 if (ctxt->error != NULL)
4541 ctxt->error(ctxt->userData,
4542 "Internal error: reference has content in CheckReference %s\n",
4543 name);
4544 ctxt->nbErrors++;
4545 return;
4546 }
4547 if (grammar->defs != NULL) {
4548 def = xmlHashLookup(grammar->defs, name);
4549 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004550 cur = ref;
4551 while (cur != NULL) {
4552 cur->content = def;
4553 cur = cur->nextHash;
4554 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004555 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004556 if (ctxt->error != NULL)
4557 ctxt->error(ctxt->userData,
4558 "Reference %s has no matching definition\n",
4559 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004560 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004561 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004562 } else {
4563 if (ctxt->error != NULL)
4564 ctxt->error(ctxt->userData,
4565 "Reference %s has no matching definition\n",
4566 name);
4567 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004568 }
4569 /*
4570 * TODO: make a closure and verify there is no loop !
4571 */
4572}
4573
4574/**
4575 * xmlRelaxNGCheckCombine:
4576 * @define: the define(s) list
4577 * @ctxt: a Relax-NG parser context
4578 * @name: the name associated to the defines
4579 *
4580 * Applies the 4.17. combine attribute rule for all the define
4581 * element of a given grammar using the same name.
4582 */
4583static void
4584xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4585 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4586 xmlChar *combine;
4587 int choiceOrInterleave = -1;
4588 int missing = 0;
4589 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4590
4591 if (define->nextHash == NULL)
4592 return;
4593 cur = define;
4594 while (cur != NULL) {
4595 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4596 if (combine != NULL) {
4597 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4598 if (choiceOrInterleave == -1)
4599 choiceOrInterleave = 1;
4600 else if (choiceOrInterleave == 0) {
4601 if (ctxt->error != NULL)
4602 ctxt->error(ctxt->userData,
4603 "Defines for %s use both 'choice' and 'interleave'\n",
4604 name);
4605 ctxt->nbErrors++;
4606 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004607 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004608 if (choiceOrInterleave == -1)
4609 choiceOrInterleave = 0;
4610 else if (choiceOrInterleave == 1) {
4611 if (ctxt->error != NULL)
4612 ctxt->error(ctxt->userData,
4613 "Defines for %s use both 'choice' and 'interleave'\n",
4614 name);
4615 ctxt->nbErrors++;
4616 }
4617 } else {
4618 if (ctxt->error != NULL)
4619 ctxt->error(ctxt->userData,
4620 "Defines for %s use unknown combine value '%s''\n",
4621 name, combine);
4622 ctxt->nbErrors++;
4623 }
4624 xmlFree(combine);
4625 } else {
4626 if (missing == 0)
4627 missing = 1;
4628 else {
4629 if (ctxt->error != NULL)
4630 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004631 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004632 name);
4633 ctxt->nbErrors++;
4634 }
4635 }
4636
4637 cur = cur->nextHash;
4638 }
4639#ifdef DEBUG
4640 xmlGenericError(xmlGenericErrorContext,
4641 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4642 name, choiceOrInterleave);
4643#endif
4644 if (choiceOrInterleave == -1)
4645 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004646 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004647 if (cur == NULL)
4648 return;
4649 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004650 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004651 else
4652 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004653 tmp = define;
4654 last = NULL;
4655 while (tmp != NULL) {
4656 if (tmp->content != NULL) {
4657 if (tmp->content->next != NULL) {
4658 /*
4659 * we need first to create a wrapper.
4660 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00004661 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004662 if (tmp2 == NULL)
4663 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004664 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004665 tmp2->content = tmp->content;
4666 } else {
4667 tmp2 = tmp->content;
4668 }
4669 if (last == NULL) {
4670 cur->content = tmp2;
4671 } else {
4672 last->next = tmp2;
4673 }
4674 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004675 }
Daniel Veillard952379b2003-03-17 15:37:12 +00004676 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004677 tmp = tmp->nextHash;
4678 }
4679 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004680 if (choiceOrInterleave == 0) {
4681 if (ctxt->interleaves == NULL)
4682 ctxt->interleaves = xmlHashCreate(10);
4683 if (ctxt->interleaves == NULL) {
4684 if (ctxt->error != NULL)
4685 ctxt->error(ctxt->userData,
4686 "Failed to create interleaves hash table\n");
4687 ctxt->nbErrors++;
4688 } else {
4689 char tmpname[32];
4690
4691 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4692 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4693 if (ctxt->error != NULL)
4694 ctxt->error(ctxt->userData,
4695 "Failed to add %s to hash table\n", tmpname);
4696 ctxt->nbErrors++;
4697 }
4698 }
4699 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004700}
4701
4702/**
4703 * xmlRelaxNGCombineStart:
4704 * @ctxt: a Relax-NG parser context
4705 * @grammar: the grammar
4706 *
4707 * Applies the 4.17. combine rule for all the start
4708 * element of a given grammar.
4709 */
4710static void
4711xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
4712 xmlRelaxNGGrammarPtr grammar) {
4713 xmlRelaxNGDefinePtr starts;
4714 xmlChar *combine;
4715 int choiceOrInterleave = -1;
4716 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004717 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004718
Daniel Veillard2df2de22003-02-17 23:34:33 +00004719 starts = grammar->start;
4720 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00004721 return;
4722 cur = starts;
4723 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00004724 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
4725 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
4726 combine = NULL;
4727 if (ctxt->error != NULL)
4728 ctxt->error(ctxt->userData,
4729 "Internal error: start element not found\n");
4730 ctxt->nbErrors++;
4731 } else {
4732 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
4733 }
4734
Daniel Veillard6eadf632003-01-23 18:29:16 +00004735 if (combine != NULL) {
4736 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4737 if (choiceOrInterleave == -1)
4738 choiceOrInterleave = 1;
4739 else if (choiceOrInterleave == 0) {
4740 if (ctxt->error != NULL)
4741 ctxt->error(ctxt->userData,
4742 "<start> use both 'choice' and 'interleave'\n");
4743 ctxt->nbErrors++;
4744 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00004745 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004746 if (choiceOrInterleave == -1)
4747 choiceOrInterleave = 0;
4748 else if (choiceOrInterleave == 1) {
4749 if (ctxt->error != NULL)
4750 ctxt->error(ctxt->userData,
4751 "<start> use both 'choice' and 'interleave'\n");
4752 ctxt->nbErrors++;
4753 }
4754 } else {
4755 if (ctxt->error != NULL)
4756 ctxt->error(ctxt->userData,
4757 "<start> uses unknown combine value '%s''\n", combine);
4758 ctxt->nbErrors++;
4759 }
4760 xmlFree(combine);
4761 } else {
4762 if (missing == 0)
4763 missing = 1;
4764 else {
4765 if (ctxt->error != NULL)
4766 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004767 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00004768 ctxt->nbErrors++;
4769 }
4770 }
4771
Daniel Veillard2df2de22003-02-17 23:34:33 +00004772 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004773 }
4774#ifdef DEBUG
4775 xmlGenericError(xmlGenericErrorContext,
4776 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
4777 choiceOrInterleave);
4778#endif
4779 if (choiceOrInterleave == -1)
4780 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004781 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004782 if (cur == NULL)
4783 return;
4784 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004785 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004786 else
4787 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004788 cur->content = grammar->start;
4789 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004790 if (choiceOrInterleave == 0) {
4791 if (ctxt->interleaves == NULL)
4792 ctxt->interleaves = xmlHashCreate(10);
4793 if (ctxt->interleaves == NULL) {
4794 if (ctxt->error != NULL)
4795 ctxt->error(ctxt->userData,
4796 "Failed to create interleaves hash table\n");
4797 ctxt->nbErrors++;
4798 } else {
4799 char tmpname[32];
4800
4801 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4802 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4803 if (ctxt->error != NULL)
4804 ctxt->error(ctxt->userData,
4805 "Failed to add %s to hash table\n", tmpname);
4806 ctxt->nbErrors++;
4807 }
4808 }
4809 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004810}
4811
4812/**
Daniel Veillardd4310742003-02-18 21:12:46 +00004813 * xmlRelaxNGCheckCycles:
4814 * @ctxt: a Relax-NG parser context
4815 * @nodes: grammar children nodes
4816 * @depth: the counter
4817 *
4818 * Check for cycles.
4819 *
4820 * Returns 0 if check passed, and -1 in case of error
4821 */
4822static int
4823xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
4824 xmlRelaxNGDefinePtr cur, int depth) {
4825 int ret = 0;
4826
4827 while ((ret == 0) && (cur != NULL)) {
4828 if ((cur->type == XML_RELAXNG_REF) ||
4829 (cur->type == XML_RELAXNG_PARENTREF)) {
4830 if (cur->depth == -1) {
4831 cur->depth = depth;
4832 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4833 cur->depth = -2;
4834 } else if (depth == cur->depth) {
4835 if (ctxt->error != NULL)
4836 ctxt->error(ctxt->userData,
4837 "Detected a cycle in %s references\n", cur->name);
4838 ctxt->nbErrors++;
4839 return(-1);
4840 }
4841 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4842 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4843 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004844 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00004845 }
4846 cur = cur->next;
4847 }
4848 return(ret);
4849}
4850
4851/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00004852 * xmlRelaxNGTryUnlink:
4853 * @ctxt: a Relax-NG parser context
4854 * @cur: the definition to unlink
4855 * @parent: the parent definition
4856 * @prev: the previous sibling definition
4857 *
4858 * Try to unlink a definition. If not possble make it a NOOP
4859 *
4860 * Returns the new prev definition
4861 */
4862static xmlRelaxNGDefinePtr
4863xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4864 xmlRelaxNGDefinePtr cur,
4865 xmlRelaxNGDefinePtr parent,
4866 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004867 if (prev != NULL) {
4868 prev->next = cur->next;
4869 } else {
4870 if (parent != NULL) {
4871 if (parent->content == cur)
4872 parent->content = cur->next;
4873 else if (parent->attrs == cur)
4874 parent->attrs = cur->next;
4875 else if (parent->nameClass == cur)
4876 parent->nameClass = cur->next;
4877 } else {
4878 cur->type = XML_RELAXNG_NOOP;
4879 prev = cur;
4880 }
4881 }
4882 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004883}
4884
4885/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004886 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004887 * @ctxt: a Relax-NG parser context
4888 * @nodes: grammar children nodes
4889 *
4890 * Check for simplification of empty and notAllowed
4891 */
4892static void
4893xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4894 xmlRelaxNGDefinePtr cur,
4895 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004896 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004897
Daniel Veillardfd573f12003-03-16 17:52:32 +00004898 while (cur != NULL) {
4899 if ((cur->type == XML_RELAXNG_REF) ||
4900 (cur->type == XML_RELAXNG_PARENTREF)) {
4901 if (cur->depth != -3) {
4902 cur->depth = -3;
4903 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004904 }
4905 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004906 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004907 if ((parent != NULL) &&
4908 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4909 (parent->type == XML_RELAXNG_LIST) ||
4910 (parent->type == XML_RELAXNG_GROUP) ||
4911 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00004912 (parent->type == XML_RELAXNG_ONEORMORE) ||
4913 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004914 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004915 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004916 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004917 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00004918 (parent->type == XML_RELAXNG_CHOICE)) {
4919 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4920 } else
4921 prev = cur;
4922 } else if (cur->type == XML_RELAXNG_EMPTY){
4923 cur->parent = parent;
4924 if ((parent != NULL) &&
4925 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4926 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004927 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004928 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004929 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004930 if ((parent != NULL) &&
4931 ((parent->type == XML_RELAXNG_GROUP) ||
4932 (parent->type == XML_RELAXNG_INTERLEAVE))) {
4933 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4934 } else
4935 prev = cur;
4936 } else {
4937 cur->parent = parent;
4938 if (cur->content != NULL)
4939 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4940 if (cur->attrs != NULL)
4941 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
4942 if (cur->nameClass != NULL)
4943 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
4944 /*
4945 * This may result in a simplification
4946 */
4947 if ((cur->type == XML_RELAXNG_GROUP) ||
4948 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4949 if (cur->content == NULL)
4950 cur->type = XML_RELAXNG_EMPTY;
4951 else if (cur->content->next == NULL) {
4952 if ((parent == NULL) && (prev == NULL)) {
4953 cur->type = XML_RELAXNG_NOOP;
4954 } else if (prev == NULL) {
4955 parent->content = cur->content;
4956 cur->content->next = cur->next;
4957 cur = cur->content;
4958 } else {
4959 cur->content->next = cur->next;
4960 prev->next = cur->content;
4961 cur = cur->content;
4962 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004963 }
4964 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004965 /*
4966 * the current node may have been transformed back
4967 */
4968 if ((cur->type == XML_RELAXNG_EXCEPT) &&
4969 (cur->content != NULL) &&
4970 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4971 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4972 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4973 if ((parent != NULL) &&
4974 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4975 (parent->type == XML_RELAXNG_LIST) ||
4976 (parent->type == XML_RELAXNG_GROUP) ||
4977 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4978 (parent->type == XML_RELAXNG_ONEORMORE) ||
4979 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4980 parent->type = XML_RELAXNG_NOT_ALLOWED;
4981 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004982 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004983 if ((parent != NULL) &&
4984 (parent->type == XML_RELAXNG_CHOICE)) {
4985 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4986 } else
4987 prev = cur;
4988 } else if (cur->type == XML_RELAXNG_EMPTY){
4989 if ((parent != NULL) &&
4990 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4991 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4992 parent->type = XML_RELAXNG_EMPTY;
4993 break;
4994 }
4995 if ((parent != NULL) &&
4996 ((parent->type == XML_RELAXNG_GROUP) ||
4997 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4998 (parent->type == XML_RELAXNG_CHOICE))) {
4999 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5000 } else
5001 prev = cur;
5002 } else {
5003 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005004 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005005 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005006 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005007 }
5008}
5009
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005010/**
5011 * xmlRelaxNGGroupContentType:
5012 * @ct1: the first content type
5013 * @ct2: the second content type
5014 *
5015 * Try to group 2 content types
5016 *
5017 * Returns the content type
5018 */
5019static xmlRelaxNGContentType
5020xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5021 xmlRelaxNGContentType ct2) {
5022 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5023 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5024 return(XML_RELAXNG_CONTENT_ERROR);
5025 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5026 return(ct2);
5027 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5028 return(ct1);
5029 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5030 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5031 return(XML_RELAXNG_CONTENT_COMPLEX);
5032 return(XML_RELAXNG_CONTENT_ERROR);
5033}
5034
5035/**
5036 * xmlRelaxNGMaxContentType:
5037 * @ct1: the first content type
5038 * @ct2: the second content type
5039 *
5040 * Compute the max content-type
5041 *
5042 * Returns the content type
5043 */
5044static xmlRelaxNGContentType
5045xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5046 xmlRelaxNGContentType ct2) {
5047 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5048 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5049 return(XML_RELAXNG_CONTENT_ERROR);
5050 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5051 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5052 return(XML_RELAXNG_CONTENT_SIMPLE);
5053 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5054 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5055 return(XML_RELAXNG_CONTENT_COMPLEX);
5056 return(XML_RELAXNG_CONTENT_EMPTY);
5057}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005058
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005059/**
5060 * xmlRelaxNGCheckRules:
5061 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005062 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005063 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005064 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005065 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005066 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005067 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005068 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005069 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005070static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005071xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5072 xmlRelaxNGDefinePtr cur, int flags,
5073 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005074 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005075 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005076
Daniel Veillardfd573f12003-03-16 17:52:32 +00005077 while (cur != NULL) {
5078 ret = XML_RELAXNG_CONTENT_EMPTY;
5079 if ((cur->type == XML_RELAXNG_REF) ||
5080 (cur->type == XML_RELAXNG_PARENTREF)) {
5081 if (flags & XML_RELAXNG_IN_LIST) {
5082 if (ctxt->error != NULL)
5083 ctxt->error(ctxt->userData,
5084 "Found forbidden pattern list//ref\n");
5085 ctxt->nbErrors++;
5086 }
5087 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5088 if (ctxt->error != NULL)
5089 ctxt->error(ctxt->userData,
5090 "Found forbidden pattern data/except//ref\n");
5091 ctxt->nbErrors++;
5092 }
5093 if (cur->depth > -4) {
5094 cur->depth = -4;
5095 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5096 flags, cur->type);
5097 cur->depth = ret - 15 ;
5098 } else if (cur->depth == -4) {
5099 ret = XML_RELAXNG_CONTENT_COMPLEX;
5100 } else {
5101 ret = (xmlRelaxNGContentType) cur->depth + 15;
5102 }
5103 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5104 /*
5105 * The 7.3 Attribute derivation rule for groups is plugged there
5106 */
5107 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5108 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5109 if (ctxt->error != NULL)
5110 ctxt->error(ctxt->userData,
5111 "Found forbidden pattern data/except//element(ref)\n");
5112 ctxt->nbErrors++;
5113 }
5114 if (flags & XML_RELAXNG_IN_LIST) {
5115 if (ctxt->error != NULL)
5116 ctxt->error(ctxt->userData,
5117 "Found forbidden pattern list//element(ref)\n");
5118 ctxt->nbErrors++;
5119 }
5120 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5121 if (ctxt->error != NULL)
5122 ctxt->error(ctxt->userData,
5123 "Found forbidden pattern attribute//element(ref)\n");
5124 ctxt->nbErrors++;
5125 }
5126 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5127 if (ctxt->error != NULL)
5128 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005129 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005130 ctxt->nbErrors++;
5131 }
5132 /*
5133 * reset since in the simple form elements are only child
5134 * of grammar/define
5135 */
5136 nflags = 0;
5137 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5138 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5139 if (ctxt->error != NULL)
5140 ctxt->error(ctxt->userData,
5141 "Element %s attributes have a content type error\n",
5142 cur->name);
5143 ctxt->nbErrors++;
5144 }
5145 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5146 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5147 if (ctxt->error != NULL)
5148 ctxt->error(ctxt->userData,
5149 "Element %s has a content type error\n",
5150 cur->name);
5151 ctxt->nbErrors++;
5152 } else {
5153 ret = XML_RELAXNG_CONTENT_COMPLEX;
5154 }
5155 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5156 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5157 if (ctxt->error != NULL)
5158 ctxt->error(ctxt->userData,
5159 "Found forbidden pattern attribute//attribute\n");
5160 ctxt->nbErrors++;
5161 }
5162 if (flags & XML_RELAXNG_IN_LIST) {
5163 if (ctxt->error != NULL)
5164 ctxt->error(ctxt->userData,
5165 "Found forbidden pattern list//attribute\n");
5166 ctxt->nbErrors++;
5167 }
5168 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5169 if (ctxt->error != NULL)
5170 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005171 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005172 ctxt->nbErrors++;
5173 }
5174 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5175 if (ctxt->error != NULL)
5176 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005177 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005178 ctxt->nbErrors++;
5179 }
5180 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5181 if (ctxt->error != NULL)
5182 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005183 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005184 ctxt->nbErrors++;
5185 }
5186 if (flags & XML_RELAXNG_IN_START) {
5187 if (ctxt->error != NULL)
5188 ctxt->error(ctxt->userData,
5189 "Found forbidden pattern start//attribute\n");
5190 ctxt->nbErrors++;
5191 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005192 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5193 if (cur->ns == NULL) {
5194 if (ctxt->error != NULL)
5195 ctxt->error(ctxt->userData,
5196 "Found anyName attribute without oneOrMore ancestor\n");
5197 ctxt->nbErrors++;
5198 } else {
5199 if (ctxt->error != NULL)
5200 ctxt->error(ctxt->userData,
5201 "Found nsName attribute without oneOrMore ancestor\n");
5202 ctxt->nbErrors++;
5203 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005204 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005205 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5206 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5207 ret = XML_RELAXNG_CONTENT_EMPTY;
5208 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5209 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5210 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5211 if (ctxt->error != NULL)
5212 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005213 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005214 ctxt->nbErrors++;
5215 }
5216 if (flags & XML_RELAXNG_IN_START) {
5217 if (ctxt->error != NULL)
5218 ctxt->error(ctxt->userData,
5219 "Found forbidden pattern start//oneOrMore\n");
5220 ctxt->nbErrors++;
5221 }
5222 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5223 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5224 ret = xmlRelaxNGGroupContentType(ret, ret);
5225 } else if (cur->type == XML_RELAXNG_LIST) {
5226 if (flags & XML_RELAXNG_IN_LIST) {
5227 if (ctxt->error != NULL)
5228 ctxt->error(ctxt->userData,
5229 "Found forbidden pattern list//list\n");
5230 ctxt->nbErrors++;
5231 }
5232 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5233 if (ctxt->error != NULL)
5234 ctxt->error(ctxt->userData,
5235 "Found forbidden pattern data/except//list\n");
5236 ctxt->nbErrors++;
5237 }
5238 if (flags & XML_RELAXNG_IN_START) {
5239 if (ctxt->error != NULL)
5240 ctxt->error(ctxt->userData,
5241 "Found forbidden pattern start//list\n");
5242 ctxt->nbErrors++;
5243 }
5244 nflags = flags | XML_RELAXNG_IN_LIST;
5245 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5246 } else if (cur->type == XML_RELAXNG_GROUP) {
5247 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5248 if (ctxt->error != NULL)
5249 ctxt->error(ctxt->userData,
5250 "Found forbidden pattern data/except//group\n");
5251 ctxt->nbErrors++;
5252 }
5253 if (flags & XML_RELAXNG_IN_START) {
5254 if (ctxt->error != NULL)
5255 ctxt->error(ctxt->userData,
5256 "Found forbidden pattern start//group\n");
5257 ctxt->nbErrors++;
5258 }
5259 if (flags & XML_RELAXNG_IN_ONEORMORE)
5260 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5261 else
5262 nflags = flags;
5263 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5264 /*
5265 * The 7.3 Attribute derivation rule for groups is plugged there
5266 */
5267 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5268 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5269 if (flags & XML_RELAXNG_IN_LIST) {
5270 if (ctxt->error != NULL)
5271 ctxt->error(ctxt->userData,
5272 "Found forbidden pattern list//interleave\n");
5273 ctxt->nbErrors++;
5274 }
5275 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5276 if (ctxt->error != NULL)
5277 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005278 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005279 ctxt->nbErrors++;
5280 }
5281 if (flags & XML_RELAXNG_IN_START) {
5282 if (ctxt->error != NULL)
5283 ctxt->error(ctxt->userData,
5284 "Found forbidden pattern start//interleave\n");
5285 ctxt->nbErrors++;
5286 }
5287 if (flags & XML_RELAXNG_IN_ONEORMORE)
5288 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5289 else
5290 nflags = flags;
5291 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5292 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5293 if ((cur->parent != NULL) &&
5294 (cur->parent->type == XML_RELAXNG_DATATYPE))
5295 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5296 else
5297 nflags = flags;
5298 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5299 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5300 if (flags & XML_RELAXNG_IN_START) {
5301 if (ctxt->error != NULL)
5302 ctxt->error(ctxt->userData,
5303 "Found forbidden pattern start//data\n");
5304 ctxt->nbErrors++;
5305 }
5306 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5307 ret = XML_RELAXNG_CONTENT_SIMPLE;
5308 } else if (cur->type == XML_RELAXNG_VALUE) {
5309 if (flags & XML_RELAXNG_IN_START) {
5310 if (ctxt->error != NULL)
5311 ctxt->error(ctxt->userData,
5312 "Found forbidden pattern start//value\n");
5313 ctxt->nbErrors++;
5314 }
5315 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5316 ret = XML_RELAXNG_CONTENT_SIMPLE;
5317 } else if (cur->type == XML_RELAXNG_TEXT) {
5318 if (flags & XML_RELAXNG_IN_LIST) {
5319 if (ctxt->error != NULL)
5320 ctxt->error(ctxt->userData,
5321 "Found forbidden pattern list//text\n");
5322 ctxt->nbErrors++;
5323 }
5324 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5325 if (ctxt->error != NULL)
5326 ctxt->error(ctxt->userData,
5327 "Found forbidden pattern data/except//text\n");
5328 ctxt->nbErrors++;
5329 }
5330 if (flags & XML_RELAXNG_IN_START) {
5331 if (ctxt->error != NULL)
5332 ctxt->error(ctxt->userData,
5333 "Found forbidden pattern start//text\n");
5334 ctxt->nbErrors++;
5335 }
5336 ret = XML_RELAXNG_CONTENT_COMPLEX;
5337 } else if (cur->type == XML_RELAXNG_EMPTY) {
5338 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5339 if (ctxt->error != NULL)
5340 ctxt->error(ctxt->userData,
5341 "Found forbidden pattern data/except//empty\n");
5342 ctxt->nbErrors++;
5343 }
5344 if (flags & XML_RELAXNG_IN_START) {
5345 if (ctxt->error != NULL)
5346 ctxt->error(ctxt->userData,
5347 "Found forbidden pattern start//empty\n");
5348 ctxt->nbErrors++;
5349 }
5350 ret = XML_RELAXNG_CONTENT_EMPTY;
5351 } else if (cur->type == XML_RELAXNG_CHOICE) {
5352 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5353 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5354 } else {
5355 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5356 }
5357 cur = cur->next;
5358 if (ptype == XML_RELAXNG_GROUP) {
5359 val = xmlRelaxNGGroupContentType(val, ret);
5360 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5361 tmp = xmlRelaxNGGroupContentType(val, ret);
5362 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5363 tmp = xmlRelaxNGMaxContentType(val, ret);
5364 } else if (ptype == XML_RELAXNG_CHOICE) {
5365 val = xmlRelaxNGMaxContentType(val, ret);
5366 } else if (ptype == XML_RELAXNG_LIST) {
5367 val = XML_RELAXNG_CONTENT_SIMPLE;
5368 } else if (ptype == XML_RELAXNG_EXCEPT) {
5369 if (ret == XML_RELAXNG_CONTENT_ERROR)
5370 val = XML_RELAXNG_CONTENT_ERROR;
5371 else
5372 val = XML_RELAXNG_CONTENT_SIMPLE;
5373 } else {
5374 val = xmlRelaxNGGroupContentType(val, ret);
5375 }
5376
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005377 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005378 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005379}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005380
5381/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005382 * xmlRelaxNGParseGrammar:
5383 * @ctxt: a Relax-NG parser context
5384 * @nodes: grammar children nodes
5385 *
5386 * parse a Relax-NG <grammar> node
5387 *
5388 * Returns the internal xmlRelaxNGGrammarPtr built or
5389 * NULL in case of error
5390 */
5391static xmlRelaxNGGrammarPtr
5392xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5393 xmlRelaxNGGrammarPtr ret, tmp, old;
5394
Daniel Veillardc482e262003-02-26 14:48:48 +00005395#ifdef DEBUG_GRAMMAR
5396 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5397#endif
5398
Daniel Veillard6eadf632003-01-23 18:29:16 +00005399 ret = xmlRelaxNGNewGrammar(ctxt);
5400 if (ret == NULL)
5401 return(NULL);
5402
5403 /*
5404 * Link the new grammar in the tree
5405 */
5406 ret->parent = ctxt->grammar;
5407 if (ctxt->grammar != NULL) {
5408 tmp = ctxt->grammar->children;
5409 if (tmp == NULL) {
5410 ctxt->grammar->children = ret;
5411 } else {
5412 while (tmp->next != NULL)
5413 tmp = tmp->next;
5414 tmp->next = ret;
5415 }
5416 }
5417
5418 old = ctxt->grammar;
5419 ctxt->grammar = ret;
5420 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5421 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005422 if (ctxt->grammar == NULL) {
5423 if (ctxt->error != NULL)
5424 ctxt->error(ctxt->userData,
5425 "Failed to parse <grammar> content\n");
5426 ctxt->nbErrors++;
5427 } else if (ctxt->grammar->start == NULL) {
5428 if (ctxt->error != NULL)
5429 ctxt->error(ctxt->userData,
5430 "Element <grammar> has no <start>\n");
5431 ctxt->nbErrors++;
5432 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005433
5434 /*
5435 * Apply 4.17 mergingd rules to defines and starts
5436 */
5437 xmlRelaxNGCombineStart(ctxt, ret);
5438 if (ret->defs != NULL) {
5439 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5440 ctxt);
5441 }
5442
5443 /*
5444 * link together defines and refs in this grammar
5445 */
5446 if (ret->refs != NULL) {
5447 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5448 ctxt);
5449 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005450
Daniel Veillard6eadf632003-01-23 18:29:16 +00005451 ctxt->grammar = old;
5452 return(ret);
5453}
5454
5455/**
5456 * xmlRelaxNGParseDocument:
5457 * @ctxt: a Relax-NG parser context
5458 * @node: the root node of the RelaxNG schema
5459 *
5460 * parse a Relax-NG definition resource and build an internal
5461 * xmlRelaxNG struture which can be used to validate instances.
5462 *
5463 * Returns the internal XML RelaxNG structure built or
5464 * NULL in case of error
5465 */
5466static xmlRelaxNGPtr
5467xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5468 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005469 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005470 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005471
5472 if ((ctxt == NULL) || (node == NULL))
5473 return (NULL);
5474
5475 schema = xmlRelaxNGNewRelaxNG(ctxt);
5476 if (schema == NULL)
5477 return(NULL);
5478
Daniel Veillard276be4a2003-01-24 01:03:34 +00005479 olddefine = ctxt->define;
5480 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005481 if (IS_RELAXNG(node, "grammar")) {
5482 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5483 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005484 xmlRelaxNGGrammarPtr tmp, ret;
5485
5486 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005487 if (schema->topgrammar == NULL) {
5488 return(schema);
5489 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005490 /*
5491 * Link the new grammar in the tree
5492 */
5493 ret->parent = ctxt->grammar;
5494 if (ctxt->grammar != NULL) {
5495 tmp = ctxt->grammar->children;
5496 if (tmp == NULL) {
5497 ctxt->grammar->children = ret;
5498 } else {
5499 while (tmp->next != NULL)
5500 tmp = tmp->next;
5501 tmp->next = ret;
5502 }
5503 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005504 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005505 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005507 if (old != NULL)
5508 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005509 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005510 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005511 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005512 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005513 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005514 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5515 while ((schema->topgrammar->start != NULL) &&
5516 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5517 (schema->topgrammar->start->next != NULL))
5518 schema->topgrammar->start = schema->topgrammar->start->content;
5519 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5520 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005521 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005522 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005523
5524#ifdef DEBUG
5525 if (schema == NULL)
5526 xmlGenericError(xmlGenericErrorContext,
5527 "xmlRelaxNGParseDocument() failed\n");
5528#endif
5529
5530 return (schema);
5531}
5532
5533/************************************************************************
5534 * *
5535 * Reading RelaxNGs *
5536 * *
5537 ************************************************************************/
5538
5539/**
5540 * xmlRelaxNGNewParserCtxt:
5541 * @URL: the location of the schema
5542 *
5543 * Create an XML RelaxNGs parse context for that file/resource expected
5544 * to contain an XML RelaxNGs file.
5545 *
5546 * Returns the parser context or NULL in case of error
5547 */
5548xmlRelaxNGParserCtxtPtr
5549xmlRelaxNGNewParserCtxt(const char *URL) {
5550 xmlRelaxNGParserCtxtPtr ret;
5551
5552 if (URL == NULL)
5553 return(NULL);
5554
5555 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5556 if (ret == NULL) {
5557 xmlGenericError(xmlGenericErrorContext,
5558 "Failed to allocate new schama parser context for %s\n", URL);
5559 return (NULL);
5560 }
5561 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5562 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005563 ret->error = xmlGenericError;
5564 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005565 return (ret);
5566}
5567
5568/**
5569 * xmlRelaxNGNewMemParserCtxt:
5570 * @buffer: a pointer to a char array containing the schemas
5571 * @size: the size of the array
5572 *
5573 * Create an XML RelaxNGs parse context for that memory buffer expected
5574 * to contain an XML RelaxNGs file.
5575 *
5576 * Returns the parser context or NULL in case of error
5577 */
5578xmlRelaxNGParserCtxtPtr
5579xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5580 xmlRelaxNGParserCtxtPtr ret;
5581
5582 if ((buffer == NULL) || (size <= 0))
5583 return(NULL);
5584
5585 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5586 if (ret == NULL) {
5587 xmlGenericError(xmlGenericErrorContext,
5588 "Failed to allocate new schama parser context\n");
5589 return (NULL);
5590 }
5591 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5592 ret->buffer = buffer;
5593 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005594 ret->error = xmlGenericError;
5595 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005596 return (ret);
5597}
5598
5599/**
5600 * xmlRelaxNGFreeParserCtxt:
5601 * @ctxt: the schema parser context
5602 *
5603 * Free the resources associated to the schema parser context
5604 */
5605void
5606xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5607 if (ctxt == NULL)
5608 return;
5609 if (ctxt->URL != NULL)
5610 xmlFree(ctxt->URL);
5611 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005612 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005613 if (ctxt->interleaves != NULL)
5614 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005615 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005616 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005617 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005618 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005619 if (ctxt->docTab != NULL)
5620 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005621 if (ctxt->incTab != NULL)
5622 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005623 if (ctxt->defTab != NULL) {
5624 int i;
5625
5626 for (i = 0;i < ctxt->defNr;i++)
5627 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5628 xmlFree(ctxt->defTab);
5629 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005630 xmlFree(ctxt);
5631}
5632
Daniel Veillard6eadf632003-01-23 18:29:16 +00005633/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005634 * xmlRelaxNGNormExtSpace:
5635 * @value: a value
5636 *
5637 * Removes the leading and ending spaces of the value
5638 * The string is modified "in situ"
5639 */
5640static void
5641xmlRelaxNGNormExtSpace(xmlChar *value) {
5642 xmlChar *start = value;
5643 xmlChar *cur = value;
5644 if (value == NULL)
5645 return;
5646
5647 while (IS_BLANK(*cur)) cur++;
5648 if (cur == start) {
5649 do {
5650 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5651 if (*cur == 0)
5652 return;
5653 start = cur;
5654 while (IS_BLANK(*cur)) cur++;
5655 if (*cur == 0) {
5656 *start = 0;
5657 return;
5658 }
5659 } while (1);
5660 } else {
5661 do {
5662 while ((*cur != 0) && (!IS_BLANK(*cur)))
5663 *start++ = *cur++;
5664 if (*cur == 0) {
5665 *start = 0;
5666 return;
5667 }
5668 /* don't try to normalize the inner spaces */
5669 while (IS_BLANK(*cur)) cur++;
5670 *start++ = *cur++;
5671 if (*cur == 0) {
5672 *start = 0;
5673 return;
5674 }
5675 } while (1);
5676 }
5677}
5678
5679/**
5680 * xmlRelaxNGCheckAttributes:
5681 * @ctxt: a Relax-NG parser context
5682 * @node: a Relax-NG node
5683 *
5684 * Check all the attributes on the given node
5685 */
5686static void
5687xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5688 xmlAttrPtr cur, next;
5689
5690 cur = node->properties;
5691 while (cur != NULL) {
5692 next = cur->next;
5693 if ((cur->ns == NULL) ||
5694 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5695 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5696 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5697 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5698 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5699 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005700 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005701 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5702 if (ctxt->error != NULL)
5703 ctxt->error(ctxt->userData,
5704 "Attribute %s is not allowed on %s\n",
5705 cur->name, node->name);
5706 ctxt->nbErrors++;
5707 }
5708 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5709 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5710 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5711 if (ctxt->error != NULL)
5712 ctxt->error(ctxt->userData,
5713 "Attribute %s is not allowed on %s\n",
5714 cur->name, node->name);
5715 ctxt->nbErrors++;
5716 }
5717 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
5718 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
5719 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
5720 if (ctxt->error != NULL)
5721 ctxt->error(ctxt->userData,
5722 "Attribute %s is not allowed on %s\n",
5723 cur->name, node->name);
5724 ctxt->nbErrors++;
5725 }
5726 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
5727 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
5728 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5729 if (ctxt->error != NULL)
5730 ctxt->error(ctxt->userData,
5731 "Attribute %s is not allowed on %s\n",
5732 cur->name, node->name);
5733 ctxt->nbErrors++;
5734 }
5735 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
5736 xmlChar *val;
5737 xmlURIPtr uri;
5738
5739 val = xmlNodeListGetString(node->doc, cur->children, 1);
5740 if (val != NULL) {
5741 if (val[0] != 0) {
5742 uri = xmlParseURI((const char *) val);
5743 if (uri == NULL) {
5744 if (ctxt->error != NULL)
5745 ctxt->error(ctxt->userData,
5746 "Attribute %s contains invalid URI %s\n",
5747 cur->name, val);
5748 ctxt->nbErrors++;
5749 } else {
5750 if (uri->scheme == NULL) {
5751 if (ctxt->error != NULL)
5752 ctxt->error(ctxt->userData,
5753 "Attribute %s URI %s is not absolute\n",
5754 cur->name, val);
5755 ctxt->nbErrors++;
5756 }
5757 if (uri->fragment != NULL) {
5758 if (ctxt->error != NULL)
5759 ctxt->error(ctxt->userData,
5760 "Attribute %s URI %s has a fragment ID\n",
5761 cur->name, val);
5762 ctxt->nbErrors++;
5763 }
5764 xmlFreeURI(uri);
5765 }
5766 }
5767 xmlFree(val);
5768 }
5769 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
5770 if (ctxt->error != NULL)
5771 ctxt->error(ctxt->userData,
5772 "Unknown attribute %s on %s\n",
5773 cur->name, node->name);
5774 ctxt->nbErrors++;
5775 }
5776 }
5777 cur = next;
5778 }
5779}
5780
5781/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00005782 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005783 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00005784 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00005785 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00005786 * Cleanup the subtree from unwanted nodes for parsing, resolve
5787 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00005788 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005789static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00005790xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00005791 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005792
Daniel Veillard6eadf632003-01-23 18:29:16 +00005793 delete = NULL;
5794 cur = root;
5795 while (cur != NULL) {
5796 if (delete != NULL) {
5797 xmlUnlinkNode(delete);
5798 xmlFreeNode(delete);
5799 delete = NULL;
5800 }
5801 if (cur->type == XML_ELEMENT_NODE) {
5802 /*
5803 * Simplification 4.1. Annotations
5804 */
5805 if ((cur->ns == NULL) ||
5806 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00005807 if ((cur->parent != NULL) &&
5808 (cur->parent->type == XML_ELEMENT_NODE) &&
5809 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
5810 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
5811 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
5812 if (ctxt->error != NULL)
5813 ctxt->error(ctxt->userData,
5814 "element %s doesn't allow foreign elements\n",
5815 cur->parent->name);
5816 ctxt->nbErrors++;
5817 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005818 delete = cur;
5819 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005820 } else {
5821 xmlRelaxNGCleanupAttributes(ctxt, cur);
5822 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
5823 xmlChar *href, *ns, *base, *URL;
5824 xmlRelaxNGDocumentPtr docu;
5825 xmlNodePtr tmp;
5826
5827 ns = xmlGetProp(cur, BAD_CAST "ns");
5828 if (ns == NULL) {
5829 tmp = cur->parent;
5830 while ((tmp != NULL) &&
5831 (tmp->type == XML_ELEMENT_NODE)) {
5832 ns = xmlGetProp(tmp, BAD_CAST "ns");
5833 if (ns != NULL)
5834 break;
5835 tmp = tmp->parent;
5836 }
5837 }
5838 href = xmlGetProp(cur, BAD_CAST "href");
5839 if (href == NULL) {
5840 if (ctxt->error != NULL)
5841 ctxt->error(ctxt->userData,
5842 "xmlRelaxNGParse: externalRef has no href attribute\n");
5843 ctxt->nbErrors++;
5844 delete = cur;
5845 goto skip_children;
5846 }
5847 base = xmlNodeGetBase(cur->doc, cur);
5848 URL = xmlBuildURI(href, base);
5849 if (URL == NULL) {
5850 if (ctxt->error != NULL)
5851 ctxt->error(ctxt->userData,
5852 "Failed to compute URL for externalRef %s\n", href);
5853 ctxt->nbErrors++;
5854 if (href != NULL)
5855 xmlFree(href);
5856 if (base != NULL)
5857 xmlFree(base);
5858 delete = cur;
5859 goto skip_children;
5860 }
5861 if (href != NULL)
5862 xmlFree(href);
5863 if (base != NULL)
5864 xmlFree(base);
5865 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
5866 if (docu == NULL) {
5867 if (ctxt->error != NULL)
5868 ctxt->error(ctxt->userData,
5869 "Failed to load externalRef %s\n", URL);
5870 ctxt->nbErrors++;
5871 xmlFree(URL);
5872 delete = cur;
5873 goto skip_children;
5874 }
5875 if (ns != NULL)
5876 xmlFree(ns);
5877 xmlFree(URL);
5878 cur->_private = docu;
5879 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5880 xmlChar *href, *ns, *base, *URL;
5881 xmlRelaxNGIncludePtr incl;
5882 xmlNodePtr tmp;
5883
5884 href = xmlGetProp(cur, BAD_CAST "href");
5885 if (href == NULL) {
5886 if (ctxt->error != NULL)
5887 ctxt->error(ctxt->userData,
5888 "xmlRelaxNGParse: include has no href attribute\n");
5889 ctxt->nbErrors++;
5890 delete = cur;
5891 goto skip_children;
5892 }
5893 base = xmlNodeGetBase(cur->doc, cur);
5894 URL = xmlBuildURI(href, base);
5895 if (URL == NULL) {
5896 if (ctxt->error != NULL)
5897 ctxt->error(ctxt->userData,
5898 "Failed to compute URL for include %s\n", href);
5899 ctxt->nbErrors++;
5900 if (href != NULL)
5901 xmlFree(href);
5902 if (base != NULL)
5903 xmlFree(base);
5904 delete = cur;
5905 goto skip_children;
5906 }
5907 if (href != NULL)
5908 xmlFree(href);
5909 if (base != NULL)
5910 xmlFree(base);
5911 ns = xmlGetProp(cur, BAD_CAST "ns");
5912 if (ns == NULL) {
5913 tmp = cur->parent;
5914 while ((tmp != NULL) &&
5915 (tmp->type == XML_ELEMENT_NODE)) {
5916 ns = xmlGetProp(tmp, BAD_CAST "ns");
5917 if (ns != NULL)
5918 break;
5919 tmp = tmp->parent;
5920 }
5921 }
5922 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5923 if (ns != NULL)
5924 xmlFree(ns);
5925 if (incl == NULL) {
5926 if (ctxt->error != NULL)
5927 ctxt->error(ctxt->userData,
5928 "Failed to load include %s\n", URL);
5929 ctxt->nbErrors++;
5930 xmlFree(URL);
5931 delete = cur;
5932 goto skip_children;
5933 }
5934 xmlFree(URL);
5935 cur->_private = incl;
5936 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5937 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
5938 xmlChar *name, *ns;
5939 xmlNodePtr text = NULL;
5940
5941 /*
5942 * Simplification 4.8. name attribute of element
5943 * and attribute elements
5944 */
5945 name = xmlGetProp(cur, BAD_CAST "name");
5946 if (name != NULL) {
5947 if (cur->children == NULL) {
5948 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5949 name);
5950 } else {
5951 xmlNodePtr node;
5952 node = xmlNewNode(cur->ns, BAD_CAST "name");
5953 if (node != NULL) {
5954 xmlAddPrevSibling(cur->children, node);
5955 text = xmlNewText(name);
5956 xmlAddChild(node, text);
5957 text = node;
5958 }
5959 }
5960 if (text == NULL) {
5961 if (ctxt->error != NULL)
5962 ctxt->error(ctxt->userData,
5963 "Failed to create a name %s element\n", name);
5964 ctxt->nbErrors++;
5965 }
5966 xmlUnsetProp(cur, BAD_CAST "name");
5967 xmlFree(name);
5968 ns = xmlGetProp(cur, BAD_CAST "ns");
5969 if (ns != NULL) {
5970 if (text != NULL) {
5971 xmlSetProp(text, BAD_CAST "ns", ns);
5972 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
5973 }
5974 xmlFree(ns);
5975 } else if (xmlStrEqual(cur->name,
5976 BAD_CAST "attribute")) {
5977 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
5978 }
5979 }
5980 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
5981 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
5982 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
5983 /*
5984 * Simplification 4.8. name attribute of element
5985 * and attribute elements
5986 */
5987 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
5988 xmlNodePtr node;
5989 xmlChar *ns = NULL;
5990
5991 node = cur->parent;
5992 while ((node != NULL) &&
5993 (node->type == XML_ELEMENT_NODE)) {
5994 ns = xmlGetProp(node, BAD_CAST "ns");
5995 if (ns != NULL) {
5996 break;
5997 }
5998 node = node->parent;
5999 }
6000 if (ns == NULL) {
6001 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6002 } else {
6003 xmlSetProp(cur, BAD_CAST "ns", ns);
6004 xmlFree(ns);
6005 }
6006 }
6007 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6008 xmlChar *name, *local, *prefix;
6009
6010 /*
6011 * Simplification: 4.10. QNames
6012 */
6013 name = xmlNodeGetContent(cur);
6014 if (name != NULL) {
6015 local = xmlSplitQName2(name, &prefix);
6016 if (local != NULL) {
6017 xmlNsPtr ns;
6018
6019 ns = xmlSearchNs(cur->doc, cur, prefix);
6020 if (ns == NULL) {
6021 if (ctxt->error != NULL)
6022 ctxt->error(ctxt->userData,
6023 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6024 ctxt->nbErrors++;
6025 } else {
6026 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6027 xmlNodeSetContent(cur, local);
6028 }
6029 xmlFree(local);
6030 xmlFree(prefix);
6031 }
6032 xmlFree(name);
6033 }
6034 }
6035 /*
6036 * 4.16
6037 */
6038 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6039 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6040 if (ctxt->error != NULL)
6041 ctxt->error(ctxt->userData,
6042 "Found nsName/except//nsName forbidden construct\n");
6043 ctxt->nbErrors++;
6044 }
6045 }
6046 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6047 (cur != root)) {
6048 int oldflags = ctxt->flags;
6049
6050 /*
6051 * 4.16
6052 */
6053 if ((cur->parent != NULL) &&
6054 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6055 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6056 xmlRelaxNGCleanupTree(ctxt, cur);
6057 ctxt->flags = oldflags;
6058 goto skip_children;
6059 } else if ((cur->parent != NULL) &&
6060 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6061 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6062 xmlRelaxNGCleanupTree(ctxt, cur);
6063 ctxt->flags = oldflags;
6064 goto skip_children;
6065 }
6066 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6067 /*
6068 * 4.16
6069 */
6070 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6071 if (ctxt->error != NULL)
6072 ctxt->error(ctxt->userData,
6073 "Found anyName/except//anyName forbidden construct\n");
6074 ctxt->nbErrors++;
6075 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6076 if (ctxt->error != NULL)
6077 ctxt->error(ctxt->userData,
6078 "Found nsName/except//anyName forbidden construct\n");
6079 ctxt->nbErrors++;
6080 }
6081 }
6082 /*
6083 * Thisd is not an else since "include" is transformed
6084 * into a div
6085 */
6086 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6087 xmlChar *ns;
6088 xmlNodePtr child, ins, tmp;
6089
6090 /*
6091 * implements rule 4.11
6092 */
6093
6094 ns = xmlGetProp(cur, BAD_CAST "ns");
6095
6096 child = cur->children;
6097 ins = cur;
6098 while (child != NULL) {
6099 if (ns != NULL) {
6100 if (!xmlHasProp(child, BAD_CAST "ns")) {
6101 xmlSetProp(child, BAD_CAST "ns", ns);
6102 }
6103 }
6104 tmp = child->next;
6105 xmlUnlinkNode(child);
6106 ins = xmlAddNextSibling(ins, child);
6107 child = tmp;
6108 }
6109 if (ns != NULL)
6110 xmlFree(ns);
6111 delete = cur;
6112 goto skip_children;
6113 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006114 }
6115 }
6116 /*
6117 * Simplification 4.2 whitespaces
6118 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006119 else if ((cur->type == XML_TEXT_NODE) ||
6120 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006121 if (IS_BLANK_NODE(cur)) {
6122 if (cur->parent->type == XML_ELEMENT_NODE) {
6123 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6124 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6125 delete = cur;
6126 } else {
6127 delete = cur;
6128 goto skip_children;
6129 }
6130 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006131 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006132 delete = cur;
6133 goto skip_children;
6134 }
6135
6136 /*
6137 * Skip to next node
6138 */
6139 if (cur->children != NULL) {
6140 if ((cur->children->type != XML_ENTITY_DECL) &&
6141 (cur->children->type != XML_ENTITY_REF_NODE) &&
6142 (cur->children->type != XML_ENTITY_NODE)) {
6143 cur = cur->children;
6144 continue;
6145 }
6146 }
6147skip_children:
6148 if (cur->next != NULL) {
6149 cur = cur->next;
6150 continue;
6151 }
6152
6153 do {
6154 cur = cur->parent;
6155 if (cur == NULL)
6156 break;
6157 if (cur == root) {
6158 cur = NULL;
6159 break;
6160 }
6161 if (cur->next != NULL) {
6162 cur = cur->next;
6163 break;
6164 }
6165 } while (cur != NULL);
6166 }
6167 if (delete != NULL) {
6168 xmlUnlinkNode(delete);
6169 xmlFreeNode(delete);
6170 delete = NULL;
6171 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006172}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006173
Daniel Veillardc5312d72003-02-21 17:14:10 +00006174/**
6175 * xmlRelaxNGCleanupDoc:
6176 * @ctxt: a Relax-NG parser context
6177 * @doc: an xmldocPtr document pointer
6178 *
6179 * Cleanup the document from unwanted nodes for parsing, resolve
6180 * Include and externalRef lookups.
6181 *
6182 * Returns the cleaned up document or NULL in case of error
6183 */
6184static xmlDocPtr
6185xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6186 xmlNodePtr root;
6187
6188 /*
6189 * Extract the root
6190 */
6191 root = xmlDocGetRootElement(doc);
6192 if (root == NULL) {
6193 if (ctxt->error != NULL)
6194 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6195 ctxt->URL);
6196 ctxt->nbErrors++;
6197 return (NULL);
6198 }
6199 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006200 return(doc);
6201}
6202
6203/**
6204 * xmlRelaxNGParse:
6205 * @ctxt: a Relax-NG parser context
6206 *
6207 * parse a schema definition resource and build an internal
6208 * XML Shema struture which can be used to validate instances.
6209 * *WARNING* this interface is highly subject to change
6210 *
6211 * Returns the internal XML RelaxNG structure built from the resource or
6212 * NULL in case of error
6213 */
6214xmlRelaxNGPtr
6215xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6216{
6217 xmlRelaxNGPtr ret = NULL;
6218 xmlDocPtr doc;
6219 xmlNodePtr root;
6220
6221 xmlRelaxNGInitTypes();
6222
6223 if (ctxt == NULL)
6224 return (NULL);
6225
6226 /*
6227 * First step is to parse the input document into an DOM/Infoset
6228 */
6229 if (ctxt->URL != NULL) {
6230 doc = xmlParseFile((const char *) ctxt->URL);
6231 if (doc == NULL) {
6232 if (ctxt->error != NULL)
6233 ctxt->error(ctxt->userData,
6234 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6235 ctxt->nbErrors++;
6236 return (NULL);
6237 }
6238 } else if (ctxt->buffer != NULL) {
6239 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6240 if (doc == NULL) {
6241 if (ctxt->error != NULL)
6242 ctxt->error(ctxt->userData,
6243 "xmlRelaxNGParse: could not parse schemas\n");
6244 ctxt->nbErrors++;
6245 return (NULL);
6246 }
6247 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6248 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6249 } else {
6250 if (ctxt->error != NULL)
6251 ctxt->error(ctxt->userData,
6252 "xmlRelaxNGParse: nothing to parse\n");
6253 ctxt->nbErrors++;
6254 return (NULL);
6255 }
6256 ctxt->document = doc;
6257
6258 /*
6259 * Some preprocessing of the document content
6260 */
6261 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6262 if (doc == NULL) {
6263 xmlFreeDoc(ctxt->document);
6264 ctxt->document = NULL;
6265 return(NULL);
6266 }
6267
Daniel Veillard6eadf632003-01-23 18:29:16 +00006268 /*
6269 * Then do the parsing for good
6270 */
6271 root = xmlDocGetRootElement(doc);
6272 if (root == NULL) {
6273 if (ctxt->error != NULL)
6274 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6275 ctxt->URL);
6276 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006277 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006278 return (NULL);
6279 }
6280 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006281 if (ret == NULL) {
6282 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006283 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006284 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006285
6286 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006287 * Check the ref/defines links
6288 */
6289 /*
6290 * try to preprocess interleaves
6291 */
6292 if (ctxt->interleaves != NULL) {
6293 xmlHashScan(ctxt->interleaves,
6294 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6295 }
6296
6297 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006298 * if there was a parsing error return NULL
6299 */
6300 if (ctxt->nbErrors > 0) {
6301 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006302 ctxt->document = NULL;
6303 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006304 return(NULL);
6305 }
6306
6307 /*
6308 * Transfer the pointer for cleanup at the schema level.
6309 */
6310 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006311 ctxt->document = NULL;
6312 ret->documents = ctxt->documents;
6313 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006314
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006315 ret->includes = ctxt->includes;
6316 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006317 ret->defNr = ctxt->defNr;
6318 ret->defTab = ctxt->defTab;
6319 ctxt->defTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006320
6321 return (ret);
6322}
6323
6324/**
6325 * xmlRelaxNGSetParserErrors:
6326 * @ctxt: a Relax-NG validation context
6327 * @err: the error callback
6328 * @warn: the warning callback
6329 * @ctx: contextual data for the callbacks
6330 *
6331 * Set the callback functions used to handle errors for a validation context
6332 */
6333void
6334xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6335 xmlRelaxNGValidityErrorFunc err,
6336 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6337 if (ctxt == NULL)
6338 return;
6339 ctxt->error = err;
6340 ctxt->warning = warn;
6341 ctxt->userData = ctx;
6342}
6343/************************************************************************
6344 * *
6345 * Dump back a compiled form *
6346 * *
6347 ************************************************************************/
6348static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6349
6350/**
6351 * xmlRelaxNGDumpDefines:
6352 * @output: the file output
6353 * @defines: a list of define structures
6354 *
6355 * Dump a RelaxNG structure back
6356 */
6357static void
6358xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6359 while (defines != NULL) {
6360 xmlRelaxNGDumpDefine(output, defines);
6361 defines = defines->next;
6362 }
6363}
6364
6365/**
6366 * xmlRelaxNGDumpDefine:
6367 * @output: the file output
6368 * @define: a define structure
6369 *
6370 * Dump a RelaxNG structure back
6371 */
6372static void
6373xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6374 if (define == NULL)
6375 return;
6376 switch(define->type) {
6377 case XML_RELAXNG_EMPTY:
6378 fprintf(output, "<empty/>\n");
6379 break;
6380 case XML_RELAXNG_NOT_ALLOWED:
6381 fprintf(output, "<notAllowed/>\n");
6382 break;
6383 case XML_RELAXNG_TEXT:
6384 fprintf(output, "<text/>\n");
6385 break;
6386 case XML_RELAXNG_ELEMENT:
6387 fprintf(output, "<element>\n");
6388 if (define->name != NULL) {
6389 fprintf(output, "<name");
6390 if (define->ns != NULL)
6391 fprintf(output, " ns=\"%s\"", define->ns);
6392 fprintf(output, ">%s</name>\n", define->name);
6393 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006394 xmlRelaxNGDumpDefines(output, define->attrs);
6395 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006396 fprintf(output, "</element>\n");
6397 break;
6398 case XML_RELAXNG_LIST:
6399 fprintf(output, "<list>\n");
6400 xmlRelaxNGDumpDefines(output, define->content);
6401 fprintf(output, "</list>\n");
6402 break;
6403 case XML_RELAXNG_ONEORMORE:
6404 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006405 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006406 fprintf(output, "</oneOrMore>\n");
6407 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006408 case XML_RELAXNG_ZEROORMORE:
6409 fprintf(output, "<zeroOrMore>\n");
6410 xmlRelaxNGDumpDefines(output, define->content);
6411 fprintf(output, "</zeroOrMore>\n");
6412 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006413 case XML_RELAXNG_CHOICE:
6414 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006415 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006416 fprintf(output, "</choice>\n");
6417 break;
6418 case XML_RELAXNG_GROUP:
6419 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006420 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006421 fprintf(output, "</group>\n");
6422 break;
6423 case XML_RELAXNG_INTERLEAVE:
6424 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006425 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006426 fprintf(output, "</interleave>\n");
6427 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006428 case XML_RELAXNG_OPTIONAL:
6429 fprintf(output, "<optional>\n");
6430 xmlRelaxNGDumpDefines(output, define->content);
6431 fprintf(output, "</optional>\n");
6432 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006433 case XML_RELAXNG_ATTRIBUTE:
6434 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006435 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006436 fprintf(output, "</attribute>\n");
6437 break;
6438 case XML_RELAXNG_DEF:
6439 fprintf(output, "<define");
6440 if (define->name != NULL)
6441 fprintf(output, " name=\"%s\"", define->name);
6442 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006443 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006444 fprintf(output, "</define>\n");
6445 break;
6446 case XML_RELAXNG_REF:
6447 fprintf(output, "<ref");
6448 if (define->name != NULL)
6449 fprintf(output, " name=\"%s\"", define->name);
6450 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006451 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006452 fprintf(output, "</ref>\n");
6453 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006454 case XML_RELAXNG_PARENTREF:
6455 fprintf(output, "<parentRef");
6456 if (define->name != NULL)
6457 fprintf(output, " name=\"%s\"", define->name);
6458 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006459 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006460 fprintf(output, "</parentRef>\n");
6461 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006462 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006463 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006464 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006465 fprintf(output, "</externalRef>\n");
6466 break;
6467 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006468 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006469 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006470 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006471 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006472 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006473 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006474 TODO
6475 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006476 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006477 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006478 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006479 }
6480}
6481
6482/**
6483 * xmlRelaxNGDumpGrammar:
6484 * @output: the file output
6485 * @grammar: a grammar structure
6486 * @top: is this a top grammar
6487 *
6488 * Dump a RelaxNG structure back
6489 */
6490static void
6491xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6492{
6493 if (grammar == NULL)
6494 return;
6495
6496 fprintf(output, "<grammar");
6497 if (top)
6498 fprintf(output,
6499 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6500 switch(grammar->combine) {
6501 case XML_RELAXNG_COMBINE_UNDEFINED:
6502 break;
6503 case XML_RELAXNG_COMBINE_CHOICE:
6504 fprintf(output, " combine=\"choice\"");
6505 break;
6506 case XML_RELAXNG_COMBINE_INTERLEAVE:
6507 fprintf(output, " combine=\"interleave\"");
6508 break;
6509 default:
6510 fprintf(output, " <!-- invalid combine value -->");
6511 }
6512 fprintf(output, ">\n");
6513 if (grammar->start == NULL) {
6514 fprintf(output, " <!-- grammar had no start -->");
6515 } else {
6516 fprintf(output, "<start>\n");
6517 xmlRelaxNGDumpDefine(output, grammar->start);
6518 fprintf(output, "</start>\n");
6519 }
6520 /* TODO ? Dump the defines ? */
6521 fprintf(output, "</grammar>\n");
6522}
6523
6524/**
6525 * xmlRelaxNGDump:
6526 * @output: the file output
6527 * @schema: a schema structure
6528 *
6529 * Dump a RelaxNG structure back
6530 */
6531void
6532xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6533{
6534 if (schema == NULL) {
6535 fprintf(output, "RelaxNG empty or failed to compile\n");
6536 return;
6537 }
6538 fprintf(output, "RelaxNG: ");
6539 if (schema->doc == NULL) {
6540 fprintf(output, "no document\n");
6541 } else if (schema->doc->URL != NULL) {
6542 fprintf(output, "%s\n", schema->doc->URL);
6543 } else {
6544 fprintf(output, "\n");
6545 }
6546 if (schema->topgrammar == NULL) {
6547 fprintf(output, "RelaxNG has no top grammar\n");
6548 return;
6549 }
6550 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6551}
6552
Daniel Veillardfebcca42003-02-16 15:44:18 +00006553/**
6554 * xmlRelaxNGDumpTree:
6555 * @output: the file output
6556 * @schema: a schema structure
6557 *
6558 * Dump the transformed RelaxNG tree.
6559 */
6560void
6561xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6562{
6563 if (schema == NULL) {
6564 fprintf(output, "RelaxNG empty or failed to compile\n");
6565 return;
6566 }
6567 if (schema->doc == NULL) {
6568 fprintf(output, "no document\n");
6569 } else {
6570 xmlDocDump(output, schema->doc);
6571 }
6572}
6573
Daniel Veillard6eadf632003-01-23 18:29:16 +00006574/************************************************************************
6575 * *
6576 * Validation implementation *
6577 * *
6578 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006579static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6580 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006581static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6582 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006583
6584/**
6585 * xmlRelaxNGSkipIgnored:
6586 * @ctxt: a schema validation context
6587 * @node: the top node.
6588 *
6589 * Skip ignorable nodes in that context
6590 *
6591 * Returns the new sibling or NULL in case of error.
6592 */
6593static xmlNodePtr
6594xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6595 xmlNodePtr node) {
6596 /*
6597 * TODO complete and handle entities
6598 */
6599 while ((node != NULL) &&
6600 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006601 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006602 (((node->type == XML_TEXT_NODE) ||
6603 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard6eadf632003-01-23 18:29:16 +00006604 (IS_BLANK_NODE(node))))) {
6605 node = node->next;
6606 }
6607 return(node);
6608}
6609
6610/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006611 * xmlRelaxNGNormalize:
6612 * @ctxt: a schema validation context
6613 * @str: the string to normalize
6614 *
6615 * Implements the normalizeWhiteSpace( s ) function from
6616 * section 6.2.9 of the spec
6617 *
6618 * Returns the new string or NULL in case of error.
6619 */
6620static xmlChar *
6621xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6622 xmlChar *ret, *p;
6623 const xmlChar *tmp;
6624 int len;
6625
6626 if (str == NULL)
6627 return(NULL);
6628 tmp = str;
6629 while (*tmp != 0) tmp++;
6630 len = tmp - str;
6631
6632 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6633 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006634 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006635 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006636 } else {
6637 xmlGenericError(xmlGenericErrorContext,
6638 "xmlRelaxNGNormalize: out of memory\n");
6639 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006640 return(NULL);
6641 }
6642 p = ret;
6643 while (IS_BLANK(*str)) str++;
6644 while (*str != 0) {
6645 if (IS_BLANK(*str)) {
6646 while (IS_BLANK(*str)) str++;
6647 if (*str == 0)
6648 break;
6649 *p++ = ' ';
6650 } else
6651 *p++ = *str++;
6652 }
6653 *p = 0;
6654 return(ret);
6655}
6656
6657/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006658 * xmlRelaxNGValidateDatatype:
6659 * @ctxt: a Relax-NG validation context
6660 * @value: the string value
6661 * @type: the datatype definition
6662 *
6663 * Validate the given value against the dataype
6664 *
6665 * Returns 0 if the validation succeeded or an error code.
6666 */
6667static int
6668xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
6669 xmlRelaxNGDefinePtr define) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006670 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006671 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006672 void *result = NULL;
6673 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006674
6675 if ((define == NULL) || (define->data == NULL)) {
6676 return(-1);
6677 }
6678 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006679 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006680 if ((define->attrs != NULL) &&
6681 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006682 ret = lib->check(lib->data, define->name, value, &result);
6683 } else {
6684 ret = lib->check(lib->data, define->name, value, NULL);
6685 }
6686 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006687 ret = -1;
6688 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006689 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006690 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6691 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006692 return(-1);
6693 } else if (ret == 1) {
6694 ret = 0;
6695 } else {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006696 VALID_ERR3(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006697 ret = -1;
6698 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006699 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006700 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6701 if (lib->facet != NULL) {
6702 tmp = lib->facet(lib->data, define->name, cur->name,
6703 cur->value, value, result);
6704 if (tmp != 0)
6705 ret = -1;
6706 }
6707 cur = cur->next;
6708 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006709 if ((ret == 0) && (define->content != NULL)) {
6710 const xmlChar *oldvalue, *oldendvalue;
6711
6712 oldvalue = ctxt->state->value;
6713 oldendvalue = ctxt->state->endvalue;
6714 ctxt->state->value = (xmlChar *) value;
6715 ctxt->state->endvalue = NULL;
6716 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6717 ctxt->state->value = (xmlChar *) oldvalue;
6718 ctxt->state->endvalue = (xmlChar *) oldendvalue;
6719 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006720 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6721 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006722 return(ret);
6723}
6724
6725/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006726 * xmlRelaxNGNextValue:
6727 * @ctxt: a Relax-NG validation context
6728 *
6729 * Skip to the next value when validating within a list
6730 *
6731 * Returns 0 if the operation succeeded or an error code.
6732 */
6733static int
6734xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
6735 xmlChar *cur;
6736
6737 cur = ctxt->state->value;
6738 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
6739 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00006740 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006741 return(0);
6742 }
6743 while (*cur != 0) cur++;
6744 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
6745 if (cur == ctxt->state->endvalue)
6746 ctxt->state->value = NULL;
6747 else
6748 ctxt->state->value = cur;
6749 return(0);
6750}
6751
6752/**
6753 * xmlRelaxNGValidateValueList:
6754 * @ctxt: a Relax-NG validation context
6755 * @defines: the list of definitions to verify
6756 *
6757 * Validate the given set of definitions for the current value
6758 *
6759 * Returns 0 if the validation succeeded or an error code.
6760 */
6761static int
6762xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
6763 xmlRelaxNGDefinePtr defines) {
6764 int ret = 0;
6765
6766 while (defines != NULL) {
6767 ret = xmlRelaxNGValidateValue(ctxt, defines);
6768 if (ret != 0)
6769 break;
6770 defines = defines->next;
6771 }
6772 return(ret);
6773}
6774
6775/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006776 * xmlRelaxNGValidateValue:
6777 * @ctxt: a Relax-NG validation context
6778 * @define: the definition to verify
6779 *
6780 * Validate the given definition for the current value
6781 *
6782 * Returns 0 if the validation succeeded or an error code.
6783 */
6784static int
6785xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6786 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00006787 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006788 xmlChar *value;
6789
6790 value = ctxt->state->value;
6791 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006792 case XML_RELAXNG_EMPTY: {
6793 if ((value != NULL) && (value[0] != 0)) {
6794 int idx = 0;
6795
6796 while (IS_BLANK(value[idx]))
6797 idx++;
6798 if (value[idx] != 0)
6799 ret = -1;
6800 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006801 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00006802 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006803 case XML_RELAXNG_TEXT:
6804 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00006805 case XML_RELAXNG_VALUE: {
6806 if (!xmlStrEqual(value, define->value)) {
6807 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006808 xmlRelaxNGTypeLibraryPtr lib;
6809
6810 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
6811 if ((lib != NULL) && (lib->comp != NULL))
6812 ret = lib->comp(lib->data, define->name, value,
6813 define->value);
6814 else
6815 ret = -1;
6816 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006817 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006818 return(-1);
6819 } else if (ret == 1) {
6820 ret = 0;
6821 } else {
6822 ret = -1;
6823 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006824 } else {
6825 xmlChar *nval, *nvalue;
6826
6827 /*
6828 * TODO: trivial optimizations are possible by
6829 * computing at compile-time
6830 */
6831 nval = xmlRelaxNGNormalize(ctxt, define->value);
6832 nvalue = xmlRelaxNGNormalize(ctxt, value);
6833
Daniel Veillardea3f3982003-01-26 19:45:18 +00006834 if ((nval == NULL) || (nvalue == NULL) ||
6835 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00006836 ret = -1;
6837 if (nval != NULL)
6838 xmlFree(nval);
6839 if (nvalue != NULL)
6840 xmlFree(nvalue);
6841 }
6842 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006843 if (ret == 0)
6844 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00006845 break;
6846 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006847 case XML_RELAXNG_DATATYPE: {
6848 ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
6849 if (ret == 0)
6850 xmlRelaxNGNextValue(ctxt);
6851
6852 break;
6853 }
6854 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006855 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006856 xmlChar *oldvalue;
6857
6858 oldflags = ctxt->flags;
6859 ctxt->flags |= FLAGS_IGNORABLE;
6860
6861 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006862 while (list != NULL) {
6863 ret = xmlRelaxNGValidateValue(ctxt, list);
6864 if (ret == 0) {
6865 break;
6866 }
6867 ctxt->state->value = oldvalue;
6868 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006869 }
6870 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006871 if (ret != 0) {
6872 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6873 xmlRelaxNGDumpValidError(ctxt);
6874 } else {
6875 ctxt->errNr = 0;
6876 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006877 if (ret == 0)
6878 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006879 break;
6880 }
6881 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006882 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006883 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00006884#ifdef DEBUG_LIST
6885 int nb_values = 0;
6886#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006887
6888 oldvalue = ctxt->state->value;
6889 oldend = ctxt->state->endvalue;
6890
6891 val = xmlStrdup(oldvalue);
6892 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006893 val = xmlStrdup(BAD_CAST "");
6894 }
6895 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006896 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006897 return(-1);
6898 }
6899 cur = val;
6900 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006901 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006902 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00006903 cur++;
6904#ifdef DEBUG_LIST
6905 nb_values++;
6906#endif
6907 while (IS_BLANK(*cur))
6908 *cur++ = 0;
6909 } else
6910 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006911 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006912#ifdef DEBUG_LIST
6913 xmlGenericError(xmlGenericErrorContext,
6914 "list value: '%s' found %d items\n", oldvalue, nb_values);
6915 nb_values = 0;
6916#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006917 ctxt->state->endvalue = cur;
6918 cur = val;
6919 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006920
Daniel Veillardfd573f12003-03-16 17:52:32 +00006921 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006922
Daniel Veillardfd573f12003-03-16 17:52:32 +00006923 while (list != NULL) {
6924 if (ctxt->state->value == ctxt->state->endvalue)
6925 ctxt->state->value = NULL;
6926 ret = xmlRelaxNGValidateValue(ctxt, list);
6927 if (ret != 0) {
6928#ifdef DEBUG_LIST
6929 xmlGenericError(xmlGenericErrorContext,
6930 "Failed to validate value: '%s' with %d rule\n",
6931 ctxt->state->value, nb_values);
6932#endif
6933 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006934 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006935#ifdef DEBUG_LIST
6936 nb_values++;
6937#endif
6938 list = list->next;
6939 }
6940
6941 if ((ret == 0) && (ctxt->state->value != NULL) &&
6942 (ctxt->state->value != ctxt->state->endvalue)) {
6943 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
6944 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006945 }
6946 xmlFree(val);
6947 ctxt->state->value = oldvalue;
6948 ctxt->state->endvalue = oldend;
6949 break;
6950 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006951 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006952 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6953 if (ret != 0) {
6954 break;
6955 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006956 /* no break on purpose */
6957 case XML_RELAXNG_ZEROORMORE: {
6958 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006959
6960 oldflags = ctxt->flags;
6961 ctxt->flags |= FLAGS_IGNORABLE;
6962 cur = ctxt->state->value;
6963 temp = NULL;
6964 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
6965 (temp != cur)) {
6966 temp = cur;
6967 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6968 if (ret != 0) {
6969 ctxt->state->value = temp;
6970 ret = 0;
6971 break;
6972 }
6973 cur = ctxt->state->value;
6974 }
6975 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006976 if (ret != 0) {
6977 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6978 xmlRelaxNGDumpValidError(ctxt);
6979 } else {
6980 ctxt->errNr = 0;
6981 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006982 break;
6983 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006984 case XML_RELAXNG_EXCEPT: {
6985 xmlRelaxNGDefinePtr list;
6986
6987 list = define->content;
6988 while (list != NULL) {
6989 ret = xmlRelaxNGValidateValue(ctxt, list);
6990 if (ret == 0) {
6991 ret = -1;
6992 break;
6993 } else
6994 ret = 0;
6995 list = list->next;
6996 }
6997 break;
6998 }
Daniel Veillard463a5472003-02-27 21:30:32 +00006999 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007000 case XML_RELAXNG_GROUP: {
7001 xmlRelaxNGDefinePtr list;
7002
7003 list = define->content;
7004 while (list != NULL) {
7005 ret = xmlRelaxNGValidateValue(ctxt, list);
7006 if (ret != 0) {
7007 ret = -1;
7008 break;
7009 } else
7010 ret = 0;
7011 list = list->next;
7012 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007013 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007014 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007015 case XML_RELAXNG_REF:
7016 case XML_RELAXNG_PARENTREF:
7017 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7018 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007019 default:
7020 TODO
7021 ret = -1;
7022 }
7023 return(ret);
7024}
7025
7026/**
7027 * xmlRelaxNGValidateValueContent:
7028 * @ctxt: a Relax-NG validation context
7029 * @defines: the list of definitions to verify
7030 *
7031 * Validate the given definitions for the current value
7032 *
7033 * Returns 0 if the validation succeeded or an error code.
7034 */
7035static int
7036xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7037 xmlRelaxNGDefinePtr defines) {
7038 int ret = 0;
7039
7040 while (defines != NULL) {
7041 ret = xmlRelaxNGValidateValue(ctxt, defines);
7042 if (ret != 0)
7043 break;
7044 defines = defines->next;
7045 }
7046 return(ret);
7047}
7048
7049/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007050 * xmlRelaxNGAttributeMatch:
7051 * @ctxt: a Relax-NG validation context
7052 * @define: the definition to check
7053 * @prop: the attribute
7054 *
7055 * Check if the attribute matches the definition nameClass
7056 *
7057 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7058 */
7059static int
7060xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7061 xmlRelaxNGDefinePtr define,
7062 xmlAttrPtr prop) {
7063 int ret;
7064
7065 if (define->name != NULL) {
7066 if (!xmlStrEqual(define->name, prop->name))
7067 return(0);
7068 }
7069 if (define->ns != NULL) {
7070 if (define->ns[0] == 0) {
7071 if (prop->ns != NULL)
7072 return(0);
7073 } else {
7074 if ((prop->ns == NULL) ||
7075 (!xmlStrEqual(define->ns, prop->ns->href)))
7076 return(0);
7077 }
7078 }
7079 if (define->nameClass == NULL)
7080 return(1);
7081 define = define->nameClass;
7082 if (define->type == XML_RELAXNG_EXCEPT) {
7083 xmlRelaxNGDefinePtr list;
7084
7085 list = define->content;
7086 while (list != NULL) {
7087 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7088 if (ret == 1)
7089 return(0);
7090 if (ret < 0)
7091 return(ret);
7092 list = list->next;
7093 }
7094 } else {
7095 TODO
7096 }
7097 return(1);
7098}
7099
7100/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007101 * xmlRelaxNGValidateAttribute:
7102 * @ctxt: a Relax-NG validation context
7103 * @define: the definition to verify
7104 *
7105 * Validate the given attribute definition for that node
7106 *
7107 * Returns 0 if the validation succeeded or an error code.
7108 */
7109static int
7110xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7111 xmlRelaxNGDefinePtr define) {
7112 int ret = 0, i;
7113 xmlChar *value, *oldvalue;
7114 xmlAttrPtr prop = NULL, tmp;
7115
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007116 if (ctxt->state->nbAttrLeft <= 0)
7117 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007118 if (define->name != NULL) {
7119 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7120 tmp = ctxt->state->attrs[i];
7121 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7122 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7123 (tmp->ns == NULL)) ||
7124 ((tmp->ns != NULL) &&
7125 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7126 prop = tmp;
7127 break;
7128 }
7129 }
7130 }
7131 if (prop != NULL) {
7132 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7133 oldvalue = ctxt->state->value;
7134 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007135 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007136 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007137 if (ctxt->state->value != NULL)
7138 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007139 if (value != NULL)
7140 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007141 ctxt->state->value = oldvalue;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007142 if (ret == 0) {
7143 /*
7144 * flag the attribute as processed
7145 */
7146 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007147 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007148 }
7149 } else {
7150 ret = -1;
7151 }
7152#ifdef DEBUG
7153 xmlGenericError(xmlGenericErrorContext,
7154 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7155#endif
7156 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007157 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7158 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007159 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007160 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007161 prop = tmp;
7162 break;
7163 }
7164 }
7165 if (prop != NULL) {
7166 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7167 oldvalue = ctxt->state->value;
7168 ctxt->state->value = value;
7169 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007170 if (ctxt->state->value != NULL)
7171 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007172 if (value != NULL)
7173 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007174 ctxt->state->value = oldvalue;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007175 if (ret == 0) {
7176 /*
7177 * flag the attribute as processed
7178 */
7179 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007180 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007181 }
7182 } else {
7183 ret = -1;
7184 }
7185#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007186 if (define->ns != NULL) {
7187 xmlGenericError(xmlGenericErrorContext,
7188 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7189 define->ns, ret);
7190 } else {
7191 xmlGenericError(xmlGenericErrorContext,
7192 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7193 ret);
7194 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007195#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007196 }
7197
7198 return(ret);
7199}
7200
7201/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007202 * xmlRelaxNGValidateAttributeList:
7203 * @ctxt: a Relax-NG validation context
7204 * @define: the list of definition to verify
7205 *
7206 * Validate the given node against the list of attribute definitions
7207 *
7208 * Returns 0 if the validation succeeded or an error code.
7209 */
7210static int
7211xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7212 xmlRelaxNGDefinePtr defines) {
7213 int ret = 0;
7214 while (defines != NULL) {
7215 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7216 ret = -1;
7217 defines = defines->next;
7218 }
7219 return(ret);
7220}
7221
7222/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007223 * xmlRelaxNGNodeMatchesList:
7224 * @node: the node
7225 * @list: a NULL terminated array of definitions
7226 *
7227 * Check if a node can be matched by one of the definitions
7228 *
7229 * Returns 1 if matches 0 otherwise
7230 */
7231static int
7232xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7233 xmlRelaxNGDefinePtr cur;
7234 int i = 0;
7235
7236 if ((node == NULL) || (list == NULL))
7237 return(0);
7238
7239 cur = list[i++];
7240 while (cur != NULL) {
7241 if ((node->type == XML_ELEMENT_NODE) &&
7242 (cur->type == XML_RELAXNG_ELEMENT)) {
7243 if (cur->name == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007244 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7245 if (node->ns == NULL)
7246 return(1);
7247 } else {
7248 if ((node->ns != NULL) &&
7249 (xmlStrEqual(node->ns->href, cur->ns)))
7250 return(1);
7251 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007252 } else if (xmlStrEqual(cur->name, node->name)) {
7253 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7254 if (node->ns == NULL)
7255 return(1);
7256 } else {
7257 if ((node->ns != NULL) &&
7258 (xmlStrEqual(node->ns->href, cur->ns)))
7259 return(1);
7260 }
7261 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007262 } else if (((node->type == XML_TEXT_NODE) ||
7263 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007264 (cur->type == XML_RELAXNG_TEXT)) {
7265 return(1);
7266 }
7267 cur = list[i++];
7268 }
7269 return(0);
7270}
7271
7272/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007273 * xmlRelaxNGValidateInterleave:
7274 * @ctxt: a Relax-NG validation context
7275 * @define: the definition to verify
7276 *
7277 * Validate an interleave definition for a node.
7278 *
7279 * Returns 0 if the validation succeeded or an error code.
7280 */
7281static int
7282xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7283 xmlRelaxNGDefinePtr define) {
7284 int ret = 0, i, nbgroups, left;
7285 int errNr = ctxt->errNr;
7286
7287 xmlRelaxNGValidStatePtr oldstate;
7288 xmlRelaxNGPartitionPtr partitions;
7289 xmlRelaxNGInterleaveGroupPtr group = NULL;
7290 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7291 xmlNodePtr *list = NULL, *lasts = NULL;
7292
7293 if (define->data != NULL) {
7294 partitions = (xmlRelaxNGPartitionPtr) define->data;
7295 nbgroups = partitions->nbgroups;
7296 left = nbgroups;
7297 } else {
7298 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7299 return(-1);
7300 }
7301
7302 /*
7303 * Build arrays to store the first and last node of the chain
7304 * pertaining to each group
7305 */
7306 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7307 if (list == NULL) {
7308 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7309 return(-1);
7310 }
7311 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7312 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7313 if (lasts == NULL) {
7314 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7315 return(-1);
7316 }
7317 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7318
7319 /*
7320 * Walk the sequence of children finding the right group and
7321 * sorting them in sequences.
7322 */
7323 cur = ctxt->state->seq;
7324 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7325 start = cur;
7326 while (cur != NULL) {
7327 ctxt->state->seq = cur;
7328 for (i = 0;i < nbgroups;i++) {
7329 group = partitions->groups[i];
7330 if (group == NULL)
7331 continue;
7332 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7333 break;
7334 }
7335 /*
7336 * We break as soon as an element not matched is found
7337 */
7338 if (i >= nbgroups) {
7339 break;
7340 }
7341 if (lasts[i] != NULL) {
7342 lasts[i]->next = cur;
7343 lasts[i] = cur;
7344 } else {
7345 list[i] = cur;
7346 lasts[i] = cur;
7347 }
7348 if (cur->next != NULL)
7349 lastchg = cur->next;
7350 else
7351 lastchg = cur;
7352 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7353 }
7354 if (ret != 0) {
7355 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7356 ret = -1;
7357 goto done;
7358 }
7359 lastelem = cur;
7360 oldstate = ctxt->state;
7361 for (i = 0;i < nbgroups;i++) {
7362 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7363 group = partitions->groups[i];
7364 if (lasts[i] != NULL) {
7365 last = lasts[i]->next;
7366 lasts[i]->next = NULL;
7367 }
7368 ctxt->state->seq = list[i];
7369 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7370 if (ret != 0)
7371 break;
7372 if (ctxt->state != NULL) {
7373 cur = ctxt->state->seq;
7374 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7375 xmlRelaxNGFreeValidState(oldstate);
7376 oldstate = ctxt->state;
7377 ctxt->state = NULL;
7378 if (cur != NULL) {
7379 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7380 ret = -1;
7381 ctxt->state = oldstate;
7382 goto done;
7383 }
7384 } else if (ctxt->states != NULL) {
7385 int j;
7386 int found = 0;
7387
7388 for (j = 0;j < ctxt->states->nbState;j++) {
7389 cur = ctxt->states->tabState[j]->seq;
7390 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7391 if (cur == NULL) {
7392 found = 1;
7393 break;
7394 }
7395 }
7396 if (ctxt->states->nbState > 0) {
7397 xmlRelaxNGFreeValidState(oldstate);
7398 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7399 }
7400 for (j = 0;j < ctxt->states->nbState - 1;j++) {
7401 xmlRelaxNGFreeValidState(ctxt->states->tabState[j]);
7402 }
7403 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7404 ctxt->states = NULL;
7405 if (found == 0) {
7406 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7407 ret = -1;
7408 ctxt->state = oldstate;
7409 goto done;
7410 }
7411 } else {
7412 ret = -1;
7413 break;
7414 }
7415 if (lasts[i] != NULL) {
7416 lasts[i]->next = last;
7417 }
7418 }
7419 if (ctxt->state != NULL)
7420 xmlRelaxNGFreeValidState(ctxt->state);
7421 ctxt->state = oldstate;
7422 ctxt->state->seq = lastelem;
7423 if (ret != 0) {
7424 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7425 ret = -1;
7426 goto done;
7427 }
7428
7429done:
7430 /*
7431 * builds the next links chain from the prev one
7432 */
7433 cur = lastchg;
7434 while (cur != NULL) {
7435 if ((cur == start) || (cur->prev == NULL))
7436 break;
7437 cur->prev->next = cur;
7438 cur = cur->prev;
7439 }
7440 if (ret == 0) {
7441 ctxt->errNr = errNr;
7442 }
7443
7444 xmlFree(list);
7445 xmlFree(lasts);
7446 return(ret);
7447}
7448
7449/**
7450 * xmlRelaxNGValidateDefinitionList:
7451 * @ctxt: a Relax-NG validation context
7452 * @define: the list of definition to verify
7453 *
7454 * Validate the given node content against the (list) of definitions
7455 *
7456 * Returns 0 if the validation succeeded or an error code.
7457 */
7458static int
7459xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7460 xmlRelaxNGDefinePtr defines) {
7461 int ret = 0, res;
7462
7463
Daniel Veillard952379b2003-03-17 15:37:12 +00007464 if (defines == NULL) {
7465 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7466 return(-1);
7467 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007468 while (defines != NULL) {
7469 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7470 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7471 if (res < 0)
7472 ret = -1;
7473 } else {
7474 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7475 return(-1);
7476 }
7477 if (ret < 0)
7478 break;
7479 defines = defines->next;
7480 }
7481
7482 return(ret);
7483}
7484
7485/**
7486 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007487 * @ctxt: a Relax-NG validation context
7488 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007489 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007490 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007491 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007492 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007493 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007494 */
7495static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007496xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7497 xmlRelaxNGDefinePtr define,
7498 xmlNodePtr elem) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007499 int ret, oldflags;
7500
Daniel Veillardfd573f12003-03-16 17:52:32 +00007501 if (define->name != NULL) {
7502 if (!xmlStrEqual(elem->name, define->name)) {
7503 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7504 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007505 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007506 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007507 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7508 if (elem->ns == NULL) {
7509 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7510 elem->name);
7511 return(0);
7512 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7513 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7514 elem->name, define->ns);
7515 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007516 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007517 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7518 (define->name == NULL)) {
7519 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7520 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007521 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007522 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7523 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7524 define->name);
7525 return(0);
7526 }
7527
7528 if (define->nameClass == NULL)
7529 return(1);
7530
7531 define = define->nameClass;
7532 if (define->type == XML_RELAXNG_EXCEPT) {
7533 xmlRelaxNGDefinePtr list;
7534 oldflags = ctxt->flags;
7535 ctxt->flags |= FLAGS_IGNORABLE;
7536
7537 list = define->content;
7538 while (list != NULL) {
7539 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7540 if (ret == 1) {
7541 ctxt->flags = oldflags;
7542 return(0);
7543 }
7544 if (ret < 0) {
7545 ctxt->flags = oldflags;
7546 return(ret);
7547 }
7548 list = list->next;
7549 }
7550 ret = 1;
7551 ctxt->flags = oldflags;
7552 } else if (define->type == XML_RELAXNG_CHOICE) {
7553 xmlRelaxNGDefinePtr list;
7554
7555 oldflags = ctxt->flags;
7556 ctxt->flags |= FLAGS_IGNORABLE;
7557
7558 list = define->nameClass;
7559 while (list != NULL) {
7560 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7561 if (ret == 1) {
7562 ctxt->flags = oldflags;
7563 return(1);
7564 }
7565 if (ret < 0) {
7566 ctxt->flags = oldflags;
7567 return(ret);
7568 }
7569 list = list->next;
7570 }
7571 if (ret != 0) {
7572 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7573 xmlRelaxNGDumpValidError(ctxt);
7574 } else {
7575 ctxt->errNr = 0;
7576 }
7577 ret = 0;
7578 ctxt->flags = oldflags;
7579 } else {
7580 TODO
7581 ret = -1;
7582 }
7583 return(ret);
7584}
7585
7586/**
7587 * xmlRelaxNGValidateElementEnd:
7588 * @ctxt: a Relax-NG validation context
7589 *
7590 * Validate the end of the element, implements check that
7591 * there is nothing left not consumed in the element content
7592 * or in the attribute list.
7593 *
7594 * Returns 0 if the validation succeeded or an error code.
7595 */
7596static int
7597xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
7598 int ret = 0, i;
7599 xmlRelaxNGValidStatePtr state;
7600
7601 state = ctxt->state;
7602 if (state->seq != NULL) {
7603 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
7604 if (state->seq != NULL) {
7605 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
7606 state->node->name, state->seq->name);
7607 ret = -1;
7608 }
7609 }
7610 for (i = 0;i < state->nbAttrs;i++) {
7611 if (state->attrs[i] != NULL) {
7612 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
7613 state->attrs[i]->name, state->node->name);
7614 ret = -1;
7615 }
7616 }
7617 return(ret);
7618}
7619
7620/**
7621 * xmlRelaxNGValidateState:
7622 * @ctxt: a Relax-NG validation context
7623 * @define: the definition to verify
7624 *
7625 * Validate the current state against the definition
7626 *
7627 * Returns 0 if the validation succeeded or an error code.
7628 */
7629static int
7630xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
7631 xmlRelaxNGDefinePtr define) {
7632 xmlNodePtr node;
7633 int ret = 0, i, tmp, oldflags, errNr;
7634 xmlRelaxNGValidStatePtr oldstate, state;
7635
7636 if (define == NULL) {
7637 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
7638 return(-1);
7639 }
7640
7641 if (ctxt->state != NULL) {
7642 node = ctxt->state->seq;
7643 } else {
7644 node = NULL;
7645 }
7646#ifdef DEBUG
7647 for (i = 0;i < ctxt->depth;i++)
7648 xmlGenericError(xmlGenericErrorContext, " ");
7649 xmlGenericError(xmlGenericErrorContext,
7650 "Start validating %s ", xmlRelaxNGDefName(define));
7651 if (define->name != NULL)
7652 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7653 if ((node != NULL) && (node->name != NULL))
7654 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
7655 else
7656 xmlGenericError(xmlGenericErrorContext, "\n");
7657#endif
7658 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007659 switch (define->type) {
7660 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007661 node = xmlRelaxNGSkipIgnored(ctxt, node);
7662 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007663 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007664 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007665 ret = -1;
7666 break;
7667 case XML_RELAXNG_TEXT:
7668 while ((node != NULL) &&
7669 ((node->type == XML_TEXT_NODE) ||
7670 (node->type == XML_COMMENT_NODE) ||
7671 (node->type == XML_PI_NODE) ||
7672 (node->type == XML_CDATA_SECTION_NODE)))
7673 node = node->next;
7674 ctxt->state->seq = node;
7675 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007676 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007677 errNr = ctxt->errNr;
7678 node = xmlRelaxNGSkipIgnored(ctxt, node);
7679 if (node == NULL) {
7680 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
7681 ret = -1;
7682 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7683 xmlRelaxNGDumpValidError(ctxt);
7684 break;
7685 }
7686 if (node->type != XML_ELEMENT_NODE) {
7687 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7688 ret = -1;
7689 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7690 xmlRelaxNGDumpValidError(ctxt);
7691 break;
7692 }
7693 /*
7694 * This node was already validated successfully against
7695 * this definition.
7696 */
7697 if (node->_private == define) {
7698 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7699 break;
7700 }
7701
7702 ret = xmlRelaxNGElementMatch(ctxt, define, node);
7703 if (ret <= 0) {
7704 ret = -1;
7705 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7706 xmlRelaxNGDumpValidError(ctxt);
7707 break;
7708 }
7709 ret = 0;
7710 if (ctxt->errNr != 0) {
7711 while ((ctxt->err != NULL) &&
7712 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
7713 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
7714 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
7715 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
7716 xmlRelaxNGValidErrorPop(ctxt);
7717 }
7718 errNr = ctxt->errNr;
7719
7720 state = xmlRelaxNGNewValidState(ctxt, node);
7721 if (state == NULL) {
7722 ret = -1;
7723 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7724 xmlRelaxNGDumpValidError(ctxt);
7725 break;
7726 }
7727
7728 oldstate = ctxt->state;
7729 ctxt->state = state;
7730 if (define->attrs != NULL) {
7731 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7732 if (tmp != 0) {
7733 ret = -1;
7734 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7735 }
7736 }
7737 if (define->content != NULL) {
7738 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7739 if (tmp != 0) {
7740 ret = -1;
7741 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
7742 }
7743 }
7744 if (ctxt->states != NULL) {
7745 tmp = -1;
7746
7747 oldflags = ctxt->flags;
7748 ctxt->flags |= FLAGS_IGNORABLE;
7749
7750 for (i = 0;i < ctxt->states->nbState;i++) {
7751 state = ctxt->states->tabState[i];
7752 ctxt->state = state;
7753
7754 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7755 tmp = 0;
7756 xmlRelaxNGFreeValidState(state);
7757 }
7758 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7759 ctxt->flags = oldflags;
7760 ctxt->states = NULL;
7761 if ((ret == 0) && (tmp == -1))
7762 ret = -1;
7763 } else {
7764 state = ctxt->state;
7765 if (ret == 0)
7766 ret = xmlRelaxNGValidateElementEnd(ctxt);
7767 xmlRelaxNGFreeValidState(state);
7768 }
7769 ctxt->state = oldstate;
7770 if (oldstate != NULL)
7771 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7772 if (ret == 0) {
7773 node->_private = define;
7774 }
7775 if (ret != 0) {
7776 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7777 xmlRelaxNGDumpValidError(ctxt);
7778 } else {
7779 ctxt->errNr = errNr;
7780 }
7781
7782#ifdef DEBUG
7783 xmlGenericError(xmlGenericErrorContext,
7784 "xmlRelaxNGValidateDefinition(): validated %s : %d",
7785 node->name, ret);
7786 if (oldstate == NULL)
7787 xmlGenericError(xmlGenericErrorContext, ": no state\n");
7788 else if (oldstate->seq == NULL)
7789 xmlGenericError(xmlGenericErrorContext, ": done\n");
7790 else if (oldstate->seq->type == XML_ELEMENT_NODE)
7791 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
7792 oldstate->seq->name);
7793 else
7794 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
7795 oldstate->seq->name, oldstate->seq->type);
7796#endif
7797 break;
7798 case XML_RELAXNG_OPTIONAL: {
7799 oldflags = ctxt->flags;
7800 ctxt->flags |= FLAGS_IGNORABLE;
7801 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7802 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7803 if (ret != 0) {
7804 if (ctxt->state != NULL)
7805 xmlRelaxNGFreeValidState(ctxt->state);
7806 ctxt->state = oldstate;
7807 ctxt->flags = oldflags;
7808 ret = 0;
7809 break;
7810 }
7811 if (ctxt->states != NULL) {
7812 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7813 } else {
7814 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
7815 if (ctxt->states == NULL) {
7816 xmlRelaxNGFreeValidState(oldstate);
7817 ctxt->flags = oldflags;
7818 ret = -1;
7819 break;
7820 }
7821 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7822 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
7823 ctxt->state = NULL;
7824 }
7825 ctxt->flags = oldflags;
7826 ret = 0;
7827 break;
7828 }
7829 case XML_RELAXNG_ONEORMORE:
7830 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7831 if (ret != 0) {
7832 break;
7833 }
7834 /* no break on purpose */
7835 case XML_RELAXNG_ZEROORMORE: {
7836 int progress;
7837 xmlRelaxNGStatesPtr states = NULL, res = NULL;
7838 int base, j;
7839
7840 res = xmlRelaxNGNewStates(ctxt, 1);
7841 if (res == NULL) {
7842 ret = -1;
7843 break;
7844 }
7845 /*
7846 * All the input states are also exit states
7847 */
7848 if (ctxt->state != NULL) {
7849 xmlRelaxNGAddStates(ctxt, res,
7850 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
7851 } else {
7852 for (j = 0;j < ctxt->states->nbState;j++) {
7853 xmlRelaxNGAddStates(ctxt, res,
7854 xmlRelaxNGCopyValidState(ctxt,
7855 ctxt->states->tabState[j]));
7856 }
7857 }
7858 oldflags = ctxt->flags;
7859 ctxt->flags |= FLAGS_IGNORABLE;
7860 do {
7861 progress = 0;
7862 base = res->nbState;
7863
7864 if (ctxt->states != NULL) {
7865 states = ctxt->states;
7866 for (i = 0;i < states->nbState;i++) {
7867 ctxt->state = states->tabState[i];
7868 ctxt->states = NULL;
7869 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7870 define->content);
7871 if (ret == 0) {
7872 if (ctxt->state != NULL) {
7873 tmp = xmlRelaxNGAddStates(ctxt, res,
7874 ctxt->state);
7875 ctxt->state = NULL;
7876 if (tmp == 1)
7877 progress = 1;
7878 } else if (ctxt->states != NULL) {
7879 for (j = 0;j < ctxt->states->nbState;j++) {
7880 tmp = xmlRelaxNGAddStates(ctxt, res,
7881 ctxt->states->tabState[j]);
7882 if (tmp == 1)
7883 progress = 1;
7884 }
7885 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7886 ctxt->states = NULL;
7887 }
7888 } else {
7889 if (ctxt->state != NULL) {
7890 xmlRelaxNGFreeValidState(ctxt->state);
7891 ctxt->state = NULL;
7892 }
7893 }
7894 }
7895 } else {
7896 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7897 define->content);
7898 if (ret != 0) {
7899 xmlRelaxNGFreeValidState(ctxt->state);
7900 ctxt->state = NULL;
7901 } else {
7902 base = res->nbState;
7903 if (ctxt->state != NULL) {
7904 tmp = xmlRelaxNGAddStates(ctxt, res,
7905 ctxt->state);
7906 ctxt->state = NULL;
7907 if (tmp == 1)
7908 progress = 1;
7909 } else if (ctxt->states != NULL) {
7910 for (j = 0;j < ctxt->states->nbState;j++) {
7911 tmp = xmlRelaxNGAddStates(ctxt, res,
7912 ctxt->states->tabState[j]);
7913 if (tmp == 1)
7914 progress = 1;
7915 }
7916 if (states == NULL) {
7917 states = ctxt->states;
7918 } else {
7919 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7920 }
7921 ctxt->states = NULL;
7922 }
7923 }
7924 }
7925 if (progress) {
7926 /*
7927 * Collect all the new nodes added at that step
7928 * and make them the new node set
7929 */
7930 if (res->nbState - base == 1) {
7931 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
7932 res->tabState[base]);
7933 } else {
7934 if (states == NULL) {
7935 xmlRelaxNGNewStates(ctxt, res->nbState - base);
7936 }
7937 states->nbState = 0;
7938 for (i = base;i < res->nbState;i++)
7939 xmlRelaxNGAddStates(ctxt, states,
7940 xmlRelaxNGCopyValidState(ctxt,
7941 res->tabState[i]));
7942 ctxt->states = states;
7943 }
7944 }
7945 } while (progress == 1);
7946 if (states != NULL) {
7947 xmlRelaxNGFreeStates(ctxt, states);
7948 }
7949 ctxt->states = res;
7950 ctxt->flags = oldflags;
7951 ret = 0;
7952 break;
7953 }
7954 case XML_RELAXNG_CHOICE: {
7955 xmlRelaxNGDefinePtr list = define->content;
7956 xmlRelaxNGStatesPtr states = NULL;
7957
7958
7959 oldflags = ctxt->flags;
7960 errNr = ctxt->errNr;
7961 ctxt->flags |= FLAGS_IGNORABLE;
7962 node = xmlRelaxNGSkipIgnored(ctxt, node);
7963
7964 while (list != NULL) {
7965 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7966 ret = xmlRelaxNGValidateDefinition(ctxt, list);
7967 if (ret == 0) {
7968 if (states == NULL) {
7969 states = xmlRelaxNGNewStates(ctxt, 1);
7970 }
7971 if (ctxt->state != NULL) {
7972 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
7973 } else if (ctxt->states != NULL) {
7974 for (i = 0;i < ctxt->states->nbState;i++) {
7975 xmlRelaxNGAddStates(ctxt, states,
7976 ctxt->states->tabState[i]);
7977 }
7978 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7979 ctxt->states = NULL;
7980 }
7981 } else {
7982 xmlRelaxNGFreeValidState(ctxt->state);
7983 }
7984 ctxt->state = oldstate;
7985 list = list->next;
7986 }
7987 if (states != NULL) {
7988 xmlRelaxNGFreeValidState(oldstate);
7989 ctxt->states = states;
7990 ctxt->state = NULL;
7991 ret = 0;
7992 } else {
7993 ctxt->states = NULL;
7994 }
7995 ctxt->flags = oldflags;
7996 if (ret != 0) {
7997 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7998 xmlRelaxNGDumpValidError(ctxt);
7999 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8000 ctxt->errNr = errNr;
8001 }
8002 break;
8003 }
8004 case XML_RELAXNG_DEF:
8005 case XML_RELAXNG_GROUP:
8006 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008007 break;
8008 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008009 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008010 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008011 case XML_RELAXNG_ATTRIBUTE:
8012 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8013 break;
8014 case XML_RELAXNG_NOOP:
8015 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008016 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008017 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8018 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008019 case XML_RELAXNG_PARENTREF:
8020 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8021 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008022 case XML_RELAXNG_DATATYPE: {
8023 xmlNodePtr child;
8024 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008025
Daniel Veillardfd573f12003-03-16 17:52:32 +00008026 child = node;
8027 while (child != NULL) {
8028 if (child->type == XML_ELEMENT_NODE) {
8029 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8030 node->parent->name);
8031 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008032 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008033 } else if ((child->type == XML_TEXT_NODE) ||
8034 (child->type == XML_CDATA_SECTION_NODE)) {
8035 content = xmlStrcat(content, child->content);
8036 }
8037 /* TODO: handle entities ... */
8038 child = child->next;
8039 }
8040 if (ret == -1) {
8041 if (content != NULL)
8042 xmlFree(content);
8043 break;
8044 }
8045 if (content == NULL) {
8046 content = xmlStrdup(BAD_CAST "");
8047 if (content == NULL) {
8048 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8049 ret = -1;
8050 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008051 }
8052 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008053 ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
8054 if (ret == -1) {
8055 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8056 } else if (ret == 0) {
8057 ctxt->state->seq = NULL;
8058 }
8059 if (content != NULL)
8060 xmlFree(content);
8061 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008062 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008063 case XML_RELAXNG_VALUE: {
8064 xmlChar *content = NULL;
8065 xmlChar *oldvalue;
8066 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008067
Daniel Veillardfd573f12003-03-16 17:52:32 +00008068 child = node;
8069 while (child != NULL) {
8070 if (child->type == XML_ELEMENT_NODE) {
8071 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8072 node->parent->name);
8073 ret = -1;
8074 break;
8075 } else if ((child->type == XML_TEXT_NODE) ||
8076 (child->type == XML_CDATA_SECTION_NODE)) {
8077 content = xmlStrcat(content, child->content);
8078 }
8079 /* TODO: handle entities ... */
8080 child = child->next;
8081 }
8082 if (ret == -1) {
8083 if (content != NULL)
8084 xmlFree(content);
8085 break;
8086 }
8087 if (content == NULL) {
8088 content = xmlStrdup(BAD_CAST "");
8089 if (content == NULL) {
8090 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8091 ret = -1;
8092 break;
8093 }
8094 }
8095 oldvalue = ctxt->state->value;
8096 ctxt->state->value = content;
8097 ret = xmlRelaxNGValidateValue(ctxt, define);
8098 ctxt->state->value = oldvalue;
8099 if (ret == -1) {
8100 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8101 } else if (ret == 0) {
8102 ctxt->state->seq = NULL;
8103 }
8104 if (content != NULL)
8105 xmlFree(content);
8106 break;
8107 }
8108 case XML_RELAXNG_LIST: {
8109 xmlChar *content;
8110 xmlNodePtr child;
8111 xmlChar *oldvalue, *oldendvalue;
8112 int len;
8113
8114 /*
8115 * Make sure it's only text nodes
8116 */
8117
8118 content = NULL;
8119 child = node;
8120 while (child != NULL) {
8121 if (child->type == XML_ELEMENT_NODE) {
8122 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8123 node->parent->name);
8124 ret = -1;
8125 break;
8126 } else if ((child->type == XML_TEXT_NODE) ||
8127 (child->type == XML_CDATA_SECTION_NODE)) {
8128 content = xmlStrcat(content, child->content);
8129 }
8130 /* TODO: handle entities ... */
8131 child = child->next;
8132 }
8133 if (ret == -1) {
8134 if (content != NULL)
8135 xmlFree(content);
8136 break;
8137 }
8138 if (content == NULL) {
8139 content = xmlStrdup(BAD_CAST "");
8140 if (content == NULL) {
8141 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8142 ret = -1;
8143 break;
8144 }
8145 }
8146 len = xmlStrlen(content);
8147 oldvalue = ctxt->state->value;
8148 oldendvalue = ctxt->state->endvalue;
8149 ctxt->state->value = content;
8150 ctxt->state->endvalue = content + len;
8151 ret = xmlRelaxNGValidateValue(ctxt, define);
8152 ctxt->state->value = oldvalue;
8153 ctxt->state->endvalue = oldendvalue;
8154 if (ret == -1) {
8155 VALID_ERR(XML_RELAXNG_ERR_LIST);
8156 } else if ((ret == 0) && (node != NULL)) {
8157 ctxt->state->seq = node->next;
8158 }
8159 if (content != NULL)
8160 xmlFree(content);
8161 break;
8162 }
8163 case XML_RELAXNG_START:
8164 case XML_RELAXNG_EXCEPT:
8165 case XML_RELAXNG_PARAM:
8166 TODO
8167 ret = -1;
8168 break;
8169 }
8170 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008171#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008172 for (i = 0;i < ctxt->depth;i++)
8173 xmlGenericError(xmlGenericErrorContext, " ");
8174 xmlGenericError(xmlGenericErrorContext,
8175 "Validating %s ", xmlRelaxNGDefName(define));
8176 if (define->name != NULL)
8177 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8178 if (ret == 0)
8179 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8180 else
8181 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008182#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008183 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008184}
8185
8186/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008187 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008188 * @ctxt: a Relax-NG validation context
8189 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008190 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008191 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008192 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008193 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008194 */
8195static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008196xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8197 xmlRelaxNGDefinePtr define) {
8198 xmlRelaxNGStatesPtr states, res;
8199 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008200
Daniel Veillardfd573f12003-03-16 17:52:32 +00008201 /*
8202 * We should NOT have both ctxt->state and ctxt->states
8203 */
8204 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8205 TODO
8206 xmlRelaxNGFreeValidState(ctxt->state);
8207 ctxt->state = NULL;
8208 }
8209
8210 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8211 if (ctxt->states != NULL) {
8212 ctxt->state = ctxt->states->tabState[0];
8213 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8214 ctxt->states = NULL;
8215 }
8216 ret = xmlRelaxNGValidateState(ctxt, define);
8217 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8218 TODO
8219 xmlRelaxNGFreeValidState(ctxt->state);
8220 ctxt->state = NULL;
8221 }
8222 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8223 ctxt->state = ctxt->states->tabState[0];
8224 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8225 ctxt->states = NULL;
8226 }
8227 return(ret);
8228 }
8229
8230 states = ctxt->states;
8231 ctxt->states = NULL;
8232 res = NULL;
8233 j = 0;
8234 oldflags = ctxt->flags;
8235 ctxt->flags |= FLAGS_IGNORABLE;
8236 for (i = 0;i < states->nbState;i++) {
8237 ctxt->state = states->tabState[i];
8238 ctxt->states = NULL;
8239 ret = xmlRelaxNGValidateState(ctxt, define);
8240 /*
8241 * We should NOT have both ctxt->state and ctxt->states
8242 */
8243 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8244 TODO
8245 xmlRelaxNGFreeValidState(ctxt->state);
8246 ctxt->state = NULL;
8247 }
8248 if (ret == 0) {
8249 if (ctxt->states == NULL) {
8250 if (res != NULL) {
8251 /* add the state to the container */
8252 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8253 ctxt->state = NULL;
8254 } else {
8255 /* add the state directly in states */
8256 states->tabState[j++] = ctxt->state;
8257 ctxt->state = NULL;
8258 }
8259 } else {
8260 if (res == NULL) {
8261 /* make it the new container and copy other results */
8262 res = ctxt->states;
8263 ctxt->states = NULL;
8264 for (k = 0;k < j;k++)
8265 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8266 } else {
8267 /* add all the new results to res and reff the container */
8268 for (k = 0;k < ctxt->states->nbState;k++)
8269 xmlRelaxNGAddStates(ctxt, res,
8270 ctxt->states->tabState[k]);
8271 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8272 ctxt->states = NULL;
8273 }
8274 }
8275 } else {
8276 if (ctxt->state != NULL) {
8277 xmlRelaxNGFreeValidState(ctxt->state);
8278 ctxt->state = NULL;
8279 } else if (ctxt->states != NULL) {
8280 for (k = 0;k < ctxt->states->nbState;k++)
8281 xmlRelaxNGFreeValidState(ctxt->states->tabState[k]);
8282 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8283 ctxt->states = NULL;
8284 }
8285 }
8286 }
8287 ctxt->flags = oldflags;
8288 if (res != NULL) {
8289 xmlRelaxNGFreeStates(ctxt, states);
8290 ctxt->states = res;
8291 ret = 0;
8292 } else if (j > 1) {
8293 states->nbState = j;
8294 ctxt->states = states;
8295 ret =0;
8296 } else if (j == 1) {
8297 ctxt->state = states->tabState[0];
8298 xmlRelaxNGFreeStates(ctxt, states);
8299 ret = 0;
8300 } else {
8301 ret = -1;
8302 xmlRelaxNGFreeStates(ctxt, states);
8303 if (ctxt->states != NULL) {
8304 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8305 ctxt->states = NULL;
8306 }
8307 }
8308 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8309 TODO
8310 xmlRelaxNGFreeValidState(ctxt->state);
8311 ctxt->state = NULL;
8312 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008313 return(ret);
8314}
8315
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008316/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008317 * xmlRelaxNGValidateDocument:
8318 * @ctxt: a Relax-NG validation context
8319 * @doc: the document
8320 *
8321 * Validate the given document
8322 *
8323 * Returns 0 if the validation succeeded or an error code.
8324 */
8325static int
8326xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8327 int ret;
8328 xmlRelaxNGPtr schema;
8329 xmlRelaxNGGrammarPtr grammar;
8330 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008331 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008332
8333 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8334 return(-1);
8335
8336 schema = ctxt->schema;
8337 grammar = schema->topgrammar;
8338 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008339 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008340 return(-1);
8341 }
8342 state = xmlRelaxNGNewValidState(ctxt, NULL);
8343 ctxt->state = state;
8344 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008345 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8346 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008347 node = state->seq;
8348 node = xmlRelaxNGSkipIgnored(ctxt, node);
8349 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008350 if (ret != -1) {
8351 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8352 ret = -1;
8353 }
8354 }
8355 } else if (ctxt->states != NULL) {
8356 int i;
8357 int tmp = -1;
8358
8359 for (i = 0;i < ctxt->states->nbState;i++) {
8360 state = ctxt->states->tabState[i];
8361 node = state->seq;
8362 node = xmlRelaxNGSkipIgnored(ctxt, node);
8363 if (node == NULL)
8364 tmp = 0;
8365 xmlRelaxNGFreeValidState(state);
8366 }
8367 if (tmp == -1) {
8368 if (ret != -1) {
8369 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8370 ret = -1;
8371 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008372 }
8373 }
8374 xmlRelaxNGFreeValidState(state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008375 if (ret != 0)
8376 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008377
8378 return(ret);
8379}
8380
Daniel Veillardfd573f12003-03-16 17:52:32 +00008381/************************************************************************
8382 * *
8383 * Validation interfaces *
8384 * *
8385 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008386/**
8387 * xmlRelaxNGNewValidCtxt:
8388 * @schema: a precompiled XML RelaxNGs
8389 *
8390 * Create an XML RelaxNGs validation context based on the given schema
8391 *
8392 * Returns the validation context or NULL in case of error
8393 */
8394xmlRelaxNGValidCtxtPtr
8395xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8396 xmlRelaxNGValidCtxtPtr ret;
8397
8398 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8399 if (ret == NULL) {
8400 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008401 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008402 return (NULL);
8403 }
8404 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8405 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008406 ret->error = xmlGenericError;
8407 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008408 ret->errNr = 0;
8409 ret->errMax = 0;
8410 ret->err = NULL;
8411 ret->errTab = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008412 return (ret);
8413}
8414
8415/**
8416 * xmlRelaxNGFreeValidCtxt:
8417 * @ctxt: the schema validation context
8418 *
8419 * Free the resources associated to the schema validation context
8420 */
8421void
8422xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
8423 if (ctxt == NULL)
8424 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008425 if (ctxt->states != NULL)
8426 xmlRelaxNGFreeStates(ctxt, ctxt->states);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008427 if (ctxt->errTab != NULL)
8428 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008429 xmlFree(ctxt);
8430}
8431
8432/**
8433 * xmlRelaxNGSetValidErrors:
8434 * @ctxt: a Relax-NG validation context
8435 * @err: the error function
8436 * @warn: the warning function
8437 * @ctx: the functions context
8438 *
8439 * Set the error and warning callback informations
8440 */
8441void
8442xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8443 xmlRelaxNGValidityErrorFunc err,
8444 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8445 if (ctxt == NULL)
8446 return;
8447 ctxt->error = err;
8448 ctxt->warning = warn;
8449 ctxt->userData = ctx;
8450}
8451
8452/**
8453 * xmlRelaxNGValidateDoc:
8454 * @ctxt: a Relax-NG validation context
8455 * @doc: a parsed document tree
8456 *
8457 * Validate a document tree in memory.
8458 *
8459 * Returns 0 if the document is valid, a positive error code
8460 * number otherwise and -1 in case of internal or API error.
8461 */
8462int
8463xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8464 int ret;
8465
8466 if ((ctxt == NULL) || (doc == NULL))
8467 return(-1);
8468
8469 ctxt->doc = doc;
8470
8471 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008472 /*
8473 * TODO: build error codes
8474 */
8475 if (ret == -1)
8476 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008477 return(ret);
8478}
8479
8480#endif /* LIBXML_SCHEMAS_ENABLED */
8481