blob: 0fd8b40c400c69cc53a9a869fd8842770dd465f8 [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 {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000157 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000158 xmlRelaxNGGrammarPtr topgrammar;
159 xmlDocPtr doc;
160
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000161 int idref; /* requires idref checking */
162
Daniel Veillard6eadf632003-01-23 18:29:16 +0000163 xmlHashTablePtr defs; /* define */
164 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000165 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
166 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000167 int defNr; /* number of defines used */
168 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000169
Daniel Veillard6eadf632003-01-23 18:29:16 +0000170};
171
Daniel Veillard77648bb2003-02-20 15:03:22 +0000172#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
173#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
174#define XML_RELAXNG_IN_LIST (1 << 2)
175#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
176#define XML_RELAXNG_IN_START (1 << 4)
177#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
178#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
179#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000180#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
181#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000182
183struct _xmlRelaxNGParserCtxt {
184 void *userData; /* user specific data block */
185 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
186 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000187 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000188
189 xmlRelaxNGPtr schema; /* The schema in use */
190 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000191 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000192 int flags; /* parser flags */
193 int nbErrors; /* number of errors at parse time */
194 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000195 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000196 xmlRelaxNGDefinePtr def; /* the current define */
197
198 int nbInterleaves;
199 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200
Daniel Veillardc482e262003-02-26 14:48:48 +0000201 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
202 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000203 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000204 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000205
Daniel Veillard419a7682003-02-03 23:22:49 +0000206 int defNr; /* number of defines used */
207 int defMax; /* number of defines aloocated */
208 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
209
Daniel Veillard6eadf632003-01-23 18:29:16 +0000210 const char *buffer;
211 int size;
212
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000213 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000214 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000215 int docNr; /* Depth of the parsing stack */
216 int docMax; /* Max depth of the parsing stack */
217 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000218
219 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000220 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000221 int incNr; /* Depth of the include parsing stack */
222 int incMax; /* Max depth of the parsing stack */
223 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000224
225 int idref; /* requires idref checking */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000226};
227
228#define FLAGS_IGNORABLE 1
229#define FLAGS_NEGATIVE 2
230
231/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000232 * xmlRelaxNGInterleaveGroup:
233 *
234 * A RelaxNGs partition set associated to lists of definitions
235 */
236typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
237typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
238struct _xmlRelaxNGInterleaveGroup {
239 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
240 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000241 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000242};
243
244/**
245 * xmlRelaxNGPartitions:
246 *
247 * A RelaxNGs partition associated to an interleave group
248 */
249typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
250typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
251struct _xmlRelaxNGPartition {
252 int nbgroups; /* number of groups in the partitions */
253 xmlRelaxNGInterleaveGroupPtr *groups;
254};
255
256/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000257 * xmlRelaxNGValidState:
258 *
259 * A RelaxNGs validation state
260 */
261#define MAX_ATTR 20
262typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
263typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
264struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000265 xmlNodePtr node; /* the current node */
266 xmlNodePtr seq; /* the sequence of children left to validate */
267 int nbAttrs; /* the number of attributes */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000268 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000269 xmlChar *value; /* the value when operating on string */
270 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000271 xmlAttrPtr attrs[1]; /* the array of attributes */
272};
273
274/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000275 * xmlRelaxNGStates:
276 *
277 * A RelaxNGs container for validation state
278 */
279typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
280typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
281struct _xmlRelaxNGStates {
282 int nbState; /* the number of states */
283 int maxState; /* the size of the array */
284 xmlRelaxNGValidStatePtr *tabState;
285};
286
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000287#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000288/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000289 * xmlRelaxNGValidError:
290 *
291 * A RelaxNGs validation error
292 */
293typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
294typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
295struct _xmlRelaxNGValidError {
296 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000297 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000298 xmlNodePtr node; /* the current node */
299 xmlNodePtr seq; /* the current child */
300 const xmlChar * arg1; /* first arg */
301 const xmlChar * arg2; /* second arg */
302};
303
304/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000305 * xmlRelaxNGValidCtxt:
306 *
307 * A RelaxNGs validation context
308 */
309
310struct _xmlRelaxNGValidCtxt {
311 void *userData; /* user specific data block */
312 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
313 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
314
315 xmlRelaxNGPtr schema; /* The schema in use */
316 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000317 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000318 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000319 int idref; /* requires idref checking */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000320
321 /*
322 * Errors accumulated in branches may have to be stacked to be
323 * provided back when it's sure they affect validation.
324 */
325 xmlRelaxNGValidErrorPtr err; /* Last error */
326 int errNr; /* Depth of the error stack */
327 int errMax; /* Max depth of the error stack */
328 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000329
Daniel Veillardfd573f12003-03-16 17:52:32 +0000330 xmlRelaxNGValidStatePtr state; /* the current validation state */
331 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000332};
333
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000334/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000335 * xmlRelaxNGInclude:
336 *
337 * Structure associated to a RelaxNGs document element
338 */
339struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000340 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000341 xmlChar *href; /* the normalized href value */
342 xmlDocPtr doc; /* the associated XML document */
343 xmlRelaxNGDefinePtr content;/* the definitions */
344 xmlRelaxNGPtr schema; /* the schema */
345};
346
347/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000348 * xmlRelaxNGDocument:
349 *
350 * Structure associated to a RelaxNGs document element
351 */
352struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000353 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000354 xmlChar *href; /* the normalized href value */
355 xmlDocPtr doc; /* the associated XML document */
356 xmlRelaxNGDefinePtr content;/* the definitions */
357 xmlRelaxNGPtr schema; /* the schema */
358};
359
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000360
Daniel Veillard6eadf632003-01-23 18:29:16 +0000361/************************************************************************
362 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000363 * Preliminary type checking interfaces *
364 * *
365 ************************************************************************/
366/**
367 * xmlRelaxNGTypeHave:
368 * @data: data needed for the library
369 * @type: the type name
370 * @value: the value to check
371 *
372 * Function provided by a type library to check if a type is exported
373 *
374 * Returns 1 if yes, 0 if no and -1 in case of error.
375 */
376typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
377
378/**
379 * xmlRelaxNGTypeCheck:
380 * @data: data needed for the library
381 * @type: the type name
382 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000383 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000384 *
385 * Function provided by a type library to check if a value match a type
386 *
387 * Returns 1 if yes, 0 if no and -1 in case of error.
388 */
389typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000390 const xmlChar *value, void **result,
391 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000392
393/**
394 * xmlRelaxNGFacetCheck:
395 * @data: data needed for the library
396 * @type: the type name
397 * @facet: the facet name
398 * @val: the facet value
399 * @strval: the string value
400 * @value: the value to check
401 *
402 * Function provided by a type library to check a value facet
403 *
404 * Returns 1 if yes, 0 if no and -1 in case of error.
405 */
406typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
407 const xmlChar *facet, const xmlChar *val,
408 const xmlChar *strval, void *value);
409
410/**
411 * xmlRelaxNGTypeFree:
412 * @data: data needed for the library
413 * @result: the value to free
414 *
415 * Function provided by a type library to free a returned result
416 */
417typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000418
419/**
420 * xmlRelaxNGTypeCompare:
421 * @data: data needed for the library
422 * @type: the type name
423 * @value1: the first value
424 * @value2: the second value
425 *
426 * Function provided by a type library to compare two values accordingly
427 * to a type.
428 *
429 * Returns 1 if yes, 0 if no and -1 in case of error.
430 */
431typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
432 const xmlChar *value1,
433 const xmlChar *value2);
434typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
435typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
436struct _xmlRelaxNGTypeLibrary {
437 const xmlChar *namespace; /* the datatypeLibrary value */
438 void *data; /* data needed for the library */
439 xmlRelaxNGTypeHave have; /* the export function */
440 xmlRelaxNGTypeCheck check; /* the checking function */
441 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000442 xmlRelaxNGFacetCheck facet; /* the facet check function */
443 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000444};
445
446/************************************************************************
447 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000448 * Allocation functions *
449 * *
450 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000451static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
452static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000453static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000454static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000455static int xmlRelaxNGEqualValidState(
456 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
457 xmlRelaxNGValidStatePtr state1,
458 xmlRelaxNGValidStatePtr state2);
459static void xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000460
461/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000462 * xmlRelaxNGFreeDocument:
463 * @docu: a document structure
464 *
465 * Deallocate a RelaxNG document structure.
466 */
467static void
468xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
469{
470 if (docu == NULL)
471 return;
472
473 if (docu->href != NULL)
474 xmlFree(docu->href);
475 if (docu->doc != NULL)
476 xmlFreeDoc(docu->doc);
477 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000478 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000479 xmlFree(docu);
480}
481
482/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000483 * xmlRelaxNGFreeDocumentList:
484 * @docu: a list of document structure
485 *
486 * Deallocate a RelaxNG document structures.
487 */
488static void
489xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
490{
491 xmlRelaxNGDocumentPtr next;
492 while (docu != NULL) {
493 next = docu->next;
494 xmlRelaxNGFreeDocument(docu);
495 docu = next;
496 }
497}
498
499/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000500 * xmlRelaxNGFreeInclude:
501 * @incl: a include structure
502 *
503 * Deallocate a RelaxNG include structure.
504 */
505static void
506xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
507{
508 if (incl == NULL)
509 return;
510
511 if (incl->href != NULL)
512 xmlFree(incl->href);
513 if (incl->doc != NULL)
514 xmlFreeDoc(incl->doc);
515 if (incl->schema != NULL)
516 xmlRelaxNGFree(incl->schema);
517 xmlFree(incl);
518}
519
520/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000521 * xmlRelaxNGFreeIncludeList:
522 * @incl: a include structure list
523 *
524 * Deallocate a RelaxNG include structure.
525 */
526static void
527xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
528{
529 xmlRelaxNGIncludePtr next;
530 while (incl != NULL) {
531 next = incl->next;
532 xmlRelaxNGFreeInclude(incl);
533 incl = next;
534 }
535}
536
537/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000538 * xmlRelaxNGNewRelaxNG:
539 * @ctxt: a Relax-NG validation context (optional)
540 *
541 * Allocate a new RelaxNG structure.
542 *
543 * Returns the newly allocated structure or NULL in case or error
544 */
545static xmlRelaxNGPtr
546xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
547{
548 xmlRelaxNGPtr ret;
549
550 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
551 if (ret == NULL) {
552 if ((ctxt != NULL) && (ctxt->error != NULL))
553 ctxt->error(ctxt->userData, "Out of memory\n");
554 ctxt->nbErrors++;
555 return (NULL);
556 }
557 memset(ret, 0, sizeof(xmlRelaxNG));
558
559 return (ret);
560}
561
562/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000563 * xmlRelaxNGFreeInnerSchema:
564 * @schema: a schema structure
565 *
566 * Deallocate a RelaxNG schema structure.
567 */
568static void
569xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
570{
571 if (schema == NULL)
572 return;
573
574 if (schema->doc != NULL)
575 xmlFreeDoc(schema->doc);
576 if (schema->defTab != NULL) {
577 int i;
578
579 for (i = 0;i < schema->defNr;i++)
580 xmlRelaxNGFreeDefine(schema->defTab[i]);
581 xmlFree(schema->defTab);
582 }
583
584 xmlFree(schema);
585}
586
587/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000588 * xmlRelaxNGFree:
589 * @schema: a schema structure
590 *
591 * Deallocate a RelaxNG structure.
592 */
593void
594xmlRelaxNGFree(xmlRelaxNGPtr schema)
595{
596 if (schema == NULL)
597 return;
598
Daniel Veillard6eadf632003-01-23 18:29:16 +0000599 if (schema->topgrammar != NULL)
600 xmlRelaxNGFreeGrammar(schema->topgrammar);
601 if (schema->doc != NULL)
602 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000603 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000604 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000605 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000606 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000607 if (schema->defTab != NULL) {
608 int i;
609
610 for (i = 0;i < schema->defNr;i++)
611 xmlRelaxNGFreeDefine(schema->defTab[i]);
612 xmlFree(schema->defTab);
613 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000614
615 xmlFree(schema);
616}
617
618/**
619 * xmlRelaxNGNewGrammar:
620 * @ctxt: a Relax-NG validation context (optional)
621 *
622 * Allocate a new RelaxNG grammar.
623 *
624 * Returns the newly allocated structure or NULL in case or error
625 */
626static xmlRelaxNGGrammarPtr
627xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
628{
629 xmlRelaxNGGrammarPtr ret;
630
631 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
632 if (ret == NULL) {
633 if ((ctxt != NULL) && (ctxt->error != NULL))
634 ctxt->error(ctxt->userData, "Out of memory\n");
635 ctxt->nbErrors++;
636 return (NULL);
637 }
638 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
639
640 return (ret);
641}
642
643/**
644 * xmlRelaxNGFreeGrammar:
645 * @grammar: a grammar structure
646 *
647 * Deallocate a RelaxNG grammar structure.
648 */
649static void
650xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
651{
652 if (grammar == NULL)
653 return;
654
Daniel Veillardc482e262003-02-26 14:48:48 +0000655 if (grammar->children != NULL) {
656 xmlRelaxNGFreeGrammar(grammar->children);
657 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000658 if (grammar->next != NULL) {
659 xmlRelaxNGFreeGrammar(grammar->next);
660 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000661 if (grammar->refs != NULL) {
662 xmlHashFree(grammar->refs, NULL);
663 }
664 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000665 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000666 }
667
668 xmlFree(grammar);
669}
670
671/**
672 * xmlRelaxNGNewDefine:
673 * @ctxt: a Relax-NG validation context
674 * @node: the node in the input document.
675 *
676 * Allocate a new RelaxNG define.
677 *
678 * Returns the newly allocated structure or NULL in case or error
679 */
680static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000681xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000682{
683 xmlRelaxNGDefinePtr ret;
684
Daniel Veillard419a7682003-02-03 23:22:49 +0000685 if (ctxt->defMax == 0) {
686 ctxt->defMax = 16;
687 ctxt->defNr = 0;
688 ctxt->defTab = (xmlRelaxNGDefinePtr *)
689 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
690 if (ctxt->defTab == NULL) {
691 if ((ctxt != NULL) && (ctxt->error != NULL))
692 ctxt->error(ctxt->userData, "Out of memory\n");
693 ctxt->nbErrors++;
694 return (NULL);
695 }
696 } else if (ctxt->defMax <= ctxt->defNr) {
697 xmlRelaxNGDefinePtr *tmp;
698 ctxt->defMax *= 2;
699 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
700 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
701 if (tmp == NULL) {
702 if ((ctxt != NULL) && (ctxt->error != NULL))
703 ctxt->error(ctxt->userData, "Out of memory\n");
704 ctxt->nbErrors++;
705 return (NULL);
706 }
707 ctxt->defTab = tmp;
708 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000709 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
710 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000711 if ((ctxt != NULL) && (ctxt->error != NULL))
712 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000713 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000714 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000715 }
716 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000717 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000718 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000719 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000720 return (ret);
721}
722
723/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000724 * xmlRelaxNGFreePartition:
725 * @partitions: a partition set structure
726 *
727 * Deallocate RelaxNG partition set structures.
728 */
729static void
730xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
731 xmlRelaxNGInterleaveGroupPtr group;
732 int j;
733
734 if (partitions != NULL) {
735 if (partitions->groups != NULL) {
736 for (j = 0;j < partitions->nbgroups;j++) {
737 group = partitions->groups[j];
738 if (group != NULL) {
739 if (group->defs != NULL)
740 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000741 if (group->attrs != NULL)
742 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000743 xmlFree(group);
744 }
745 }
746 xmlFree(partitions->groups);
747 }
748 xmlFree(partitions);
749 }
750}
751/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000752 * xmlRelaxNGFreeDefine:
753 * @define: a define structure
754 *
755 * Deallocate a RelaxNG define structure.
756 */
757static void
758xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
759{
760 if (define == NULL)
761 return;
762
Daniel Veillard419a7682003-02-03 23:22:49 +0000763 if ((define->data != NULL) &&
764 (define->type == XML_RELAXNG_INTERLEAVE))
765 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000766 if (define->name != NULL)
767 xmlFree(define->name);
768 if (define->ns != NULL)
769 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000770 if (define->value != NULL)
771 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000772 xmlFree(define);
773}
774
775/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000776 * xmlRelaxNGNewStates:
777 * @ctxt: a Relax-NG validation context
778 * @size: the default size for the container
779 *
780 * Allocate a new RelaxNG validation state container
781 * TODO: keep a pool in the ctxt
782 *
783 * Returns the newly allocated structure or NULL in case or error
784 */
785static xmlRelaxNGStatesPtr
786xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
787{
788 xmlRelaxNGStatesPtr ret;
789
790 if (size < 16) size = 16;
791
792 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
793 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
794 if (ret == NULL) {
795 if ((ctxt != NULL) && (ctxt->error != NULL))
796 ctxt->error(ctxt->userData, "Out of memory\n");
797 return (NULL);
798 }
799 ret->nbState = 0;
800 ret->maxState = size;
801 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
802 (size) * sizeof(xmlRelaxNGValidStatePtr));
803 if (ret->tabState == NULL) {
804 if ((ctxt != NULL) && (ctxt->error != NULL))
805 ctxt->error(ctxt->userData, "Out of memory\n");
806 xmlFree(ret->tabState);
807 return (NULL);
808 }
809 return(ret);
810}
811
812/**
813 * xmlRelaxNGAddState:
814 * @ctxt: a Relax-NG validation context
815 * @states: the states container
816 * @state: the validation state
817 *
818 * Add a RelaxNG validation state to the container
819 *
820 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
821 */
822static int
823xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
824 xmlRelaxNGValidStatePtr state)
825{
826 int i;
827
828 if (state == NULL) {
829 return(-1);
830 }
831 if (states->nbState >= states->maxState) {
832 xmlRelaxNGValidStatePtr *tmp;
833 int size;
834
835 size = states->maxState * 2;
836 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
837 (size) * sizeof(xmlRelaxNGValidStatePtr));
838 if (tmp == NULL) {
839 if ((ctxt != NULL) && (ctxt->error != NULL))
840 ctxt->error(ctxt->userData, "Out of memory\n");
841 return(-1);
842 }
843 states->tabState = tmp;
844 states->maxState = size;
845 }
846 for (i = 0;i < states->nbState;i++) {
847 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
848 xmlRelaxNGFreeValidState(state);
849 return(0);
850 }
851 }
852 states->tabState[states->nbState++] = state;
853 return(1);
854}
855
856/**
857 * xmlRelaxNGFreeStates:
858 * @ctxt: a Relax-NG validation context
859 * @states: teh container
860 *
861 * Free a RelaxNG validation state container
862 * TODO: keep a pool in the ctxt
863 */
864static void
865xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
866 xmlRelaxNGStatesPtr states)
867{
868 if (states != NULL) {
869 xmlFree(states->tabState);
870 xmlFree(states);
871 }
872}
873
874/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000875 * xmlRelaxNGNewValidState:
876 * @ctxt: a Relax-NG validation context
877 * @node: the current node or NULL for the document
878 *
879 * Allocate a new RelaxNG validation state
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000880 * TODO: keep a pool in the ctxt
Daniel Veillard6eadf632003-01-23 18:29:16 +0000881 *
882 * Returns the newly allocated structure or NULL in case or error
883 */
884static xmlRelaxNGValidStatePtr
885xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
886{
887 xmlRelaxNGValidStatePtr ret;
888 xmlAttrPtr attr;
889 xmlAttrPtr attrs[MAX_ATTR];
890 int nbAttrs = 0;
891 xmlNodePtr root = NULL;
892
893 if (node == NULL) {
894 root = xmlDocGetRootElement(ctxt->doc);
895 if (root == NULL)
896 return(NULL);
897 } else {
898 attr = node->properties;
899 while (attr != NULL) {
900 if (nbAttrs < MAX_ATTR)
901 attrs[nbAttrs++] = attr;
902 else
903 nbAttrs++;
904 attr = attr->next;
905 }
906 }
907
908 if (nbAttrs < MAX_ATTR)
909 attrs[nbAttrs] = NULL;
910 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
911 nbAttrs * sizeof(xmlAttrPtr));
912 if (ret == NULL) {
913 if ((ctxt != NULL) && (ctxt->error != NULL))
914 ctxt->error(ctxt->userData, "Out of memory\n");
915 return (NULL);
916 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +0000917 ret->value = NULL;
918 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000919 if (node == NULL) {
920 ret->node = (xmlNodePtr) ctxt->doc;
921 ret->seq = root;
922 ret->nbAttrs = 0;
923 } else {
924 ret->node = node;
925 ret->seq = node->children;
926 ret->nbAttrs = nbAttrs;
927 if (nbAttrs > 0) {
928 if (nbAttrs < MAX_ATTR) {
929 memcpy(&(ret->attrs[0]), attrs,
930 sizeof(xmlAttrPtr) * (nbAttrs + 1));
931 } else {
932 attr = node->properties;
933 nbAttrs = 0;
934 while (attr != NULL) {
935 ret->attrs[nbAttrs++] = attr;
936 attr = attr->next;
937 }
938 ret->attrs[nbAttrs] = NULL;
939 }
940 }
941 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000942 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000943 return (ret);
944}
945
946/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000947 * xmlRelaxNGCopyValidState:
948 * @ctxt: a Relax-NG validation context
949 * @state: a validation state
950 *
951 * Copy the validation state
952 *
953 * Returns the newly allocated structure or NULL in case or error
954 */
955static xmlRelaxNGValidStatePtr
956xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
957 xmlRelaxNGValidStatePtr state)
958{
959 xmlRelaxNGValidStatePtr ret;
960 unsigned int size;
961
962 if (state == NULL)
963 return(NULL);
964
965 size = sizeof(xmlRelaxNGValidState) +
966 state->nbAttrs * sizeof(xmlAttrPtr);
967 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size);
968 if (ret == NULL) {
969 if ((ctxt != NULL) && (ctxt->error != NULL))
970 ctxt->error(ctxt->userData, "Out of memory\n");
971 return (NULL);
972 }
973 memcpy(ret, state, size);
974 return(ret);
975}
976
977/**
978 * xmlRelaxNGEqualValidState:
979 * @ctxt: a Relax-NG validation context
980 * @state1: a validation state
981 * @state2: a validation state
982 *
983 * Compare the validation states for equality
984 *
985 * Returns 1 if equald, 0 otherwise
986 */
987static int
988xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
989 xmlRelaxNGValidStatePtr state1,
990 xmlRelaxNGValidStatePtr state2)
991{
992 int i;
993
994 if ((state1 == NULL) || (state2 == NULL))
995 return(0);
996 if (state1 == state2)
997 return(1);
998 if (state1->node != state2->node)
999 return(0);
1000 if (state1->seq != state2->seq)
1001 return(0);
1002 if (state1->nbAttrLeft != state2->nbAttrLeft)
1003 return(0);
1004 if (state1->nbAttrs != state2->nbAttrs)
1005 return(0);
1006 if (state1->endvalue != state2->endvalue)
1007 return(0);
1008 if ((state1->value != state2->value) &&
1009 (!xmlStrEqual(state1->value, state2->value)))
1010 return(0);
1011 for (i = 0;i < state1->nbAttrs;i++) {
1012 if (state1->attrs[i] != state2->attrs[i])
1013 return(0);
1014 }
1015 return(1);
1016}
1017
1018/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001019 * xmlRelaxNGFreeValidState:
1020 * @state: a validation state structure
1021 *
1022 * Deallocate a RelaxNG validation state structure.
Daniel Veillardfd573f12003-03-16 17:52:32 +00001023 * TODO: keep a pool in the ctxt
Daniel Veillard6eadf632003-01-23 18:29:16 +00001024 */
1025static void
1026xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
1027{
1028 if (state == NULL)
1029 return;
1030
1031 xmlFree(state);
1032}
1033
1034/************************************************************************
1035 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001036 * Document functions *
1037 * *
1038 ************************************************************************/
1039static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1040 xmlDocPtr doc);
1041
1042/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001043 * xmlRelaxNGIncludePush:
1044 * @ctxt: the parser context
1045 * @value: the element doc
1046 *
1047 * Pushes a new include on top of the include stack
1048 *
1049 * Returns 0 in case of error, the index in the stack otherwise
1050 */
1051static int
1052xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1053 xmlRelaxNGIncludePtr value)
1054{
1055 if (ctxt->incTab == NULL) {
1056 ctxt->incMax = 4;
1057 ctxt->incNr = 0;
1058 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1059 ctxt->incMax * sizeof(ctxt->incTab[0]));
1060 if (ctxt->incTab == NULL) {
1061 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1062 return (0);
1063 }
1064 }
1065 if (ctxt->incNr >= ctxt->incMax) {
1066 ctxt->incMax *= 2;
1067 ctxt->incTab =
1068 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1069 ctxt->incMax *
1070 sizeof(ctxt->incTab[0]));
1071 if (ctxt->incTab == NULL) {
1072 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1073 return (0);
1074 }
1075 }
1076 ctxt->incTab[ctxt->incNr] = value;
1077 ctxt->inc = value;
1078 return (ctxt->incNr++);
1079}
1080
1081/**
1082 * xmlRelaxNGIncludePop:
1083 * @ctxt: the parser context
1084 *
1085 * Pops the top include from the include stack
1086 *
1087 * Returns the include just removed
1088 */
1089static xmlRelaxNGIncludePtr
1090xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1091{
1092 xmlRelaxNGIncludePtr ret;
1093
1094 if (ctxt->incNr <= 0)
1095 return (0);
1096 ctxt->incNr--;
1097 if (ctxt->incNr > 0)
1098 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1099 else
1100 ctxt->inc = NULL;
1101 ret = ctxt->incTab[ctxt->incNr];
1102 ctxt->incTab[ctxt->incNr] = 0;
1103 return (ret);
1104}
1105
1106/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001107 * xmlRelaxNGRemoveRedefine:
1108 * @ctxt: the parser context
1109 * @URL: the normalized URL
1110 * @target: the included target
1111 * @name: the define name to eliminate
1112 *
1113 * Applies the elimination algorithm of 4.7
1114 *
1115 * Returns 0 in case of error, 1 in case of success.
1116 */
1117static int
1118xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1119 const xmlChar *URL ATTRIBUTE_UNUSED,
1120 xmlNodePtr target, const xmlChar *name) {
1121 int found = 0;
1122 xmlNodePtr tmp, tmp2;
1123 xmlChar *name2;
1124
1125#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001126 if (name == NULL)
1127 xmlGenericError(xmlGenericErrorContext,
1128 "Elimination of <include> start from %s\n", URL);
1129 else
1130 xmlGenericError(xmlGenericErrorContext,
1131 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001132#endif
1133 tmp = target;
1134 while (tmp != NULL) {
1135 tmp2 = tmp->next;
1136 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1137 found = 1;
1138 xmlUnlinkNode(tmp);
1139 xmlFreeNode(tmp);
1140 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1141 name2 = xmlGetProp(tmp, BAD_CAST "name");
1142 xmlRelaxNGNormExtSpace(name2);
1143 if (name2 != NULL) {
1144 if (xmlStrEqual(name, name2)) {
1145 found = 1;
1146 xmlUnlinkNode(tmp);
1147 xmlFreeNode(tmp);
1148 }
1149 xmlFree(name2);
1150 }
1151 } else if (IS_RELAXNG(tmp, "include")) {
1152 xmlChar *href = NULL;
1153 xmlRelaxNGDocumentPtr inc = tmp->_private;
1154
1155 if ((inc != NULL) && (inc->doc != NULL) &&
1156 (inc->doc->children != NULL)) {
1157
1158 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1159#ifdef DEBUG_INCLUDE
1160 href = xmlGetProp(tmp, BAD_CAST "href");
1161#endif
1162 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1163 inc->doc->children->children, name) == 1) {
1164 found = 1;
1165 }
1166 if (href != NULL)
1167 xmlFree(href);
1168 }
1169 }
1170 }
1171 tmp = tmp2;
1172 }
1173 return(found);
1174}
1175
1176/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001177 * xmlRelaxNGLoadInclude:
1178 * @ctxt: the parser context
1179 * @URL: the normalized URL
1180 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001181 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001182 *
1183 * First lookup if the document is already loaded into the parser context,
1184 * check against recursion. If not found the resource is loaded and
1185 * the content is preprocessed before being returned back to the caller.
1186 *
1187 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1188 */
1189static xmlRelaxNGIncludePtr
1190xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001191 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001192 xmlRelaxNGIncludePtr ret = NULL;
1193 xmlDocPtr doc;
1194 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001195 xmlNodePtr root, cur;
1196
1197#ifdef DEBUG_INCLUDE
1198 xmlGenericError(xmlGenericErrorContext,
1199 "xmlRelaxNGLoadInclude(%s)\n", URL);
1200#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001201
1202 /*
1203 * check against recursion in the stack
1204 */
1205 for (i = 0;i < ctxt->incNr;i++) {
1206 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1207 if (ctxt->error != NULL)
1208 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001209 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001210 URL);
1211 ctxt->nbErrors++;
1212 return(NULL);
1213 }
1214 }
1215
1216 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001217 * load the document
1218 */
1219 doc = xmlParseFile((const char *) URL);
1220 if (doc == NULL) {
1221 if (ctxt->error != NULL)
1222 ctxt->error(ctxt->userData,
1223 "xmlRelaxNG: could not load %s\n", URL);
1224 ctxt->nbErrors++;
1225 return (NULL);
1226 }
1227
Daniel Veillard5add8682003-03-10 13:13:58 +00001228#ifdef DEBUG_INCLUDE
1229 xmlGenericError(xmlGenericErrorContext,
1230 "Parsed %s Okay\n", URL);
1231#endif
1232
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001233 /*
1234 * Allocate the document structures and register it first.
1235 */
1236 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1237 if (ret == NULL) {
1238 if (ctxt->error != NULL)
1239 ctxt->error(ctxt->userData,
1240 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1241 ctxt->nbErrors++;
1242 xmlFreeDoc(doc);
1243 return (NULL);
1244 }
1245 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1246 ret->doc = doc;
1247 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001248 ret->next = ctxt->includes;
1249 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001250
1251 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001252 * transmit the ns if needed
1253 */
1254 if (ns != NULL) {
1255 root = xmlDocGetRootElement(doc);
1256 if (root != NULL) {
1257 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1258 xmlSetProp(root, BAD_CAST"ns", ns);
1259 }
1260 }
1261 }
1262
1263 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001264 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001265 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001266 xmlRelaxNGIncludePush(ctxt, ret);
1267
1268 /*
1269 * Some preprocessing of the document content, this include recursing
1270 * in the include stack.
1271 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001272#ifdef DEBUG_INCLUDE
1273 xmlGenericError(xmlGenericErrorContext,
1274 "cleanup of %s\n", URL);
1275#endif
1276
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001277 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1278 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001279 ctxt->inc = NULL;
1280 return(NULL);
1281 }
1282
1283 /*
1284 * Pop up the include from the stack
1285 */
1286 xmlRelaxNGIncludePop(ctxt);
1287
Daniel Veillard5add8682003-03-10 13:13:58 +00001288#ifdef DEBUG_INCLUDE
1289 xmlGenericError(xmlGenericErrorContext,
1290 "Checking of %s\n", URL);
1291#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001292 /*
1293 * Check that the top element is a grammar
1294 */
1295 root = xmlDocGetRootElement(doc);
1296 if (root == NULL) {
1297 if (ctxt->error != NULL)
1298 ctxt->error(ctxt->userData,
1299 "xmlRelaxNG: included document is empty %s\n", URL);
1300 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001301 return (NULL);
1302 }
1303 if (!IS_RELAXNG(root, "grammar")) {
1304 if (ctxt->error != NULL)
1305 ctxt->error(ctxt->userData,
1306 "xmlRelaxNG: included document %s root is not a grammar\n",
1307 URL);
1308 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001309 return (NULL);
1310 }
1311
1312 /*
1313 * Elimination of redefined rules in the include.
1314 */
1315 cur = node->children;
1316 while (cur != NULL) {
1317 if (IS_RELAXNG(cur, "start")) {
1318 int found = 0;
1319
Daniel Veillard5add8682003-03-10 13:13:58 +00001320 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001321 if (!found) {
1322 if (ctxt->error != NULL)
1323 ctxt->error(ctxt->userData,
1324 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1325 URL);
1326 ctxt->nbErrors++;
1327 }
1328 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001329 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001330
1331 name = xmlGetProp(cur, BAD_CAST "name");
1332 if (name == NULL) {
1333 if (ctxt->error != NULL)
1334 ctxt->error(ctxt->userData,
1335 "xmlRelaxNG: include %s has define without name\n",
1336 URL);
1337 ctxt->nbErrors++;
1338 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001339 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001340
Daniel Veillardd2298792003-02-14 16:54:11 +00001341 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001342 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1343 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001344 if (!found) {
1345 if (ctxt->error != NULL)
1346 ctxt->error(ctxt->userData,
1347 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1348 URL, name);
1349 ctxt->nbErrors++;
1350 }
1351 xmlFree(name);
1352 }
1353 }
1354 cur = cur->next;
1355 }
1356
1357
1358 return(ret);
1359}
1360
1361/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001362 * xmlRelaxNGValidErrorPush:
1363 * @ctxt: the validation context
1364 * @err: the error code
1365 * @arg1: the first string argument
1366 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001367 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001368 *
1369 * Pushes a new error on top of the error stack
1370 *
1371 * Returns 0 in case of error, the index in the stack otherwise
1372 */
1373static int
1374xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001375 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001376{
1377 xmlRelaxNGValidErrorPtr cur;
1378 if (ctxt->errTab == NULL) {
1379 ctxt->errMax = 8;
1380 ctxt->errNr = 0;
1381 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1382 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1383 if (ctxt->errTab == NULL) {
1384 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1385 return (0);
1386 }
1387 }
1388 if (ctxt->errNr >= ctxt->errMax) {
1389 ctxt->errMax *= 2;
1390 ctxt->errTab =
1391 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1392 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1393 if (ctxt->errTab == NULL) {
1394 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1395 return (0);
1396 }
1397 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001398 if ((ctxt->err != NULL) &&
1399 (ctxt->err->node == ctxt->state->node) &&
1400 (ctxt->err->err == err))
1401 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001402 cur = &ctxt->errTab[ctxt->errNr];
1403 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001404 if (dup) {
1405 cur->arg1 = xmlStrdup(arg1);
1406 cur->arg2 = xmlStrdup(arg2);
1407 cur->flags = ERROR_IS_DUP;
1408 } else {
1409 cur->arg1 = arg1;
1410 cur->arg2 = arg2;
1411 cur->flags = 0;
1412 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001413 if (ctxt->state != NULL) {
1414 cur->node = ctxt->state->node;
1415 cur->seq = ctxt->state->seq;
1416 } else {
1417 cur->node = NULL;
1418 cur->seq = NULL;
1419 }
1420 ctxt->err = cur;
1421 return (ctxt->errNr++);
1422}
1423
1424/**
1425 * xmlRelaxNGValidErrorPop:
1426 * @ctxt: the validation context
1427 *
1428 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001429 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001430static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001431xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1432{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001433 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001434
1435 if (ctxt->errNr <= 0)
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001436 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001437 ctxt->errNr--;
1438 if (ctxt->errNr > 0)
1439 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1440 else
1441 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001442 cur = &ctxt->errTab[ctxt->errNr];
1443 if (cur->flags & ERROR_IS_DUP) {
1444 xmlFree((xmlChar *)cur->arg1);
1445 cur->arg1 = NULL;
1446 xmlFree((xmlChar *)cur->arg2);
1447 cur->arg2 = NULL;
1448 cur->flags = 0;
1449 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001450}
1451
Daniel Veillard42f12e92003-03-07 18:32:59 +00001452/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001453 * xmlRelaxNGDocumentPush:
1454 * @ctxt: the parser context
1455 * @value: the element doc
1456 *
1457 * Pushes a new doc on top of the doc stack
1458 *
1459 * Returns 0 in case of error, the index in the stack otherwise
1460 */
1461static int
1462xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1463 xmlRelaxNGDocumentPtr value)
1464{
1465 if (ctxt->docTab == NULL) {
1466 ctxt->docMax = 4;
1467 ctxt->docNr = 0;
1468 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1469 ctxt->docMax * sizeof(ctxt->docTab[0]));
1470 if (ctxt->docTab == NULL) {
1471 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1472 return (0);
1473 }
1474 }
1475 if (ctxt->docNr >= ctxt->docMax) {
1476 ctxt->docMax *= 2;
1477 ctxt->docTab =
1478 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1479 ctxt->docMax *
1480 sizeof(ctxt->docTab[0]));
1481 if (ctxt->docTab == NULL) {
1482 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1483 return (0);
1484 }
1485 }
1486 ctxt->docTab[ctxt->docNr] = value;
1487 ctxt->doc = value;
1488 return (ctxt->docNr++);
1489}
1490
1491/**
1492 * xmlRelaxNGDocumentPop:
1493 * @ctxt: the parser context
1494 *
1495 * Pops the top doc from the doc stack
1496 *
1497 * Returns the doc just removed
1498 */
1499static xmlRelaxNGDocumentPtr
1500xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1501{
1502 xmlRelaxNGDocumentPtr ret;
1503
1504 if (ctxt->docNr <= 0)
1505 return (0);
1506 ctxt->docNr--;
1507 if (ctxt->docNr > 0)
1508 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1509 else
1510 ctxt->doc = NULL;
1511 ret = ctxt->docTab[ctxt->docNr];
1512 ctxt->docTab[ctxt->docNr] = 0;
1513 return (ret);
1514}
1515
1516/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001517 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001518 * @ctxt: the parser context
1519 * @URL: the normalized URL
1520 * @ns: the inherited ns if any
1521 *
1522 * First lookup if the document is already loaded into the parser context,
1523 * check against recursion. If not found the resource is loaded and
1524 * the content is preprocessed before being returned back to the caller.
1525 *
1526 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1527 */
1528static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001529xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001530 const xmlChar *ns) {
1531 xmlRelaxNGDocumentPtr ret = NULL;
1532 xmlDocPtr doc;
1533 xmlNodePtr root;
1534 int i;
1535
1536 /*
1537 * check against recursion in the stack
1538 */
1539 for (i = 0;i < ctxt->docNr;i++) {
1540 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1541 if (ctxt->error != NULL)
1542 ctxt->error(ctxt->userData,
1543 "Detected an externalRef recursion for %s\n",
1544 URL);
1545 ctxt->nbErrors++;
1546 return(NULL);
1547 }
1548 }
1549
1550 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001551 * load the document
1552 */
1553 doc = xmlParseFile((const char *) URL);
1554 if (doc == NULL) {
1555 if (ctxt->error != NULL)
1556 ctxt->error(ctxt->userData,
1557 "xmlRelaxNG: could not load %s\n", URL);
1558 ctxt->nbErrors++;
1559 return (NULL);
1560 }
1561
1562 /*
1563 * Allocate the document structures and register it first.
1564 */
1565 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1566 if (ret == NULL) {
1567 if (ctxt->error != NULL)
1568 ctxt->error(ctxt->userData,
1569 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1570 ctxt->nbErrors++;
1571 xmlFreeDoc(doc);
1572 return (NULL);
1573 }
1574 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1575 ret->doc = doc;
1576 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001577 ret->next = ctxt->documents;
1578 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001579
1580 /*
1581 * transmit the ns if needed
1582 */
1583 if (ns != NULL) {
1584 root = xmlDocGetRootElement(doc);
1585 if (root != NULL) {
1586 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1587 xmlSetProp(root, BAD_CAST"ns", ns);
1588 }
1589 }
1590 }
1591
1592 /*
1593 * push it on the stack and register it in the hash table
1594 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001595 xmlRelaxNGDocumentPush(ctxt, ret);
1596
1597 /*
1598 * Some preprocessing of the document content
1599 */
1600 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1601 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001602 ctxt->doc = NULL;
1603 return(NULL);
1604 }
1605
1606 xmlRelaxNGDocumentPop(ctxt);
1607
1608 return(ret);
1609}
1610
1611/************************************************************************
1612 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001613 * Error functions *
1614 * *
1615 ************************************************************************/
1616
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001617#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1618#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1619#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1620#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1621#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001622
Daniel Veillardfd573f12003-03-16 17:52:32 +00001623#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001624static const char *
1625xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1626 if (def == NULL)
1627 return("none");
1628 switch(def->type) {
1629 case XML_RELAXNG_EMPTY: return("empty");
1630 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1631 case XML_RELAXNG_EXCEPT: return("except");
1632 case XML_RELAXNG_TEXT: return("text");
1633 case XML_RELAXNG_ELEMENT: return("element");
1634 case XML_RELAXNG_DATATYPE: return("datatype");
1635 case XML_RELAXNG_VALUE: return("value");
1636 case XML_RELAXNG_LIST: return("list");
1637 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1638 case XML_RELAXNG_DEF: return("def");
1639 case XML_RELAXNG_REF: return("ref");
1640 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1641 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001642 case XML_RELAXNG_OPTIONAL: return("optional");
1643 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001644 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1645 case XML_RELAXNG_CHOICE: return("choice");
1646 case XML_RELAXNG_GROUP: return("group");
1647 case XML_RELAXNG_INTERLEAVE: return("interleave");
1648 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001649 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001650 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001651 }
1652 return("unknown");
1653}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001654#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001655
Daniel Veillard6eadf632003-01-23 18:29:16 +00001656/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001657 * xmlRelaxNGGetErrorString:
1658 * @err: the error code
1659 * @arg1: the first string argument
1660 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001661 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001662 * computes a formatted error string for the given error code and args
1663 *
1664 * Returns the error string, it must be deallocated by the caller
1665 */
1666static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001667xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1668 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001669 char msg[1000];
1670
1671 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001672 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001673 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001674 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001675
1676 msg[0] = 0;
1677 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001678 case XML_RELAXNG_OK:
1679 return(NULL);
1680 case XML_RELAXNG_ERR_MEMORY:
1681 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001682 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001683 snprintf(msg, 1000, "failed to validate type %s", arg1);
1684 break;
1685 case XML_RELAXNG_ERR_TYPEVAL:
1686 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1687 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001688 case XML_RELAXNG_ERR_DUPID:
1689 snprintf(msg, 1000, "ID %s redefined", arg1);
1690 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001691 case XML_RELAXNG_ERR_TYPECMP:
1692 snprintf(msg, 1000, "failed to compare type %s", arg1);
1693 break;
1694 case XML_RELAXNG_ERR_NOSTATE:
1695 return(xmlCharStrdup("Internal error: no state"));
1696 case XML_RELAXNG_ERR_NODEFINE:
1697 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001698 case XML_RELAXNG_ERR_INTERNAL:
1699 snprintf(msg, 1000, "Internal error: %s", arg1);
1700 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001701 case XML_RELAXNG_ERR_LISTEXTRA:
1702 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1703 break;
1704 case XML_RELAXNG_ERR_INTERNODATA:
1705 return(xmlCharStrdup("Internal: interleave block has no data"));
1706 case XML_RELAXNG_ERR_INTERSEQ:
1707 return(xmlCharStrdup("Invalid sequence in interleave"));
1708 case XML_RELAXNG_ERR_INTEREXTRA:
1709 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1710 break;
1711 case XML_RELAXNG_ERR_ELEMNAME:
1712 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1713 break;
1714 case XML_RELAXNG_ERR_ELEMNONS:
1715 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1716 break;
1717 case XML_RELAXNG_ERR_ELEMWRONGNS:
1718 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1719 arg1, arg2);
1720 break;
1721 case XML_RELAXNG_ERR_ELEMEXTRANS:
1722 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1723 break;
1724 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1725 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1726 break;
1727 case XML_RELAXNG_ERR_NOELEM:
1728 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1729 break;
1730 case XML_RELAXNG_ERR_NOTELEM:
1731 return(xmlCharStrdup("Expecting an element got text"));
1732 case XML_RELAXNG_ERR_ATTRVALID:
1733 snprintf(msg, 1000, "Element %s failed to validate attributes",
1734 arg1);
1735 break;
1736 case XML_RELAXNG_ERR_CONTENTVALID:
1737 snprintf(msg, 1000, "Element %s failed to validate content",
1738 arg1);
1739 break;
1740 case XML_RELAXNG_ERR_EXTRACONTENT:
1741 snprintf(msg, 1000, "Element %s has extra content: %s",
1742 arg1, arg2);
1743 break;
1744 case XML_RELAXNG_ERR_INVALIDATTR:
1745 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1746 arg1, arg2);
1747 break;
1748 case XML_RELAXNG_ERR_DATAELEM:
1749 snprintf(msg, 1000, "Datatype element %s has child elements",
1750 arg1);
1751 break;
1752 case XML_RELAXNG_ERR_VALELEM:
1753 snprintf(msg, 1000, "Value element %s has child elements",
1754 arg1);
1755 break;
1756 case XML_RELAXNG_ERR_LISTELEM:
1757 snprintf(msg, 1000, "List element %s has child elements",
1758 arg1);
1759 break;
1760 case XML_RELAXNG_ERR_DATATYPE:
1761 snprintf(msg, 1000, "Error validating datatype %s",
1762 arg1);
1763 break;
1764 case XML_RELAXNG_ERR_VALUE:
1765 snprintf(msg, 1000, "Error validating value %s",
1766 arg1);
1767 break;
1768 case XML_RELAXNG_ERR_LIST:
1769 return(xmlCharStrdup("Error validating list"));
1770 case XML_RELAXNG_ERR_NOGRAMMAR:
1771 return(xmlCharStrdup("No top grammar defined"));
1772 case XML_RELAXNG_ERR_EXTRADATA:
1773 return(xmlCharStrdup("Extra data in the document"));
1774 default:
1775 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001776 }
1777 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001778 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001779 }
1780 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001781 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001782}
1783
1784/**
1785 * xmlRelaxNGValidErrorContext:
1786 * @ctxt: the validation context
1787 * @node: the node
1788 * @child: the node child generating the problem.
1789 *
1790 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001791 */
1792static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001793xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1794 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001795{
1796 int line = 0;
1797 const xmlChar *file = NULL;
1798 const xmlChar *name = NULL;
1799 const char *type = "error";
1800
1801 if ((ctxt == NULL) || (ctxt->error == NULL))
1802 return;
1803
1804 if (child != NULL)
1805 node = child;
1806
1807 if (node != NULL) {
1808 if ((node->type == XML_DOCUMENT_NODE) ||
1809 (node->type == XML_HTML_DOCUMENT_NODE)) {
1810 xmlDocPtr doc = (xmlDocPtr) node;
1811
1812 file = doc->URL;
1813 } else {
1814 /*
1815 * Try to find contextual informations to report
1816 */
1817 if (node->type == XML_ELEMENT_NODE) {
1818 line = (int) node->content;
1819 } else if ((node->prev != NULL) &&
1820 (node->prev->type == XML_ELEMENT_NODE)) {
1821 line = (int) node->prev->content;
1822 } else if ((node->parent != NULL) &&
1823 (node->parent->type == XML_ELEMENT_NODE)) {
1824 line = (int) node->parent->content;
1825 }
1826 if ((node->doc != NULL) && (node->doc->URL != NULL))
1827 file = node->doc->URL;
1828 if (node->name != NULL)
1829 name = node->name;
1830 }
1831 }
1832
Daniel Veillard42f12e92003-03-07 18:32:59 +00001833 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001834
1835 if ((file != NULL) && (line != 0) && (name != NULL))
1836 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1837 type, file, line, name);
1838 else if ((file != NULL) && (name != NULL))
1839 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1840 type, file, name);
1841 else if ((file != NULL) && (line != 0))
1842 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1843 else if (file != NULL)
1844 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1845 else if (name != NULL)
1846 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1847 else
1848 ctxt->error(ctxt->userData, "%s\n", type);
1849}
Daniel Veillard42f12e92003-03-07 18:32:59 +00001850
1851/**
1852 * xmlRelaxNGShowValidError:
1853 * @ctxt: the validation context
1854 * @err: the error number
1855 * @node: the node
1856 * @child: the node child generating the problem.
1857 * @arg1: the first argument
1858 * @arg2: the second argument
1859 *
1860 * Show a validation error.
1861 */
1862static void
1863xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1864 xmlNodePtr node, xmlNodePtr child,
1865 const xmlChar *arg1, const xmlChar *arg2)
1866{
1867 xmlChar *msg;
1868
1869 if (ctxt->error == NULL)
1870 return;
1871
1872 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
1873 if (msg == NULL)
1874 return;
1875
1876 xmlRelaxNGValidErrorContext(ctxt, node, child);
1877 ctxt->error(ctxt->userData, "%s\n", msg);
1878 xmlFree(msg);
1879}
1880
1881/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00001882 * xmlRelaxNGPopErrors:
1883 * @ctxt: the validation context
1884 * @level: the error level in the stack
1885 *
1886 * pop and discard all errors until the given level is reached
1887 */
1888static void
1889xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
1890 int i;
1891 xmlRelaxNGValidErrorPtr err;
1892
1893 for (i = level;i < ctxt->errNr;i++) {
1894 err = &ctxt->errTab[i];
1895 if (err->flags & ERROR_IS_DUP) {
1896 if (err->arg1 != NULL)
1897 xmlFree((xmlChar *)err->arg1);
1898 err->arg1 = NULL;
1899 if (err->arg2 != NULL)
1900 xmlFree((xmlChar *)err->arg2);
1901 err->arg2 = NULL;
1902 err->flags = 0;
1903 }
1904 }
1905 ctxt->errNr = level;
1906}
1907/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001908 * xmlRelaxNGDumpValidError:
1909 * @ctxt: the validation context
1910 *
1911 * Show all validation error over a given index.
1912 */
1913static void
1914xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
1915 int i;
1916 xmlRelaxNGValidErrorPtr err;
1917
1918 for (i = 0;i < ctxt->errNr;i++) {
1919 err = &ctxt->errTab[i];
1920 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
1921 err->arg1, err->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001922 if (err->flags & ERROR_IS_DUP) {
1923 if (err->arg1 != NULL)
1924 xmlFree((xmlChar *)err->arg1);
1925 err->arg1 = NULL;
1926 if (err->arg2 != NULL)
1927 xmlFree((xmlChar *)err->arg2);
1928 err->arg2 = NULL;
1929 err->flags = 0;
1930 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001931 }
1932 ctxt->errNr = 0;
1933}
1934/**
1935 * xmlRelaxNGAddValidError:
1936 * @ctxt: the validation context
1937 * @err: the error number
1938 * @arg1: the first argument
1939 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001940 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00001941 *
1942 * Register a validation error, either generating it if it's sure
1943 * or stacking it for later handling if unsure.
1944 */
1945static void
1946xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001947 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001948{
1949 if ((ctxt == NULL) || (ctxt->error == NULL))
1950 return;
1951
1952 /*
1953 * generate the error directly
1954 */
1955 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
1956 xmlNodePtr node, seq;
1957 /*
1958 * Flush first any stacked error which might be the
1959 * real cause of the problem.
1960 */
1961 if (ctxt->errNr != 0)
1962 xmlRelaxNGDumpValidError(ctxt);
1963 if (ctxt->state != NULL) {
1964 node = ctxt->state->node;
1965 seq = ctxt->state->seq;
1966 } else {
1967 node = seq = NULL;
1968 }
1969 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
1970 }
1971 /*
1972 * Stack the error for later processing if needed
1973 */
1974 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001975 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001976 }
1977}
1978
Daniel Veillard6eadf632003-01-23 18:29:16 +00001979
1980/************************************************************************
1981 * *
1982 * Type library hooks *
1983 * *
1984 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00001985static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1986 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001987
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001988/**
1989 * xmlRelaxNGSchemaTypeHave:
1990 * @data: data needed for the library
1991 * @type: the type name
1992 *
1993 * Check if the given type is provided by
1994 * the W3C XMLSchema Datatype library.
1995 *
1996 * Returns 1 if yes, 0 if no and -1 in case of error.
1997 */
1998static int
1999xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002000 const xmlChar *type) {
2001 xmlSchemaTypePtr typ;
2002
2003 if (type == NULL)
2004 return(-1);
2005 typ = xmlSchemaGetPredefinedType(type,
2006 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2007 if (typ == NULL)
2008 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002009 return(1);
2010}
2011
2012/**
2013 * xmlRelaxNGSchemaTypeCheck:
2014 * @data: data needed for the library
2015 * @type: the type name
2016 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002017 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002018 *
2019 * Check if the given type and value are validated by
2020 * the W3C XMLSchema Datatype library.
2021 *
2022 * Returns 1 if yes, 0 if no and -1 in case of error.
2023 */
2024static int
2025xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002026 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002027 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002028 void **result,
2029 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002030 xmlSchemaTypePtr typ;
2031 int ret;
2032
2033 /*
2034 * TODO: the type should be cached ab provided back, interface subject
2035 * to changes.
2036 * TODO: handle facets, may require an additional interface and keep
2037 * the value returned from the validation.
2038 */
2039 if ((type == NULL) || (value == NULL))
2040 return(-1);
2041 typ = xmlSchemaGetPredefinedType(type,
2042 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2043 if (typ == NULL)
2044 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002045 ret = xmlSchemaValPredefTypeNode(typ, value,
2046 (xmlSchemaValPtr *) result, node);
2047 if (ret == 2) /* special ID error code */
2048 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002049 if (ret == 0)
2050 return(1);
2051 if (ret > 0)
2052 return(0);
2053 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002054}
2055
2056/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002057 * xmlRelaxNGSchemaFacetCheck:
2058 * @data: data needed for the library
2059 * @type: the type name
2060 * @facet: the facet name
2061 * @val: the facet value
2062 * @strval: the string value
2063 * @value: the value to check
2064 *
2065 * Function provided by a type library to check a value facet
2066 *
2067 * Returns 1 if yes, 0 if no and -1 in case of error.
2068 */
2069static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002070xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002071 const xmlChar *facetname, const xmlChar *val,
2072 const xmlChar *strval, void *value) {
2073 xmlSchemaFacetPtr facet;
2074 xmlSchemaTypePtr typ;
2075 int ret;
2076
2077 if ((type == NULL) || (strval == NULL))
2078 return(-1);
2079 typ = xmlSchemaGetPredefinedType(type,
2080 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2081 if (typ == NULL)
2082 return(-1);
2083
2084 facet = xmlSchemaNewFacet();
2085 if (facet == NULL)
2086 return(-1);
2087
2088 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2089 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2090 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2091 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2092 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2093 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2094 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2095 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2096 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2097 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2098 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2099 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2100 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2101 facet->type = XML_SCHEMA_FACET_PATTERN;
2102 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2103 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2104 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2105 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2106 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2107 facet->type = XML_SCHEMA_FACET_LENGTH;
2108 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2109 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2110 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2111 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2112 } else {
2113 xmlSchemaFreeFacet(facet);
2114 return(-1);
2115 }
2116 facet->value = xmlStrdup(val);
2117 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2118 if (ret != 0) {
2119 xmlSchemaFreeFacet(facet);
2120 return(-1);
2121 }
2122 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2123 xmlSchemaFreeFacet(facet);
2124 if (ret != 0)
2125 return(-1);
2126 return(0);
2127}
2128
2129/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002130 * xmlRelaxNGSchemaTypeCompare:
2131 * @data: data needed for the library
2132 * @type: the type name
2133 * @value1: the first value
2134 * @value2: the second value
2135 *
2136 * Compare two values accordingly a type from the W3C XMLSchema
2137 * Datatype library.
2138 *
2139 * Returns 1 if yes, 0 if no and -1 in case of error.
2140 */
2141static int
2142xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2143 const xmlChar *type ATTRIBUTE_UNUSED,
2144 const xmlChar *value1 ATTRIBUTE_UNUSED,
2145 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2146 TODO
2147 return(1);
2148}
2149
2150/**
2151 * xmlRelaxNGDefaultTypeHave:
2152 * @data: data needed for the library
2153 * @type: the type name
2154 *
2155 * Check if the given type is provided by
2156 * the default datatype library.
2157 *
2158 * Returns 1 if yes, 0 if no and -1 in case of error.
2159 */
2160static int
2161xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2162 if (type == NULL)
2163 return(-1);
2164 if (xmlStrEqual(type, BAD_CAST "string"))
2165 return(1);
2166 if (xmlStrEqual(type, BAD_CAST "token"))
2167 return(1);
2168 return(0);
2169}
2170
2171/**
2172 * xmlRelaxNGDefaultTypeCheck:
2173 * @data: data needed for the library
2174 * @type: the type name
2175 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002176 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002177 *
2178 * Check if the given type and value are validated by
2179 * the default datatype library.
2180 *
2181 * Returns 1 if yes, 0 if no and -1 in case of error.
2182 */
2183static int
2184xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2185 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002186 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002187 void **result ATTRIBUTE_UNUSED,
2188 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002189 if (value == NULL)
2190 return(-1);
2191 if (xmlStrEqual(type, BAD_CAST "string"))
2192 return(1);
2193 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002194 return(1);
2195 }
2196
2197 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002198}
2199
2200/**
2201 * xmlRelaxNGDefaultTypeCompare:
2202 * @data: data needed for the library
2203 * @type: the type name
2204 * @value1: the first value
2205 * @value2: the second value
2206 *
2207 * Compare two values accordingly a type from the default
2208 * datatype library.
2209 *
2210 * Returns 1 if yes, 0 if no and -1 in case of error.
2211 */
2212static int
2213xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2214 const xmlChar *type ATTRIBUTE_UNUSED,
2215 const xmlChar *value1 ATTRIBUTE_UNUSED,
2216 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002217 int ret = -1;
2218
2219 if (xmlStrEqual(type, BAD_CAST "string")) {
2220 ret = xmlStrEqual(value1, value2);
2221 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2222 if (!xmlStrEqual(value1, value2)) {
2223 xmlChar *nval, *nvalue;
2224
2225 /*
2226 * TODO: trivial optimizations are possible by
2227 * computing at compile-time
2228 */
2229 nval = xmlRelaxNGNormalize(NULL, value1);
2230 nvalue = xmlRelaxNGNormalize(NULL, value2);
2231
Daniel Veillardd4310742003-02-18 21:12:46 +00002232 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002233 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002234 else if (xmlStrEqual(nval, nvalue))
2235 ret = 1;
2236 else
2237 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002238 if (nval != NULL)
2239 xmlFree(nval);
2240 if (nvalue != NULL)
2241 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002242 } else
2243 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002244 }
2245 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002246}
2247
2248static int xmlRelaxNGTypeInitialized = 0;
2249static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2250
2251/**
2252 * xmlRelaxNGFreeTypeLibrary:
2253 * @lib: the type library structure
2254 * @namespace: the URI bound to the library
2255 *
2256 * Free the structure associated to the type library
2257 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002258static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002259xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2260 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2261 if (lib == NULL)
2262 return;
2263 if (lib->namespace != NULL)
2264 xmlFree((xmlChar *)lib->namespace);
2265 xmlFree(lib);
2266}
2267
2268/**
2269 * xmlRelaxNGRegisterTypeLibrary:
2270 * @namespace: the URI bound to the library
2271 * @data: data associated to the library
2272 * @have: the provide function
2273 * @check: the checking function
2274 * @comp: the comparison function
2275 *
2276 * Register a new type library
2277 *
2278 * Returns 0 in case of success and -1 in case of error.
2279 */
2280static int
2281xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2282 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002283 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2284 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002285 xmlRelaxNGTypeLibraryPtr lib;
2286 int ret;
2287
2288 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2289 (check == NULL) || (comp == NULL))
2290 return(-1);
2291 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2292 xmlGenericError(xmlGenericErrorContext,
2293 "Relax-NG types library '%s' already registered\n",
2294 namespace);
2295 return(-1);
2296 }
2297 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2298 if (lib == NULL) {
2299 xmlGenericError(xmlGenericErrorContext,
2300 "Relax-NG types library '%s' malloc() failed\n",
2301 namespace);
2302 return (-1);
2303 }
2304 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2305 lib->namespace = xmlStrdup(namespace);
2306 lib->data = data;
2307 lib->have = have;
2308 lib->comp = comp;
2309 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002310 lib->facet = facet;
2311 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002312 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2313 if (ret < 0) {
2314 xmlGenericError(xmlGenericErrorContext,
2315 "Relax-NG types library failed to register '%s'\n",
2316 namespace);
2317 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2318 return(-1);
2319 }
2320 return(0);
2321}
2322
2323/**
2324 * xmlRelaxNGInitTypes:
2325 *
2326 * Initilize the default type libraries.
2327 *
2328 * Returns 0 in case of success and -1 in case of error.
2329 */
2330static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002331xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002332 if (xmlRelaxNGTypeInitialized != 0)
2333 return(0);
2334 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2335 if (xmlRelaxNGRegisteredTypes == NULL) {
2336 xmlGenericError(xmlGenericErrorContext,
2337 "Failed to allocate sh table for Relax-NG types\n");
2338 return(-1);
2339 }
2340 xmlRelaxNGRegisterTypeLibrary(
2341 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2342 NULL,
2343 xmlRelaxNGSchemaTypeHave,
2344 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002345 xmlRelaxNGSchemaTypeCompare,
2346 xmlRelaxNGSchemaFacetCheck,
2347 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002348 xmlRelaxNGRegisterTypeLibrary(
2349 xmlRelaxNGNs,
2350 NULL,
2351 xmlRelaxNGDefaultTypeHave,
2352 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002353 xmlRelaxNGDefaultTypeCompare,
2354 NULL,
2355 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002356 xmlRelaxNGTypeInitialized = 1;
2357 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002358}
2359
2360/**
2361 * xmlRelaxNGCleanupTypes:
2362 *
2363 * Cleanup the default Schemas type library associated to RelaxNG
2364 */
2365void
2366xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002367 if (xmlRelaxNGTypeInitialized == 0)
2368 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002369 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002370 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2371 xmlRelaxNGFreeTypeLibrary);
2372 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002373}
2374
2375/************************************************************************
2376 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002377 * Compiling element content into regexp *
2378 * *
2379 * Sometime the element content can be compiled into a pure regexp, *
2380 * This allows a faster execution and streamability at that level *
2381 * *
2382 ************************************************************************/
2383
2384/**
2385 * xmlRelaxNGIsCompileable:
2386 * @define: the definition to check
2387 *
2388 * Check if a definition is nullable.
2389 *
2390 * Returns 1 if yes, 0 if no and -1 in case of error
2391 */
2392static int
2393xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2394 if (def == NULL) {
2395 return(-1);
2396 }
2397 switch(def->type) {
2398 case XML_RELAXNG_REF:
2399 case XML_RELAXNG_EXTERNALREF:
2400 case XML_RELAXNG_PARENTREF:
2401 case XML_RELAXNG_NOOP:
2402 case XML_RELAXNG_START:
2403 return(xmlRelaxNGIsCompileable(def->content));
2404 case XML_RELAXNG_TEXT:
2405 case XML_RELAXNG_DATATYPE:
2406 case XML_RELAXNG_LIST:
2407 case XML_RELAXNG_PARAM:
2408 case XML_RELAXNG_VALUE:
2409
2410 case XML_RELAXNG_EMPTY:
2411 case XML_RELAXNG_ELEMENT:
2412 return(1);
2413 case XML_RELAXNG_OPTIONAL:
2414 case XML_RELAXNG_ZEROORMORE:
2415 case XML_RELAXNG_ONEORMORE:
2416 case XML_RELAXNG_CHOICE:
2417 case XML_RELAXNG_GROUP:
2418 case XML_RELAXNG_DEF: {
2419 xmlRelaxNGDefinePtr list;
2420 int ret;
2421
2422 list = def->content;
2423 while (list != NULL) {
2424 ret = xmlRelaxNGIsCompileable(list);
2425 if (ret != 1)
2426 return(ret);
2427 list = list->next;
2428 }
2429 return(1);
2430 }
2431 case XML_RELAXNG_EXCEPT:
2432 case XML_RELAXNG_ATTRIBUTE:
2433 case XML_RELAXNG_INTERLEAVE:
2434 return(0);
2435 case XML_RELAXNG_NOT_ALLOWED:
2436 return(-1);
2437 }
2438 return(-1);
2439}
2440
2441/************************************************************************
2442 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002443 * Parsing functions *
2444 * *
2445 ************************************************************************/
2446
2447static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2448 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2449static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2450 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2451static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002452 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002453static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2454 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002455static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2456 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002457static int xmlRelaxNGParseGrammarContent(
2458 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002459static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2460 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2461 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002462static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2463 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002464static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2465 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002466
2467
2468#define IS_BLANK_NODE(n) \
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002469 ((((n)->type == XML_TEXT_NODE) || \
2470 ((n)->type == XML_CDATA_SECTION_NODE)) && \
2471 (xmlRelaxNGIsBlank((n)->content)))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002472
2473/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002474 * xmlRelaxNGIsNullable:
2475 * @define: the definition to verify
2476 *
2477 * Check if a definition is nullable.
2478 *
2479 * Returns 1 if yes, 0 if no and -1 in case of error
2480 */
2481static int
2482xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2483 int ret;
2484 if (define == NULL)
2485 return(-1);
2486
2487 if (define->flags & IS_NULLABLE)
2488 return(1);
2489 if (define->flags & IS_NOT_NULLABLE)
2490 return(0);
2491 switch (define->type) {
2492 case XML_RELAXNG_EMPTY:
2493 case XML_RELAXNG_TEXT:
2494 ret = 1; break;
2495 case XML_RELAXNG_NOOP:
2496 case XML_RELAXNG_DEF:
2497 case XML_RELAXNG_REF:
2498 case XML_RELAXNG_EXTERNALREF:
2499 case XML_RELAXNG_PARENTREF:
2500 case XML_RELAXNG_ONEORMORE:
2501 ret = xmlRelaxNGIsNullable(define->content);
2502 break;
2503 case XML_RELAXNG_EXCEPT:
2504 case XML_RELAXNG_NOT_ALLOWED:
2505 case XML_RELAXNG_ELEMENT:
2506 case XML_RELAXNG_DATATYPE:
2507 case XML_RELAXNG_PARAM:
2508 case XML_RELAXNG_VALUE:
2509 case XML_RELAXNG_LIST:
2510 case XML_RELAXNG_ATTRIBUTE:
2511 ret = 0; break;
2512 case XML_RELAXNG_CHOICE: {
2513 xmlRelaxNGDefinePtr list = define->content;
2514
2515 while (list != NULL) {
2516 ret = xmlRelaxNGIsNullable(list);
2517 if (ret != 0)
2518 goto done;
2519 list = list->next;
2520 }
2521 ret = 0; break;
2522 }
2523 case XML_RELAXNG_START:
2524 case XML_RELAXNG_INTERLEAVE:
2525 case XML_RELAXNG_GROUP: {
2526 xmlRelaxNGDefinePtr list = define->content;
2527
2528 while (list != NULL) {
2529 ret = xmlRelaxNGIsNullable(list);
2530 if (ret != 1)
2531 goto done;
2532 list = list->next;
2533 }
2534 return(1);
2535 }
2536 default:
2537 return(-1);
2538 }
2539done:
2540 if (ret == 0)
2541 define->flags |= IS_NOT_NULLABLE;
2542 if (ret == 1)
2543 define->flags |= IS_NULLABLE;
2544 return(ret);
2545}
2546
2547/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002548 * xmlRelaxNGIsBlank:
2549 * @str: a string
2550 *
2551 * Check if a string is ignorable c.f. 4.2. Whitespace
2552 *
2553 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2554 */
2555static int
2556xmlRelaxNGIsBlank(xmlChar *str) {
2557 if (str == NULL)
2558 return(1);
2559 while (*str != 0) {
2560 if (!(IS_BLANK(*str))) return(0);
2561 str++;
2562 }
2563 return(1);
2564}
2565
Daniel Veillard6eadf632003-01-23 18:29:16 +00002566/**
2567 * xmlRelaxNGGetDataTypeLibrary:
2568 * @ctxt: a Relax-NG parser context
2569 * @node: the current data or value element
2570 *
2571 * Applies algorithm from 4.3. datatypeLibrary attribute
2572 *
2573 * Returns the datatypeLibary value or NULL if not found
2574 */
2575static xmlChar *
2576xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2577 xmlNodePtr node) {
2578 xmlChar *ret, *escape;
2579
Daniel Veillard6eadf632003-01-23 18:29:16 +00002580 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2581 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2582 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002583 if (ret[0] == 0) {
2584 xmlFree(ret);
2585 return(NULL);
2586 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002587 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002588 if (escape == NULL) {
2589 return(ret);
2590 }
2591 xmlFree(ret);
2592 return(escape);
2593 }
2594 }
2595 node = node->parent;
2596 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002597 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2598 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002599 if (ret[0] == 0) {
2600 xmlFree(ret);
2601 return(NULL);
2602 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002603 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2604 if (escape == NULL) {
2605 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002606 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002607 xmlFree(ret);
2608 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002609 }
2610 node = node->parent;
2611 }
2612 return(NULL);
2613}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002614
2615/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002616 * xmlRelaxNGParseValue:
2617 * @ctxt: a Relax-NG parser context
2618 * @node: the data node.
2619 *
2620 * parse the content of a RelaxNG value node.
2621 *
2622 * Returns the definition pointer or NULL in case of error
2623 */
2624static xmlRelaxNGDefinePtr
2625xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2626 xmlRelaxNGDefinePtr def = NULL;
2627 xmlRelaxNGTypeLibraryPtr lib;
2628 xmlChar *type;
2629 xmlChar *library;
2630 int tmp;
2631
Daniel Veillardfd573f12003-03-16 17:52:32 +00002632 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002633 if (def == NULL)
2634 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002635 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002636
2637 type = xmlGetProp(node, BAD_CAST "type");
2638 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002639 xmlRelaxNGNormExtSpace(type);
2640 if (xmlValidateNCName(type, 0)) {
2641 if (ctxt->error != NULL)
2642 ctxt->error(ctxt->userData,
2643 "value type '%s' is not an NCName\n",
2644 type);
2645 ctxt->nbErrors++;
2646 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002647 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2648 if (library == NULL)
2649 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2650
2651 def->name = type;
2652 def->ns = library;
2653
2654 lib = (xmlRelaxNGTypeLibraryPtr)
2655 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2656 if (lib == NULL) {
2657 if (ctxt->error != NULL)
2658 ctxt->error(ctxt->userData,
2659 "Use of unregistered type library '%s'\n",
2660 library);
2661 ctxt->nbErrors++;
2662 def->data = NULL;
2663 } else {
2664 def->data = lib;
2665 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002666 if (ctxt->error != NULL)
2667 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002668 "Internal error with type library '%s': no 'have'\n",
2669 library);
2670 ctxt->nbErrors++;
2671 } else {
2672 tmp = lib->have(lib->data, def->name);
2673 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002674 if (ctxt->error != NULL)
2675 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002676 "Error type '%s' is not exported by type library '%s'\n",
2677 def->name, library);
2678 ctxt->nbErrors++;
2679 }
2680 }
2681 }
2682 }
2683 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002684 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002685 } else if (((node->children->type != XML_TEXT_NODE) &&
2686 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002687 (node->children->next != NULL)) {
2688 if (ctxt->error != NULL)
2689 ctxt->error(ctxt->userData,
2690 "Expecting a single text value for <value>content\n");
2691 ctxt->nbErrors++;
2692 } else {
2693 def->value = xmlNodeGetContent(node);
2694 if (def->value == NULL) {
2695 if (ctxt->error != NULL)
2696 ctxt->error(ctxt->userData,
2697 "Element <value> has no content\n");
2698 ctxt->nbErrors++;
2699 }
2700 }
2701 /* TODO check ahead of time that the value is okay per the type */
2702 return(def);
2703}
2704
2705/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002706 * xmlRelaxNGParseData:
2707 * @ctxt: a Relax-NG parser context
2708 * @node: the data node.
2709 *
2710 * parse the content of a RelaxNG data node.
2711 *
2712 * Returns the definition pointer or NULL in case of error
2713 */
2714static xmlRelaxNGDefinePtr
2715xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002716 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002717 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002718 xmlRelaxNGTypeLibraryPtr lib;
2719 xmlChar *type;
2720 xmlChar *library;
2721 xmlNodePtr content;
2722 int tmp;
2723
2724 type = xmlGetProp(node, BAD_CAST "type");
2725 if (type == NULL) {
2726 if (ctxt->error != NULL)
2727 ctxt->error(ctxt->userData,
2728 "data has no type\n");
2729 ctxt->nbErrors++;
2730 return(NULL);
2731 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002732 xmlRelaxNGNormExtSpace(type);
2733 if (xmlValidateNCName(type, 0)) {
2734 if (ctxt->error != NULL)
2735 ctxt->error(ctxt->userData,
2736 "data type '%s' is not an NCName\n",
2737 type);
2738 ctxt->nbErrors++;
2739 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002740 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2741 if (library == NULL)
2742 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2743
Daniel Veillardfd573f12003-03-16 17:52:32 +00002744 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002745 if (def == NULL) {
2746 xmlFree(type);
2747 return(NULL);
2748 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002749 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002750 def->name = type;
2751 def->ns = library;
2752
2753 lib = (xmlRelaxNGTypeLibraryPtr)
2754 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2755 if (lib == NULL) {
2756 if (ctxt->error != NULL)
2757 ctxt->error(ctxt->userData,
2758 "Use of unregistered type library '%s'\n",
2759 library);
2760 ctxt->nbErrors++;
2761 def->data = NULL;
2762 } else {
2763 def->data = lib;
2764 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002765 if (ctxt->error != NULL)
2766 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002767 "Internal error with type library '%s': no 'have'\n",
2768 library);
2769 ctxt->nbErrors++;
2770 } else {
2771 tmp = lib->have(lib->data, def->name);
2772 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002773 if (ctxt->error != NULL)
2774 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002775 "Error type '%s' is not exported by type library '%s'\n",
2776 def->name, library);
2777 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002778 } else if ((xmlStrEqual(library, BAD_CAST
2779 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2780 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2781 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2782 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002783 }
2784 }
2785 }
2786 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002787
2788 /*
2789 * Handle optional params
2790 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002791 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002792 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2793 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002794 if (xmlStrEqual(library,
2795 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2796 if (ctxt->error != NULL)
2797 ctxt->error(ctxt->userData,
2798 "Type library '%s' does not allow type parameters\n",
2799 library);
2800 ctxt->nbErrors++;
2801 content = content->next;
2802 while ((content != NULL) &&
2803 (xmlStrEqual(content->name, BAD_CAST "param")))
2804 content = content->next;
2805 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002806 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002807 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002808 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002809 param->name = xmlGetProp(content, BAD_CAST "name");
2810 if (param->name == NULL) {
2811 if (ctxt->error != NULL)
2812 ctxt->error(ctxt->userData,
2813 "param has no name\n");
2814 ctxt->nbErrors++;
2815 }
2816 param->value = xmlNodeGetContent(content);
2817 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002818 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002819 } else {
2820 lastparam->next = param;
2821 lastparam = param;
2822 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002823 if (lib != NULL) {
2824 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002825 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002826 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002827 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002828 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002829 /*
2830 * Handle optional except
2831 */
2832 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2833 xmlNodePtr child;
2834 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2835
Daniel Veillardfd573f12003-03-16 17:52:32 +00002836 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00002837 if (except == NULL) {
2838 return(def);
2839 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002840 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00002841 child = content->children;
2842 if (last == NULL) {
2843 def->content = except;
2844 } else {
2845 last->next = except;
2846 }
2847 if (child == NULL) {
2848 if (ctxt->error != NULL)
2849 ctxt->error(ctxt->userData,
2850 "except has no content\n");
2851 ctxt->nbErrors++;
2852 }
2853 while (child != NULL) {
2854 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2855 if (tmp2 != NULL) {
2856 if (last2 == NULL) {
2857 except->content = last2 = tmp2;
2858 } else {
2859 last2->next = tmp2;
2860 last2 = tmp2;
2861 }
2862 }
2863 child = child->next;
2864 }
2865 content = content->next;
2866 }
2867 /*
2868 * Check there is no unhandled data
2869 */
2870 if (content != NULL) {
2871 if (ctxt->error != NULL)
2872 ctxt->error(ctxt->userData,
2873 "Element data has unexpected content %s\n", content->name);
2874 ctxt->nbErrors++;
2875 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002876
2877 return(def);
2878}
2879
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002880static const xmlChar *invalidName = BAD_CAST "\1";
2881
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002882/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002883 * xmlRelaxNGCompareNameClasses:
2884 * @defs1: the first element/attribute defs
2885 * @defs2: the second element/attribute defs
2886 * @name: the restriction on the name
2887 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002888 *
2889 * Compare the 2 lists of element definitions. The comparison is
2890 * that if both lists do not accept the same QNames, it returns 1
2891 * If the 2 lists can accept the same QName the comparison returns 0
2892 *
2893 * Returns 1 disttinct, 0 if equal
2894 */
2895static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002896xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2897 xmlRelaxNGDefinePtr def2) {
2898 int ret = 1;
2899 xmlNode node;
2900 xmlNs ns;
2901 xmlRelaxNGValidCtxt ctxt;
2902 ctxt.flags = FLAGS_IGNORABLE;
2903
Daniel Veillard42f12e92003-03-07 18:32:59 +00002904 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
2905
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002906 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2907 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2908 if (def2->type == XML_RELAXNG_TEXT)
2909 return(1);
2910 if (def1->name != NULL) {
2911 node.name = def1->name;
2912 } else {
2913 node.name = invalidName;
2914 }
2915 node.ns = &ns;
2916 if (def1->ns != NULL) {
2917 if (def1->ns[0] == 0) {
2918 node.ns = NULL;
2919 } else {
2920 ns.href = def1->ns;
2921 }
2922 } else {
2923 ns.href = invalidName;
2924 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002925 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002926 if (def1->nameClass != NULL) {
2927 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2928 } else {
2929 ret = 0;
2930 }
2931 } else {
2932 ret = 1;
2933 }
2934 } else if (def1->type == XML_RELAXNG_TEXT) {
2935 if (def2->type == XML_RELAXNG_TEXT)
2936 return(0);
2937 return(1);
2938 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002939 TODO
2940 ret = 0;
2941 } else {
2942 TODO
2943 ret = 0;
2944 }
2945 if (ret == 0)
2946 return(ret);
2947 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2948 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2949 if (def2->name != NULL) {
2950 node.name = def2->name;
2951 } else {
2952 node.name = invalidName;
2953 }
2954 node.ns = &ns;
2955 if (def2->ns != NULL) {
2956 if (def2->ns[0] == 0) {
2957 node.ns = NULL;
2958 } else {
2959 ns.href = def2->ns;
2960 }
2961 } else {
2962 ns.href = invalidName;
2963 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002964 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002965 if (def2->nameClass != NULL) {
2966 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2967 } else {
2968 ret = 0;
2969 }
2970 } else {
2971 ret = 1;
2972 }
2973 } else {
2974 TODO
2975 ret = 0;
2976 }
2977
2978 return(ret);
2979}
2980
2981/**
2982 * xmlRelaxNGCompareElemDefLists:
2983 * @ctxt: a Relax-NG parser context
2984 * @defs1: the first list of element/attribute defs
2985 * @defs2: the second list of element/attribute defs
2986 *
2987 * Compare the 2 lists of element or attribute definitions. The comparison
2988 * is that if both lists do not accept the same QNames, it returns 1
2989 * If the 2 lists can accept the same QName the comparison returns 0
2990 *
2991 * Returns 1 disttinct, 0 if equal
2992 */
2993static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002994xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2995 xmlRelaxNGDefinePtr *def1,
2996 xmlRelaxNGDefinePtr *def2) {
2997 xmlRelaxNGDefinePtr *basedef2 = def2;
2998
Daniel Veillard154877e2003-01-30 12:17:05 +00002999 if ((def1 == NULL) || (def2 == NULL))
3000 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003001 if ((*def1 == NULL) || (*def2 == NULL))
3002 return(1);
3003 while (*def1 != NULL) {
3004 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003005 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3006 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003007 def2++;
3008 }
3009 def2 = basedef2;
3010 def1++;
3011 }
3012 return(1);
3013}
3014
3015/**
3016 * xmlRelaxNGGetElements:
3017 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003018 * @def: the definition definition
3019 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003020 *
3021 * Compute the list of top elements a definition can generate
3022 *
3023 * Returns a list of elements or NULL if none was found.
3024 */
3025static xmlRelaxNGDefinePtr *
3026xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003027 xmlRelaxNGDefinePtr def,
3028 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003029 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003030 int len = 0;
3031 int max = 0;
3032
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003033 /*
3034 * Don't run that check in case of error. Infinite recursion
3035 * becomes possible.
3036 */
3037 if (ctxt->nbErrors != 0)
3038 return(NULL);
3039
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003040 parent = NULL;
3041 cur = def;
3042 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003043 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3044 (cur->type == XML_RELAXNG_TEXT))) ||
3045 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003046 if (ret == NULL) {
3047 max = 10;
3048 ret = (xmlRelaxNGDefinePtr *)
3049 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3050 if (ret == NULL) {
3051 if (ctxt->error != NULL)
3052 ctxt->error(ctxt->userData,
3053 "Out of memory in element search\n");
3054 ctxt->nbErrors++;
3055 return(NULL);
3056 }
3057 } else if (max <= len) {
3058 max *= 2;
3059 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3060 if (ret == NULL) {
3061 if (ctxt->error != NULL)
3062 ctxt->error(ctxt->userData,
3063 "Out of memory in element search\n");
3064 ctxt->nbErrors++;
3065 return(NULL);
3066 }
3067 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003068 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003069 ret[len] = NULL;
3070 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3071 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3072 (cur->type == XML_RELAXNG_GROUP) ||
3073 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003074 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3075 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003076 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003077 (cur->type == XML_RELAXNG_REF) ||
3078 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003079 /*
3080 * Don't go within elements or attributes or string values.
3081 * Just gather the element top list
3082 */
3083 if (cur->content != NULL) {
3084 parent = cur;
3085 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003086 tmp = cur;
3087 while (tmp != NULL) {
3088 tmp->parent = parent;
3089 tmp = tmp->next;
3090 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003091 continue;
3092 }
3093 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003094 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003095 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003096 if (cur->next != NULL) {
3097 cur = cur->next;
3098 continue;
3099 }
3100 do {
3101 cur = cur->parent;
3102 if (cur == NULL) break;
3103 if (cur == def) return(ret);
3104 if (cur->next != NULL) {
3105 cur = cur->next;
3106 break;
3107 }
3108 } while (cur != NULL);
3109 }
3110 return(ret);
3111}
3112
3113/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003114 * xmlRelaxNGCheckChoiceDeterminism:
3115 * @ctxt: a Relax-NG parser context
3116 * @def: the choice definition
3117 *
3118 * Also used to find indeterministic pattern in choice
3119 */
3120static void
3121xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3122 xmlRelaxNGDefinePtr def) {
3123 xmlRelaxNGDefinePtr **list;
3124 xmlRelaxNGDefinePtr cur;
3125 int nbchild = 0, i, j, ret;
3126 int is_nullable = 0;
3127 int is_indeterminist = 0;
3128
3129 if ((def == NULL) ||
3130 (def->type != XML_RELAXNG_CHOICE))
3131 return;
3132
3133 /*
3134 * Don't run that check in case of error. Infinite recursion
3135 * becomes possible.
3136 */
3137 if (ctxt->nbErrors != 0)
3138 return;
3139
3140 is_nullable = xmlRelaxNGIsNullable(def);
3141
3142 cur = def->content;
3143 while (cur != NULL) {
3144 nbchild++;
3145 cur = cur->next;
3146 }
3147
3148 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3149 sizeof(xmlRelaxNGDefinePtr *));
3150 if (list == NULL) {
3151 if (ctxt->error != NULL)
3152 ctxt->error(ctxt->userData,
3153 "Out of memory in choice computation\n");
3154 ctxt->nbErrors++;
3155 return;
3156 }
3157 i = 0;
3158 cur = def->content;
3159 while (cur != NULL) {
3160 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
3161 i++;
3162 cur = cur->next;
3163 }
3164
3165 for (i = 0;i < nbchild;i++) {
3166 if (list[i] == NULL)
3167 continue;
3168 for (j = 0;j < i;j++) {
3169 if (list[j] == NULL)
3170 continue;
3171 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3172 if (ret == 0) {
3173 is_indeterminist = 1;
3174 }
3175 }
3176 }
3177 for (i = 0;i < nbchild;i++) {
3178 if (list[i] != NULL)
3179 xmlFree(list[i]);
3180 }
3181
3182 xmlFree(list);
3183 if (is_indeterminist) {
3184 def->flags |= IS_INDETERMINIST;
3185 }
3186}
3187
3188/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003189 * xmlRelaxNGCheckGroupAttrs:
3190 * @ctxt: a Relax-NG parser context
3191 * @def: the group definition
3192 *
3193 * Detects violations of rule 7.3
3194 */
3195static void
3196xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3197 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003198 xmlRelaxNGDefinePtr **list;
3199 xmlRelaxNGDefinePtr cur;
3200 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003201
3202 if ((def == NULL) ||
3203 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003204 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003205 return;
3206
3207 /*
3208 * Don't run that check in case of error. Infinite recursion
3209 * becomes possible.
3210 */
3211 if (ctxt->nbErrors != 0)
3212 return;
3213
Daniel Veillardfd573f12003-03-16 17:52:32 +00003214 cur = def->attrs;
3215 while (cur != NULL) {
3216 nbchild++;
3217 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003218 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003219 cur = def->content;
3220 while (cur != NULL) {
3221 nbchild++;
3222 cur = cur->next;
3223 }
3224
3225 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3226 sizeof(xmlRelaxNGDefinePtr *));
3227 if (list == NULL) {
3228 if (ctxt->error != NULL)
3229 ctxt->error(ctxt->userData,
3230 "Out of memory in group computation\n");
3231 ctxt->nbErrors++;
3232 return;
3233 }
3234 i = 0;
3235 cur = def->attrs;
3236 while (cur != NULL) {
3237 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3238 i++;
3239 cur = cur->next;
3240 }
3241 cur = def->content;
3242 while (cur != NULL) {
3243 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3244 i++;
3245 cur = cur->next;
3246 }
3247
3248 for (i = 0;i < nbchild;i++) {
3249 if (list[i] == NULL)
3250 continue;
3251 for (j = 0;j < i;j++) {
3252 if (list[j] == NULL)
3253 continue;
3254 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3255 if (ret == 0) {
3256 if (ctxt->error != NULL)
3257 ctxt->error(ctxt->userData,
3258 "Attributes conflicts in group\n");
3259 ctxt->nbErrors++;
3260 }
3261 }
3262 }
3263 for (i = 0;i < nbchild;i++) {
3264 if (list[i] != NULL)
3265 xmlFree(list[i]);
3266 }
3267
3268 xmlFree(list);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003269}
3270
3271/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003272 * xmlRelaxNGComputeInterleaves:
3273 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003274 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003275 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003276 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003277 * A lot of work for preprocessing interleave definitions
3278 * is potentially needed to get a decent execution speed at runtime
3279 * - trying to get a total order on the element nodes generated
3280 * by the interleaves, order the list of interleave definitions
3281 * following that order.
3282 * - if <text/> is used to handle mixed content, it is better to
3283 * flag this in the define and simplify the runtime checking
3284 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003285 */
3286static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003287xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3288 xmlRelaxNGParserCtxtPtr ctxt,
3289 xmlChar *name ATTRIBUTE_UNUSED) {
3290 xmlRelaxNGDefinePtr cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003291
Daniel Veillardfd573f12003-03-16 17:52:32 +00003292 xmlRelaxNGPartitionPtr partitions = NULL;
3293 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3294 xmlRelaxNGInterleaveGroupPtr group;
3295 int i,j,ret;
3296 int nbgroups = 0;
3297 int nbchild = 0;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003298
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003299 /*
3300 * Don't run that check in case of error. Infinite recursion
3301 * becomes possible.
3302 */
3303 if (ctxt->nbErrors != 0)
3304 return;
3305
Daniel Veillardfd573f12003-03-16 17:52:32 +00003306#ifdef DEBUG_INTERLEAVE
3307 xmlGenericError(xmlGenericErrorContext,
3308 "xmlRelaxNGComputeInterleaves(%s)\n",
3309 name);
3310#endif
3311 cur = def->content;
3312 while (cur != NULL) {
3313 nbchild++;
3314 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003315 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003316
3317#ifdef DEBUG_INTERLEAVE
3318 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3319#endif
3320 groups = (xmlRelaxNGInterleaveGroupPtr *)
3321 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3322 if (groups == NULL)
3323 goto error;
3324 cur = def->content;
3325 while (cur != NULL) {
3326 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3327 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3328 if (groups[nbgroups] == NULL)
3329 goto error;
3330 groups[nbgroups]->rule = cur;
3331 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3332 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3333 nbgroups++;
3334 cur = cur->next;
3335 }
3336#ifdef DEBUG_INTERLEAVE
3337 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3338#endif
3339
3340 /*
3341 * Let's check that all rules makes a partitions according to 7.4
3342 */
3343 partitions = (xmlRelaxNGPartitionPtr)
3344 xmlMalloc(sizeof(xmlRelaxNGPartition));
3345 if (partitions == NULL)
3346 goto error;
3347 partitions->nbgroups = nbgroups;
3348 for (i = 0;i < nbgroups;i++) {
3349 group = groups[i];
3350 for (j = i+1;j < nbgroups;j++) {
3351 if (groups[j] == NULL)
3352 continue;
3353 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3354 groups[j]->defs);
3355 if (ret == 0) {
3356 if (ctxt->error != NULL)
3357 ctxt->error(ctxt->userData,
3358 "Element or text conflicts in interleave\n");
3359 ctxt->nbErrors++;
3360 }
3361 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3362 groups[j]->attrs);
3363 if (ret == 0) {
3364 if (ctxt->error != NULL)
3365 ctxt->error(ctxt->userData,
3366 "Attributes conflicts in interleave\n");
3367 ctxt->nbErrors++;
3368 }
3369 }
3370 }
3371 partitions->groups = groups;
3372
3373 /*
3374 * and save the partition list back in the def
3375 */
3376 def->data = partitions;
3377 return;
3378
3379error:
3380 if (ctxt->error != NULL)
3381 ctxt->error(ctxt->userData,
3382 "Out of memory in interleave computation\n");
3383 ctxt->nbErrors++;
3384 if (groups != NULL) {
3385 for (i = 0;i < nbgroups;i++)
3386 if (groups[i] != NULL) {
3387 if (groups[i]->defs != NULL)
3388 xmlFree(groups[i]->defs);
3389 xmlFree(groups[i]);
3390 }
3391 xmlFree(groups);
3392 }
3393 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003394}
3395
3396/**
3397 * xmlRelaxNGParseInterleave:
3398 * @ctxt: a Relax-NG parser context
3399 * @node: the data node.
3400 *
3401 * parse the content of a RelaxNG interleave node.
3402 *
3403 * Returns the definition pointer or NULL in case of error
3404 */
3405static xmlRelaxNGDefinePtr
3406xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3407 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003408 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003409 xmlNodePtr child;
3410
Daniel Veillardfd573f12003-03-16 17:52:32 +00003411 def = xmlRelaxNGNewDefine(ctxt, node);
3412 if (def == NULL) {
3413 return(NULL);
3414 }
3415 def->type = XML_RELAXNG_INTERLEAVE;
3416
3417 if (ctxt->interleaves == NULL)
3418 ctxt->interleaves = xmlHashCreate(10);
3419 if (ctxt->interleaves == NULL) {
3420 if (ctxt->error != NULL)
3421 ctxt->error(ctxt->userData,
3422 "Failed to create interleaves hash table\n");
3423 ctxt->nbErrors++;
3424 } else {
3425 char name[32];
3426
3427 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3428 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3429 if (ctxt->error != NULL)
3430 ctxt->error(ctxt->userData,
3431 "Failed to add %s to hash table\n", name);
3432 ctxt->nbErrors++;
3433 }
3434 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003435 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003436 if (child == NULL) {
3437 if (ctxt->error != NULL)
3438 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3439 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003440 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003441 while (child != NULL) {
3442 if (IS_RELAXNG(child, "element")) {
3443 cur = xmlRelaxNGParseElement(ctxt, child);
3444 } else {
3445 cur = xmlRelaxNGParsePattern(ctxt, child);
3446 }
3447 if (cur != NULL) {
3448 cur->parent = def;
3449 if (last == NULL) {
3450 def->content = last = cur;
3451 } else {
3452 last->next = cur;
3453 last = cur;
3454 }
3455 }
3456 child = child->next;
3457 }
3458
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003459 return(def);
3460}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003461
3462/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003463 * xmlRelaxNGParseInclude:
3464 * @ctxt: a Relax-NG parser context
3465 * @node: the include node
3466 *
3467 * Integrate the content of an include node in the current grammar
3468 *
3469 * Returns 0 in case of success or -1 in case of error
3470 */
3471static int
3472xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3473 xmlRelaxNGIncludePtr incl;
3474 xmlNodePtr root;
3475 int ret = 0, tmp;
3476
3477 incl = node->_private;
3478 if (incl == NULL) {
3479 if (ctxt->error != NULL)
3480 ctxt->error(ctxt->userData,
3481 "Include node has no data\n");
3482 ctxt->nbErrors++;
3483 return(-1);
3484 }
3485 root = xmlDocGetRootElement(incl->doc);
3486 if (root == NULL) {
3487 if (ctxt->error != NULL)
3488 ctxt->error(ctxt->userData,
3489 "Include document is empty\n");
3490 ctxt->nbErrors++;
3491 return(-1);
3492 }
3493 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3494 if (ctxt->error != NULL)
3495 ctxt->error(ctxt->userData,
3496 "Include document root is not a grammar\n");
3497 ctxt->nbErrors++;
3498 return(-1);
3499 }
3500
3501 /*
3502 * Merge the definition from both the include and the internal list
3503 */
3504 if (root->children != NULL) {
3505 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3506 if (tmp != 0)
3507 ret = -1;
3508 }
3509 if (node->children != NULL) {
3510 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3511 if (tmp != 0)
3512 ret = -1;
3513 }
3514 return(ret);
3515}
3516
3517/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003518 * xmlRelaxNGParseDefine:
3519 * @ctxt: a Relax-NG parser context
3520 * @node: the define node
3521 *
3522 * parse the content of a RelaxNG define element node.
3523 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003524 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003525 */
3526static int
3527xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3528 xmlChar *name;
3529 int ret = 0, tmp;
3530 xmlRelaxNGDefinePtr def;
3531 const xmlChar *olddefine;
3532
3533 name = xmlGetProp(node, BAD_CAST "name");
3534 if (name == NULL) {
3535 if (ctxt->error != NULL)
3536 ctxt->error(ctxt->userData,
3537 "define has no name\n");
3538 ctxt->nbErrors++;
3539 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003540 xmlRelaxNGNormExtSpace(name);
3541 if (xmlValidateNCName(name, 0)) {
3542 if (ctxt->error != NULL)
3543 ctxt->error(ctxt->userData,
3544 "define name '%s' is not an NCName\n",
3545 name);
3546 ctxt->nbErrors++;
3547 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003548 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003549 if (def == NULL) {
3550 xmlFree(name);
3551 return(-1);
3552 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003553 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003554 def->name = name;
3555 if (node->children == NULL) {
3556 if (ctxt->error != NULL)
3557 ctxt->error(ctxt->userData,
3558 "define has no children\n");
3559 ctxt->nbErrors++;
3560 } else {
3561 olddefine = ctxt->define;
3562 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003563 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003564 ctxt->define = olddefine;
3565 }
3566 if (ctxt->grammar->defs == NULL)
3567 ctxt->grammar->defs = xmlHashCreate(10);
3568 if (ctxt->grammar->defs == NULL) {
3569 if (ctxt->error != NULL)
3570 ctxt->error(ctxt->userData,
3571 "Could not create definition hash\n");
3572 ctxt->nbErrors++;
3573 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003574 } else {
3575 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3576 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003577 xmlRelaxNGDefinePtr prev;
3578
3579 prev = xmlHashLookup(ctxt->grammar->defs, name);
3580 if (prev == NULL) {
3581 if (ctxt->error != NULL)
3582 ctxt->error(ctxt->userData,
3583 "Internal error on define aggregation of %s\n",
3584 name);
3585 ctxt->nbErrors++;
3586 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003587 } else {
3588 while (prev->nextHash != NULL)
3589 prev = prev->nextHash;
3590 prev->nextHash = def;
3591 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003592 }
3593 }
3594 }
3595 return(ret);
3596}
3597
3598/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003599 * xmlRelaxNGProcessExternalRef:
3600 * @ctxt: the parser context
3601 * @node: the externlRef node
3602 *
3603 * Process and compile an externlRef node
3604 *
3605 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3606 */
3607static xmlRelaxNGDefinePtr
3608xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3609 xmlRelaxNGDocumentPtr docu;
3610 xmlNodePtr root, tmp;
3611 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003612 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003613 xmlRelaxNGDefinePtr def;
3614
3615 docu = node->_private;
3616 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003617 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003618 if (def == NULL)
3619 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003620 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003621
3622 if (docu->content == NULL) {
3623 /*
3624 * Then do the parsing for good
3625 */
3626 root = xmlDocGetRootElement(docu->doc);
3627 if (root == NULL) {
3628 if (ctxt->error != NULL)
3629 ctxt->error(ctxt->userData,
3630 "xmlRelaxNGParse: %s is empty\n",
3631 ctxt->URL);
3632 ctxt->nbErrors++;
3633 return (NULL);
3634 }
3635 /*
3636 * ns transmission rules
3637 */
3638 ns = xmlGetProp(root, BAD_CAST "ns");
3639 if (ns == NULL) {
3640 tmp = node;
3641 while ((tmp != NULL) &&
3642 (tmp->type == XML_ELEMENT_NODE)) {
3643 ns = xmlGetProp(tmp, BAD_CAST "ns");
3644 if (ns != NULL) {
3645 break;
3646 }
3647 tmp = tmp->parent;
3648 }
3649 if (ns != NULL) {
3650 xmlSetProp(root, BAD_CAST "ns", ns);
3651 newNs = 1;
3652 xmlFree(ns);
3653 }
3654 } else {
3655 xmlFree(ns);
3656 }
3657
3658 /*
3659 * Parsing to get a precompiled schemas.
3660 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003661 oldflags = ctxt->flags;
3662 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003663 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003664 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003665 if ((docu->schema != NULL) &&
3666 (docu->schema->topgrammar != NULL)) {
3667 docu->content = docu->schema->topgrammar->start;
3668 }
3669
3670 /*
3671 * the externalRef may be reused in a different ns context
3672 */
3673 if (newNs == 1) {
3674 xmlUnsetProp(root, BAD_CAST "ns");
3675 }
3676 }
3677 def->content = docu->content;
3678 } else {
3679 def = NULL;
3680 }
3681 return(def);
3682}
3683
3684/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003685 * xmlRelaxNGParsePattern:
3686 * @ctxt: a Relax-NG parser context
3687 * @node: the pattern node.
3688 *
3689 * parse the content of a RelaxNG pattern node.
3690 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003691 * Returns the definition pointer or NULL in case of error or if no
3692 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003693 */
3694static xmlRelaxNGDefinePtr
3695xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3696 xmlRelaxNGDefinePtr def = NULL;
3697
Daniel Veillardd2298792003-02-14 16:54:11 +00003698 if (node == NULL) {
3699 return(NULL);
3700 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003701 if (IS_RELAXNG(node, "element")) {
3702 def = xmlRelaxNGParseElement(ctxt, node);
3703 } else if (IS_RELAXNG(node, "attribute")) {
3704 def = xmlRelaxNGParseAttribute(ctxt, node);
3705 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003706 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003707 if (def == NULL)
3708 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003709 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003710 if (node->children != NULL) {
3711 if (ctxt->error != NULL)
3712 ctxt->error(ctxt->userData, "empty: had a child node\n");
3713 ctxt->nbErrors++;
3714 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003715 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003716 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003717 if (def == NULL)
3718 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003719 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003720 if (node->children != NULL) {
3721 if (ctxt->error != NULL)
3722 ctxt->error(ctxt->userData, "text: had a child node\n");
3723 ctxt->nbErrors++;
3724 }
3725 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003726 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003727 if (def == NULL)
3728 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003729 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003730 if (node->children == NULL) {
3731 if (ctxt->error != NULL)
3732 ctxt->error(ctxt->userData,
3733 "Element %s is empty\n", node->name);
3734 ctxt->nbErrors++;
3735 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003736 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003737 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003738 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003739 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003740 if (def == NULL)
3741 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003742 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003743 if (node->children == NULL) {
3744 if (ctxt->error != NULL)
3745 ctxt->error(ctxt->userData,
3746 "Element %s is empty\n", node->name);
3747 ctxt->nbErrors++;
3748 } else {
3749 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3750 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003751 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003752 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003753 if (def == NULL)
3754 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003755 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003756 if (node->children == NULL) {
3757 if (ctxt->error != NULL)
3758 ctxt->error(ctxt->userData,
3759 "Element %s is empty\n", node->name);
3760 ctxt->nbErrors++;
3761 } else {
3762 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3763 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003764 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003765 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003766 if (def == NULL)
3767 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003768 def->type = XML_RELAXNG_CHOICE;
3769 if (node->children == NULL) {
3770 if (ctxt->error != NULL)
3771 ctxt->error(ctxt->userData,
3772 "Element %s is empty\n", node->name);
3773 ctxt->nbErrors++;
3774 } else {
3775 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3776 }
3777 } else if (IS_RELAXNG(node, "group")) {
3778 def = xmlRelaxNGNewDefine(ctxt, node);
3779 if (def == NULL)
3780 return(NULL);
3781 def->type = XML_RELAXNG_GROUP;
3782 if (node->children == NULL) {
3783 if (ctxt->error != NULL)
3784 ctxt->error(ctxt->userData,
3785 "Element %s is empty\n", node->name);
3786 ctxt->nbErrors++;
3787 } else {
3788 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3789 }
3790 } else if (IS_RELAXNG(node, "ref")) {
3791 def = xmlRelaxNGNewDefine(ctxt, node);
3792 if (def == NULL)
3793 return(NULL);
3794 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003795 def->name = xmlGetProp(node, BAD_CAST "name");
3796 if (def->name == NULL) {
3797 if (ctxt->error != NULL)
3798 ctxt->error(ctxt->userData,
3799 "ref has no name\n");
3800 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003801 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003802 xmlRelaxNGNormExtSpace(def->name);
3803 if (xmlValidateNCName(def->name, 0)) {
3804 if (ctxt->error != NULL)
3805 ctxt->error(ctxt->userData,
3806 "ref name '%s' is not an NCName\n",
3807 def->name);
3808 ctxt->nbErrors++;
3809 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003810 }
3811 if (node->children != NULL) {
3812 if (ctxt->error != NULL)
3813 ctxt->error(ctxt->userData,
3814 "ref is not empty\n");
3815 ctxt->nbErrors++;
3816 }
3817 if (ctxt->grammar->refs == NULL)
3818 ctxt->grammar->refs = xmlHashCreate(10);
3819 if (ctxt->grammar->refs == NULL) {
3820 if (ctxt->error != NULL)
3821 ctxt->error(ctxt->userData,
3822 "Could not create references hash\n");
3823 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003824 def = NULL;
3825 } else {
3826 int tmp;
3827
3828 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
3829 if (tmp < 0) {
3830 xmlRelaxNGDefinePtr prev;
3831
3832 prev = (xmlRelaxNGDefinePtr)
3833 xmlHashLookup(ctxt->grammar->refs, def->name);
3834 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003835 if (def->name != NULL) {
3836 if (ctxt->error != NULL)
3837 ctxt->error(ctxt->userData,
3838 "Error refs definitions '%s'\n",
3839 def->name);
3840 } else {
3841 if (ctxt->error != NULL)
3842 ctxt->error(ctxt->userData,
3843 "Error refs definitions\n");
3844 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003845 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003846 def = NULL;
3847 } else {
3848 def->nextHash = prev->nextHash;
3849 prev->nextHash = def;
3850 }
3851 }
3852 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003853 } else if (IS_RELAXNG(node, "data")) {
3854 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003855 } else if (IS_RELAXNG(node, "value")) {
3856 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003857 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003858 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003859 if (def == NULL)
3860 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003861 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00003862 if (node->children == NULL) {
3863 if (ctxt->error != NULL)
3864 ctxt->error(ctxt->userData,
3865 "Element %s is empty\n", node->name);
3866 ctxt->nbErrors++;
3867 } else {
3868 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3869 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003870 } else if (IS_RELAXNG(node, "interleave")) {
3871 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003872 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003873 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003874 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003875 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003876 if (def == NULL)
3877 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003878 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003879 if (node->children != NULL) {
3880 if (ctxt->error != NULL)
3881 ctxt->error(ctxt->userData,
3882 "xmlRelaxNGParse: notAllowed element is not empty\n");
3883 ctxt->nbErrors++;
3884 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003885 } else if (IS_RELAXNG(node, "grammar")) {
3886 xmlRelaxNGGrammarPtr grammar, old;
3887 xmlRelaxNGGrammarPtr oldparent;
3888
Daniel Veillardc482e262003-02-26 14:48:48 +00003889#ifdef DEBUG_GRAMMAR
3890 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
3891#endif
3892
Daniel Veillard419a7682003-02-03 23:22:49 +00003893 oldparent = ctxt->parentgrammar;
3894 old = ctxt->grammar;
3895 ctxt->parentgrammar = old;
3896 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
3897 if (old != NULL) {
3898 ctxt->grammar = old;
3899 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00003900#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00003901 if (grammar != NULL) {
3902 grammar->next = old->next;
3903 old->next = grammar;
3904 }
Daniel Veillardc482e262003-02-26 14:48:48 +00003905#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00003906 }
3907 if (grammar != NULL)
3908 def = grammar->start;
3909 else
3910 def = NULL;
3911 } else if (IS_RELAXNG(node, "parentRef")) {
3912 if (ctxt->parentgrammar == NULL) {
3913 if (ctxt->error != NULL)
3914 ctxt->error(ctxt->userData,
3915 "Use of parentRef without a parent grammar\n");
3916 ctxt->nbErrors++;
3917 return(NULL);
3918 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003919 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00003920 if (def == NULL)
3921 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003922 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00003923 def->name = xmlGetProp(node, BAD_CAST "name");
3924 if (def->name == NULL) {
3925 if (ctxt->error != NULL)
3926 ctxt->error(ctxt->userData,
3927 "parentRef has no name\n");
3928 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00003929 } else {
3930 xmlRelaxNGNormExtSpace(def->name);
3931 if (xmlValidateNCName(def->name, 0)) {
3932 if (ctxt->error != NULL)
3933 ctxt->error(ctxt->userData,
3934 "parentRef name '%s' is not an NCName\n",
3935 def->name);
3936 ctxt->nbErrors++;
3937 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003938 }
3939 if (node->children != NULL) {
3940 if (ctxt->error != NULL)
3941 ctxt->error(ctxt->userData,
3942 "parentRef is not empty\n");
3943 ctxt->nbErrors++;
3944 }
3945 if (ctxt->parentgrammar->refs == NULL)
3946 ctxt->parentgrammar->refs = xmlHashCreate(10);
3947 if (ctxt->parentgrammar->refs == NULL) {
3948 if (ctxt->error != NULL)
3949 ctxt->error(ctxt->userData,
3950 "Could not create references hash\n");
3951 ctxt->nbErrors++;
3952 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003953 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00003954 int tmp;
3955
3956 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3957 if (tmp < 0) {
3958 xmlRelaxNGDefinePtr prev;
3959
3960 prev = (xmlRelaxNGDefinePtr)
3961 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3962 if (prev == NULL) {
3963 if (ctxt->error != NULL)
3964 ctxt->error(ctxt->userData,
3965 "Internal error parentRef definitions '%s'\n",
3966 def->name);
3967 ctxt->nbErrors++;
3968 def = NULL;
3969 } else {
3970 def->nextHash = prev->nextHash;
3971 prev->nextHash = def;
3972 }
3973 }
3974 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003975 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003976 if (node->children == NULL) {
3977 if (ctxt->error != NULL)
3978 ctxt->error(ctxt->userData,
3979 "Mixed is empty\n");
3980 ctxt->nbErrors++;
3981 def = NULL;
3982 } else {
3983 def = xmlRelaxNGParseInterleave(ctxt, node);
3984 if (def != NULL) {
3985 xmlRelaxNGDefinePtr tmp;
3986
3987 if ((def->content != NULL) && (def->content->next != NULL)) {
3988 tmp = xmlRelaxNGNewDefine(ctxt, node);
3989 if (tmp != NULL) {
3990 tmp->type = XML_RELAXNG_GROUP;
3991 tmp->content = def->content;
3992 def->content = tmp;
3993 }
3994 }
3995
3996 tmp = xmlRelaxNGNewDefine(ctxt, node);
3997 if (tmp == NULL)
3998 return(def);
3999 tmp->type = XML_RELAXNG_TEXT;
4000 tmp->next = def->content;
4001 def->content = tmp;
4002 }
4003 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004004 } else {
4005 if (ctxt->error != NULL)
4006 ctxt->error(ctxt->userData,
4007 "Unexpected node %s is not a pattern\n",
4008 node->name);
4009 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004010 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004011 }
4012 return(def);
4013}
4014
4015/**
4016 * xmlRelaxNGParseAttribute:
4017 * @ctxt: a Relax-NG parser context
4018 * @node: the element node
4019 *
4020 * parse the content of a RelaxNG attribute node.
4021 *
4022 * Returns the definition pointer or NULL in case of error.
4023 */
4024static xmlRelaxNGDefinePtr
4025xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004026 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004027 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004028 int old_flags;
4029
Daniel Veillardfd573f12003-03-16 17:52:32 +00004030 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004031 if (ret == NULL)
4032 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004033 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004034 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004035 child = node->children;
4036 if (child == NULL) {
4037 if (ctxt->error != NULL)
4038 ctxt->error(ctxt->userData,
4039 "xmlRelaxNGParseattribute: attribute has no children\n");
4040 ctxt->nbErrors++;
4041 return(ret);
4042 }
4043 old_flags = ctxt->flags;
4044 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004045 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4046 if (cur != NULL)
4047 child = child->next;
4048
Daniel Veillardd2298792003-02-14 16:54:11 +00004049 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004050 cur = xmlRelaxNGParsePattern(ctxt, child);
4051 if (cur != NULL) {
4052 switch (cur->type) {
4053 case XML_RELAXNG_EMPTY:
4054 case XML_RELAXNG_NOT_ALLOWED:
4055 case XML_RELAXNG_TEXT:
4056 case XML_RELAXNG_ELEMENT:
4057 case XML_RELAXNG_DATATYPE:
4058 case XML_RELAXNG_VALUE:
4059 case XML_RELAXNG_LIST:
4060 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004061 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004062 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004063 case XML_RELAXNG_DEF:
4064 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004065 case XML_RELAXNG_ZEROORMORE:
4066 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004067 case XML_RELAXNG_CHOICE:
4068 case XML_RELAXNG_GROUP:
4069 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004070 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004071 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004072 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004073 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004074 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004075 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004076 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004077 if (ctxt->error != NULL)
4078 ctxt->error(ctxt->userData,
4079 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004080 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004081 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004082 case XML_RELAXNG_NOOP:
4083 TODO
4084 if (ctxt->error != NULL)
4085 ctxt->error(ctxt->userData,
4086 "Internal error, noop found\n");
4087 ctxt->nbErrors++;
4088 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004089 }
4090 }
4091 child = child->next;
4092 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004093 if (child != NULL) {
4094 if (ctxt->error != NULL)
4095 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4096 ctxt->nbErrors++;
4097 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004098 ctxt->flags = old_flags;
4099 return(ret);
4100}
4101
4102/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004103 * xmlRelaxNGParseExceptNameClass:
4104 * @ctxt: a Relax-NG parser context
4105 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004106 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004107 *
4108 * parse the content of a RelaxNG nameClass node.
4109 *
4110 * Returns the definition pointer or NULL in case of error.
4111 */
4112static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004113xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4114 xmlNodePtr node, int attr) {
4115 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4116 xmlNodePtr child;
4117
Daniel Veillardd2298792003-02-14 16:54:11 +00004118 if (!IS_RELAXNG(node, "except")) {
4119 if (ctxt->error != NULL)
4120 ctxt->error(ctxt->userData,
4121 "Expecting an except node\n");
4122 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004123 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004124 }
4125 if (node->next != NULL) {
4126 if (ctxt->error != NULL)
4127 ctxt->error(ctxt->userData,
4128 "exceptNameClass allows only a single except node\n");
4129 ctxt->nbErrors++;
4130 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004131 if (node->children == NULL) {
4132 if (ctxt->error != NULL)
4133 ctxt->error(ctxt->userData,
4134 "except has no content\n");
4135 ctxt->nbErrors++;
4136 return(NULL);
4137 }
4138
Daniel Veillardfd573f12003-03-16 17:52:32 +00004139 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004140 if (ret == NULL)
4141 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004142 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004143 child = node->children;
4144 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004145 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004146 if (cur == NULL)
4147 break;
4148 if (attr)
4149 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004150 else
4151 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004152
Daniel Veillard419a7682003-02-03 23:22:49 +00004153 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004154 if (last == NULL) {
4155 ret->content = cur;
4156 } else {
4157 last->next = cur;
4158 }
4159 last = cur;
4160 }
4161 child = child->next;
4162 }
4163
4164 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004165}
4166
4167/**
4168 * xmlRelaxNGParseNameClass:
4169 * @ctxt: a Relax-NG parser context
4170 * @node: the nameClass node
4171 * @def: the current definition
4172 *
4173 * parse the content of a RelaxNG nameClass node.
4174 *
4175 * Returns the definition pointer or NULL in case of error.
4176 */
4177static xmlRelaxNGDefinePtr
4178xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4179 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004180 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004181 xmlChar *val;
4182
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004183 ret = def;
4184 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4185 (IS_RELAXNG(node, "nsName"))) {
4186 if ((def->type != XML_RELAXNG_ELEMENT) &&
4187 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004188 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004189 if (ret == NULL)
4190 return(NULL);
4191 ret->parent = def;
4192 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4193 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004194 else
4195 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004196 }
4197 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004198 if (IS_RELAXNG(node, "name")) {
4199 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004200 xmlRelaxNGNormExtSpace(val);
4201 if (xmlValidateNCName(val, 0)) {
4202 if (ctxt->error != NULL) {
4203 if (node->parent != NULL)
4204 ctxt->error(ctxt->userData,
4205 "Element %s name '%s' is not an NCName\n",
4206 node->parent->name, val);
4207 else
4208 ctxt->error(ctxt->userData,
4209 "name '%s' is not an NCName\n",
4210 val);
4211 }
4212 ctxt->nbErrors++;
4213 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004214 ret->name = val;
4215 val = xmlGetProp(node, BAD_CAST "ns");
4216 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004217 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4218 (val != NULL) &&
4219 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4220 ctxt->error(ctxt->userData,
4221 "Attribute with namespace '%s' is not allowed\n",
4222 val);
4223 ctxt->nbErrors++;
4224 }
4225 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4226 (val != NULL) &&
4227 (val[0] == 0) &&
4228 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4229 ctxt->error(ctxt->userData,
4230 "Attribute with QName 'xmlns' is not allowed\n",
4231 val);
4232 ctxt->nbErrors++;
4233 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004234 } else if (IS_RELAXNG(node, "anyName")) {
4235 ret->name = NULL;
4236 ret->ns = NULL;
4237 if (node->children != NULL) {
4238 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004239 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4240 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004241 }
4242 } else if (IS_RELAXNG(node, "nsName")) {
4243 ret->name = NULL;
4244 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4245 if (ret->ns == NULL) {
4246 if (ctxt->error != NULL)
4247 ctxt->error(ctxt->userData,
4248 "nsName has no ns attribute\n");
4249 ctxt->nbErrors++;
4250 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004251 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4252 (ret->ns != NULL) &&
4253 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4254 ctxt->error(ctxt->userData,
4255 "Attribute with namespace '%s' is not allowed\n",
4256 ret->ns);
4257 ctxt->nbErrors++;
4258 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004259 if (node->children != NULL) {
4260 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004261 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4262 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004263 }
4264 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004265 xmlNodePtr child;
4266 xmlRelaxNGDefinePtr last = NULL;
4267
4268 ret = xmlRelaxNGNewDefine(ctxt, node);
4269 if (ret == NULL)
4270 return(NULL);
4271 ret->parent = def;
4272 ret->type = XML_RELAXNG_CHOICE;
4273
Daniel Veillardd2298792003-02-14 16:54:11 +00004274 if (node->children == NULL) {
4275 if (ctxt->error != NULL)
4276 ctxt->error(ctxt->userData,
4277 "Element choice is empty\n");
4278 ctxt->nbErrors++;
4279 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004280
4281 child = node->children;
4282 while (child != NULL) {
4283 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4284 if (tmp != NULL) {
4285 if (last == NULL) {
4286 last = ret->nameClass = tmp;
4287 } else {
4288 last->next = tmp;
4289 last = tmp;
4290 }
4291 }
4292 child = child->next;
4293 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004294 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004295 } else {
4296 if (ctxt->error != NULL)
4297 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004298 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004299 node->name);
4300 ctxt->nbErrors++;
4301 return(NULL);
4302 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004303 if (ret != def) {
4304 if (def->nameClass == NULL) {
4305 def->nameClass = ret;
4306 } else {
4307 tmp = def->nameClass;
4308 while (tmp->next != NULL) {
4309 tmp = tmp->next;
4310 }
4311 tmp->next = ret;
4312 }
4313 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004314 return(ret);
4315}
4316
4317/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004318 * xmlRelaxNGParseElement:
4319 * @ctxt: a Relax-NG parser context
4320 * @node: the element node
4321 *
4322 * parse the content of a RelaxNG element node.
4323 *
4324 * Returns the definition pointer or NULL in case of error.
4325 */
4326static xmlRelaxNGDefinePtr
4327xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4328 xmlRelaxNGDefinePtr ret, cur, last;
4329 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004330 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004331
Daniel Veillardfd573f12003-03-16 17:52:32 +00004332 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004333 if (ret == NULL)
4334 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004335 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004336 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004337 child = node->children;
4338 if (child == NULL) {
4339 if (ctxt->error != NULL)
4340 ctxt->error(ctxt->userData,
4341 "xmlRelaxNGParseElement: element has no children\n");
4342 ctxt->nbErrors++;
4343 return(ret);
4344 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004345 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4346 if (cur != NULL)
4347 child = child->next;
4348
Daniel Veillard6eadf632003-01-23 18:29:16 +00004349 if (child == NULL) {
4350 if (ctxt->error != NULL)
4351 ctxt->error(ctxt->userData,
4352 "xmlRelaxNGParseElement: element has no content\n");
4353 ctxt->nbErrors++;
4354 return(ret);
4355 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004356 olddefine = ctxt->define;
4357 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004358 last = NULL;
4359 while (child != NULL) {
4360 cur = xmlRelaxNGParsePattern(ctxt, child);
4361 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004362 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004363 switch (cur->type) {
4364 case XML_RELAXNG_EMPTY:
4365 case XML_RELAXNG_NOT_ALLOWED:
4366 case XML_RELAXNG_TEXT:
4367 case XML_RELAXNG_ELEMENT:
4368 case XML_RELAXNG_DATATYPE:
4369 case XML_RELAXNG_VALUE:
4370 case XML_RELAXNG_LIST:
4371 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004372 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004373 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004374 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004375 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004376 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004377 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004378 case XML_RELAXNG_CHOICE:
4379 case XML_RELAXNG_GROUP:
4380 case XML_RELAXNG_INTERLEAVE:
4381 if (last == NULL) {
4382 ret->content = last = cur;
4383 } else {
4384 if ((last->type == XML_RELAXNG_ELEMENT) &&
4385 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004386 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004387 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004388 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004389 ret->content->content = last;
4390 } else {
4391 ret->content = last;
4392 }
4393 }
4394 last->next = cur;
4395 last = cur;
4396 }
4397 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004398 case XML_RELAXNG_ATTRIBUTE:
4399 cur->next = ret->attrs;
4400 ret->attrs = cur;
4401 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004402 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004403 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004404 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004405 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004406 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004407 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004408 case XML_RELAXNG_NOOP:
4409 TODO
4410 if (ctxt->error != NULL)
4411 ctxt->error(ctxt->userData,
4412 "Internal error, noop found\n");
4413 ctxt->nbErrors++;
4414 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004415 }
4416 }
4417 child = child->next;
4418 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004419 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004420 return(ret);
4421}
4422
4423/**
4424 * xmlRelaxNGParsePatterns:
4425 * @ctxt: a Relax-NG parser context
4426 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004427 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004428 *
4429 * parse the content of a RelaxNG start node.
4430 *
4431 * Returns the definition pointer or NULL in case of error.
4432 */
4433static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004434xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4435 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004436 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004437
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004438 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004439 while (nodes != NULL) {
4440 if (IS_RELAXNG(nodes, "element")) {
4441 cur = xmlRelaxNGParseElement(ctxt, nodes);
4442 if (def == NULL) {
4443 def = last = cur;
4444 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004445 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4446 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004447 def = xmlRelaxNGNewDefine(ctxt, nodes);
4448 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004449 def->content = last;
4450 }
4451 last->next = cur;
4452 last = cur;
4453 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004454 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004455 } else {
4456 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004457 if (cur != NULL) {
4458 if (def == NULL) {
4459 def = last = cur;
4460 } else {
4461 last->next = cur;
4462 last = cur;
4463 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004464 }
4465 }
4466 nodes = nodes->next;
4467 }
4468 return(def);
4469}
4470
4471/**
4472 * xmlRelaxNGParseStart:
4473 * @ctxt: a Relax-NG parser context
4474 * @nodes: start children nodes
4475 *
4476 * parse the content of a RelaxNG start node.
4477 *
4478 * Returns 0 in case of success, -1 in case of error
4479 */
4480static int
4481xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4482 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004483 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004484
Daniel Veillardd2298792003-02-14 16:54:11 +00004485 if (nodes == NULL) {
4486 if (ctxt->error != NULL)
4487 ctxt->error(ctxt->userData,
4488 "start has no children\n");
4489 ctxt->nbErrors++;
4490 return(-1);
4491 }
4492 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004493 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004494 if (def == NULL)
4495 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004496 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004497 if (nodes->children != NULL) {
4498 if (ctxt->error != NULL)
4499 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004500 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004501 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004502 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004503 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004504 if (def == NULL)
4505 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004506 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004507 if (nodes->children != NULL) {
4508 if (ctxt->error != NULL)
4509 ctxt->error(ctxt->userData,
4510 "element notAllowed is not empty\n");
4511 ctxt->nbErrors++;
4512 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004513 } else {
4514 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004515 }
4516 if (ctxt->grammar->start != NULL) {
4517 last = ctxt->grammar->start;
4518 while (last->next != NULL)
4519 last = last->next;
4520 last->next = def;
4521 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004522 ctxt->grammar->start = def;
4523 }
4524 nodes = nodes->next;
4525 if (nodes != NULL) {
4526 if (ctxt->error != NULL)
4527 ctxt->error(ctxt->userData,
4528 "start more than one children\n");
4529 ctxt->nbErrors++;
4530 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004531 }
4532 return(ret);
4533}
4534
4535/**
4536 * xmlRelaxNGParseGrammarContent:
4537 * @ctxt: a Relax-NG parser context
4538 * @nodes: grammar children nodes
4539 *
4540 * parse the content of a RelaxNG grammar node.
4541 *
4542 * Returns 0 in case of success, -1 in case of error
4543 */
4544static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004545xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004546{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004547 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004548
4549 if (nodes == NULL) {
4550 if (ctxt->error != NULL)
4551 ctxt->error(ctxt->userData,
4552 "grammar has no children\n");
4553 ctxt->nbErrors++;
4554 return(-1);
4555 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004556 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004557 if (IS_RELAXNG(nodes, "start")) {
4558 if (nodes->children == NULL) {
4559 if (ctxt->error != NULL)
4560 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004561 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004562 ctxt->nbErrors++;
4563 } else {
4564 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4565 if (tmp != 0)
4566 ret = -1;
4567 }
4568 } else if (IS_RELAXNG(nodes, "define")) {
4569 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4570 if (tmp != 0)
4571 ret = -1;
4572 } else if (IS_RELAXNG(nodes, "include")) {
4573 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4574 if (tmp != 0)
4575 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004576 } else {
4577 if (ctxt->error != NULL)
4578 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004579 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004580 ctxt->nbErrors++;
4581 ret = -1;
4582 }
4583 nodes = nodes->next;
4584 }
4585 return (ret);
4586}
4587
4588/**
4589 * xmlRelaxNGCheckReference:
4590 * @ref: the ref
4591 * @ctxt: a Relax-NG parser context
4592 * @name: the name associated to the defines
4593 *
4594 * Applies the 4.17. combine attribute rule for all the define
4595 * element of a given grammar using the same name.
4596 */
4597static void
4598xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4599 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4600 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004601 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004602
4603 grammar = ctxt->grammar;
4604 if (grammar == NULL) {
4605 if (ctxt->error != NULL)
4606 ctxt->error(ctxt->userData,
4607 "Internal error: no grammar in CheckReference %s\n",
4608 name);
4609 ctxt->nbErrors++;
4610 return;
4611 }
4612 if (ref->content != NULL) {
4613 if (ctxt->error != NULL)
4614 ctxt->error(ctxt->userData,
4615 "Internal error: reference has content in CheckReference %s\n",
4616 name);
4617 ctxt->nbErrors++;
4618 return;
4619 }
4620 if (grammar->defs != NULL) {
4621 def = xmlHashLookup(grammar->defs, name);
4622 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004623 cur = ref;
4624 while (cur != NULL) {
4625 cur->content = def;
4626 cur = cur->nextHash;
4627 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004628 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004629 if (ctxt->error != NULL)
4630 ctxt->error(ctxt->userData,
4631 "Reference %s has no matching definition\n",
4632 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004633 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004634 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004635 } else {
4636 if (ctxt->error != NULL)
4637 ctxt->error(ctxt->userData,
4638 "Reference %s has no matching definition\n",
4639 name);
4640 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004641 }
4642 /*
4643 * TODO: make a closure and verify there is no loop !
4644 */
4645}
4646
4647/**
4648 * xmlRelaxNGCheckCombine:
4649 * @define: the define(s) list
4650 * @ctxt: a Relax-NG parser context
4651 * @name: the name associated to the defines
4652 *
4653 * Applies the 4.17. combine attribute rule for all the define
4654 * element of a given grammar using the same name.
4655 */
4656static void
4657xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4658 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4659 xmlChar *combine;
4660 int choiceOrInterleave = -1;
4661 int missing = 0;
4662 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4663
4664 if (define->nextHash == NULL)
4665 return;
4666 cur = define;
4667 while (cur != NULL) {
4668 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4669 if (combine != NULL) {
4670 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4671 if (choiceOrInterleave == -1)
4672 choiceOrInterleave = 1;
4673 else if (choiceOrInterleave == 0) {
4674 if (ctxt->error != NULL)
4675 ctxt->error(ctxt->userData,
4676 "Defines for %s use both 'choice' and 'interleave'\n",
4677 name);
4678 ctxt->nbErrors++;
4679 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004680 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004681 if (choiceOrInterleave == -1)
4682 choiceOrInterleave = 0;
4683 else if (choiceOrInterleave == 1) {
4684 if (ctxt->error != NULL)
4685 ctxt->error(ctxt->userData,
4686 "Defines for %s use both 'choice' and 'interleave'\n",
4687 name);
4688 ctxt->nbErrors++;
4689 }
4690 } else {
4691 if (ctxt->error != NULL)
4692 ctxt->error(ctxt->userData,
4693 "Defines for %s use unknown combine value '%s''\n",
4694 name, combine);
4695 ctxt->nbErrors++;
4696 }
4697 xmlFree(combine);
4698 } else {
4699 if (missing == 0)
4700 missing = 1;
4701 else {
4702 if (ctxt->error != NULL)
4703 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004704 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004705 name);
4706 ctxt->nbErrors++;
4707 }
4708 }
4709
4710 cur = cur->nextHash;
4711 }
4712#ifdef DEBUG
4713 xmlGenericError(xmlGenericErrorContext,
4714 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4715 name, choiceOrInterleave);
4716#endif
4717 if (choiceOrInterleave == -1)
4718 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004719 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004720 if (cur == NULL)
4721 return;
4722 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004723 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004724 else
4725 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004726 tmp = define;
4727 last = NULL;
4728 while (tmp != NULL) {
4729 if (tmp->content != NULL) {
4730 if (tmp->content->next != NULL) {
4731 /*
4732 * we need first to create a wrapper.
4733 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00004734 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004735 if (tmp2 == NULL)
4736 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004737 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004738 tmp2->content = tmp->content;
4739 } else {
4740 tmp2 = tmp->content;
4741 }
4742 if (last == NULL) {
4743 cur->content = tmp2;
4744 } else {
4745 last->next = tmp2;
4746 }
4747 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004748 }
Daniel Veillard952379b2003-03-17 15:37:12 +00004749 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004750 tmp = tmp->nextHash;
4751 }
4752 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004753 if (choiceOrInterleave == 0) {
4754 if (ctxt->interleaves == NULL)
4755 ctxt->interleaves = xmlHashCreate(10);
4756 if (ctxt->interleaves == NULL) {
4757 if (ctxt->error != NULL)
4758 ctxt->error(ctxt->userData,
4759 "Failed to create interleaves hash table\n");
4760 ctxt->nbErrors++;
4761 } else {
4762 char tmpname[32];
4763
4764 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4765 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4766 if (ctxt->error != NULL)
4767 ctxt->error(ctxt->userData,
4768 "Failed to add %s to hash table\n", tmpname);
4769 ctxt->nbErrors++;
4770 }
4771 }
4772 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004773}
4774
4775/**
4776 * xmlRelaxNGCombineStart:
4777 * @ctxt: a Relax-NG parser context
4778 * @grammar: the grammar
4779 *
4780 * Applies the 4.17. combine rule for all the start
4781 * element of a given grammar.
4782 */
4783static void
4784xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
4785 xmlRelaxNGGrammarPtr grammar) {
4786 xmlRelaxNGDefinePtr starts;
4787 xmlChar *combine;
4788 int choiceOrInterleave = -1;
4789 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004790 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004791
Daniel Veillard2df2de22003-02-17 23:34:33 +00004792 starts = grammar->start;
4793 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00004794 return;
4795 cur = starts;
4796 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00004797 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
4798 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
4799 combine = NULL;
4800 if (ctxt->error != NULL)
4801 ctxt->error(ctxt->userData,
4802 "Internal error: start element not found\n");
4803 ctxt->nbErrors++;
4804 } else {
4805 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
4806 }
4807
Daniel Veillard6eadf632003-01-23 18:29:16 +00004808 if (combine != NULL) {
4809 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4810 if (choiceOrInterleave == -1)
4811 choiceOrInterleave = 1;
4812 else if (choiceOrInterleave == 0) {
4813 if (ctxt->error != NULL)
4814 ctxt->error(ctxt->userData,
4815 "<start> use both 'choice' and 'interleave'\n");
4816 ctxt->nbErrors++;
4817 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00004818 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004819 if (choiceOrInterleave == -1)
4820 choiceOrInterleave = 0;
4821 else if (choiceOrInterleave == 1) {
4822 if (ctxt->error != NULL)
4823 ctxt->error(ctxt->userData,
4824 "<start> use both 'choice' and 'interleave'\n");
4825 ctxt->nbErrors++;
4826 }
4827 } else {
4828 if (ctxt->error != NULL)
4829 ctxt->error(ctxt->userData,
4830 "<start> uses unknown combine value '%s''\n", combine);
4831 ctxt->nbErrors++;
4832 }
4833 xmlFree(combine);
4834 } else {
4835 if (missing == 0)
4836 missing = 1;
4837 else {
4838 if (ctxt->error != NULL)
4839 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004840 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00004841 ctxt->nbErrors++;
4842 }
4843 }
4844
Daniel Veillard2df2de22003-02-17 23:34:33 +00004845 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004846 }
4847#ifdef DEBUG
4848 xmlGenericError(xmlGenericErrorContext,
4849 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
4850 choiceOrInterleave);
4851#endif
4852 if (choiceOrInterleave == -1)
4853 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004854 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004855 if (cur == NULL)
4856 return;
4857 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004858 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004859 else
4860 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004861 cur->content = grammar->start;
4862 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004863 if (choiceOrInterleave == 0) {
4864 if (ctxt->interleaves == NULL)
4865 ctxt->interleaves = xmlHashCreate(10);
4866 if (ctxt->interleaves == NULL) {
4867 if (ctxt->error != NULL)
4868 ctxt->error(ctxt->userData,
4869 "Failed to create interleaves hash table\n");
4870 ctxt->nbErrors++;
4871 } else {
4872 char tmpname[32];
4873
4874 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4875 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4876 if (ctxt->error != NULL)
4877 ctxt->error(ctxt->userData,
4878 "Failed to add %s to hash table\n", tmpname);
4879 ctxt->nbErrors++;
4880 }
4881 }
4882 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004883}
4884
4885/**
Daniel Veillardd4310742003-02-18 21:12:46 +00004886 * xmlRelaxNGCheckCycles:
4887 * @ctxt: a Relax-NG parser context
4888 * @nodes: grammar children nodes
4889 * @depth: the counter
4890 *
4891 * Check for cycles.
4892 *
4893 * Returns 0 if check passed, and -1 in case of error
4894 */
4895static int
4896xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
4897 xmlRelaxNGDefinePtr cur, int depth) {
4898 int ret = 0;
4899
4900 while ((ret == 0) && (cur != NULL)) {
4901 if ((cur->type == XML_RELAXNG_REF) ||
4902 (cur->type == XML_RELAXNG_PARENTREF)) {
4903 if (cur->depth == -1) {
4904 cur->depth = depth;
4905 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4906 cur->depth = -2;
4907 } else if (depth == cur->depth) {
4908 if (ctxt->error != NULL)
4909 ctxt->error(ctxt->userData,
4910 "Detected a cycle in %s references\n", cur->name);
4911 ctxt->nbErrors++;
4912 return(-1);
4913 }
4914 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4915 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4916 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004917 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00004918 }
4919 cur = cur->next;
4920 }
4921 return(ret);
4922}
4923
4924/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00004925 * xmlRelaxNGTryUnlink:
4926 * @ctxt: a Relax-NG parser context
4927 * @cur: the definition to unlink
4928 * @parent: the parent definition
4929 * @prev: the previous sibling definition
4930 *
4931 * Try to unlink a definition. If not possble make it a NOOP
4932 *
4933 * Returns the new prev definition
4934 */
4935static xmlRelaxNGDefinePtr
4936xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4937 xmlRelaxNGDefinePtr cur,
4938 xmlRelaxNGDefinePtr parent,
4939 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004940 if (prev != NULL) {
4941 prev->next = cur->next;
4942 } else {
4943 if (parent != NULL) {
4944 if (parent->content == cur)
4945 parent->content = cur->next;
4946 else if (parent->attrs == cur)
4947 parent->attrs = cur->next;
4948 else if (parent->nameClass == cur)
4949 parent->nameClass = cur->next;
4950 } else {
4951 cur->type = XML_RELAXNG_NOOP;
4952 prev = cur;
4953 }
4954 }
4955 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004956}
4957
4958/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004959 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004960 * @ctxt: a Relax-NG parser context
4961 * @nodes: grammar children nodes
4962 *
4963 * Check for simplification of empty and notAllowed
4964 */
4965static void
4966xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4967 xmlRelaxNGDefinePtr cur,
4968 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004969 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004970
Daniel Veillardfd573f12003-03-16 17:52:32 +00004971 while (cur != NULL) {
4972 if ((cur->type == XML_RELAXNG_REF) ||
4973 (cur->type == XML_RELAXNG_PARENTREF)) {
4974 if (cur->depth != -3) {
4975 cur->depth = -3;
4976 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004977 }
4978 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004979 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004980 if ((parent != NULL) &&
4981 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4982 (parent->type == XML_RELAXNG_LIST) ||
4983 (parent->type == XML_RELAXNG_GROUP) ||
4984 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00004985 (parent->type == XML_RELAXNG_ONEORMORE) ||
4986 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004987 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004988 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004989 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004990 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00004991 (parent->type == XML_RELAXNG_CHOICE)) {
4992 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4993 } else
4994 prev = cur;
4995 } else if (cur->type == XML_RELAXNG_EMPTY){
4996 cur->parent = parent;
4997 if ((parent != NULL) &&
4998 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4999 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005000 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005001 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005002 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005003 if ((parent != NULL) &&
5004 ((parent->type == XML_RELAXNG_GROUP) ||
5005 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5006 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5007 } else
5008 prev = cur;
5009 } else {
5010 cur->parent = parent;
5011 if (cur->content != NULL)
5012 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5013 if (cur->attrs != NULL)
5014 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5015 if (cur->nameClass != NULL)
5016 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5017 /*
5018 * This may result in a simplification
5019 */
5020 if ((cur->type == XML_RELAXNG_GROUP) ||
5021 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5022 if (cur->content == NULL)
5023 cur->type = XML_RELAXNG_EMPTY;
5024 else if (cur->content->next == NULL) {
5025 if ((parent == NULL) && (prev == NULL)) {
5026 cur->type = XML_RELAXNG_NOOP;
5027 } else if (prev == NULL) {
5028 parent->content = cur->content;
5029 cur->content->next = cur->next;
5030 cur = cur->content;
5031 } else {
5032 cur->content->next = cur->next;
5033 prev->next = cur->content;
5034 cur = cur->content;
5035 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005036 }
5037 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005038 /*
5039 * the current node may have been transformed back
5040 */
5041 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5042 (cur->content != NULL) &&
5043 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5044 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5045 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5046 if ((parent != NULL) &&
5047 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5048 (parent->type == XML_RELAXNG_LIST) ||
5049 (parent->type == XML_RELAXNG_GROUP) ||
5050 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5051 (parent->type == XML_RELAXNG_ONEORMORE) ||
5052 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5053 parent->type = XML_RELAXNG_NOT_ALLOWED;
5054 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005055 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005056 if ((parent != NULL) &&
5057 (parent->type == XML_RELAXNG_CHOICE)) {
5058 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5059 } else
5060 prev = cur;
5061 } else if (cur->type == XML_RELAXNG_EMPTY){
5062 if ((parent != NULL) &&
5063 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5064 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5065 parent->type = XML_RELAXNG_EMPTY;
5066 break;
5067 }
5068 if ((parent != NULL) &&
5069 ((parent->type == XML_RELAXNG_GROUP) ||
5070 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5071 (parent->type == XML_RELAXNG_CHOICE))) {
5072 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5073 } else
5074 prev = cur;
5075 } else {
5076 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005077 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005078 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005079 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005080 }
5081}
5082
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005083/**
5084 * xmlRelaxNGGroupContentType:
5085 * @ct1: the first content type
5086 * @ct2: the second content type
5087 *
5088 * Try to group 2 content types
5089 *
5090 * Returns the content type
5091 */
5092static xmlRelaxNGContentType
5093xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5094 xmlRelaxNGContentType ct2) {
5095 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5096 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5097 return(XML_RELAXNG_CONTENT_ERROR);
5098 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5099 return(ct2);
5100 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5101 return(ct1);
5102 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5103 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5104 return(XML_RELAXNG_CONTENT_COMPLEX);
5105 return(XML_RELAXNG_CONTENT_ERROR);
5106}
5107
5108/**
5109 * xmlRelaxNGMaxContentType:
5110 * @ct1: the first content type
5111 * @ct2: the second content type
5112 *
5113 * Compute the max content-type
5114 *
5115 * Returns the content type
5116 */
5117static xmlRelaxNGContentType
5118xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5119 xmlRelaxNGContentType ct2) {
5120 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5121 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5122 return(XML_RELAXNG_CONTENT_ERROR);
5123 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5124 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5125 return(XML_RELAXNG_CONTENT_SIMPLE);
5126 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5127 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5128 return(XML_RELAXNG_CONTENT_COMPLEX);
5129 return(XML_RELAXNG_CONTENT_EMPTY);
5130}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005131
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005132/**
5133 * xmlRelaxNGCheckRules:
5134 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005135 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005136 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005137 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005138 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005139 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005140 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005141 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005142 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005143static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005144xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5145 xmlRelaxNGDefinePtr cur, int flags,
5146 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005147 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005148 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005149
Daniel Veillardfd573f12003-03-16 17:52:32 +00005150 while (cur != NULL) {
5151 ret = XML_RELAXNG_CONTENT_EMPTY;
5152 if ((cur->type == XML_RELAXNG_REF) ||
5153 (cur->type == XML_RELAXNG_PARENTREF)) {
5154 if (flags & XML_RELAXNG_IN_LIST) {
5155 if (ctxt->error != NULL)
5156 ctxt->error(ctxt->userData,
5157 "Found forbidden pattern list//ref\n");
5158 ctxt->nbErrors++;
5159 }
5160 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5161 if (ctxt->error != NULL)
5162 ctxt->error(ctxt->userData,
5163 "Found forbidden pattern data/except//ref\n");
5164 ctxt->nbErrors++;
5165 }
5166 if (cur->depth > -4) {
5167 cur->depth = -4;
5168 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5169 flags, cur->type);
5170 cur->depth = ret - 15 ;
5171 } else if (cur->depth == -4) {
5172 ret = XML_RELAXNG_CONTENT_COMPLEX;
5173 } else {
5174 ret = (xmlRelaxNGContentType) cur->depth + 15;
5175 }
5176 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5177 /*
5178 * The 7.3 Attribute derivation rule for groups is plugged there
5179 */
5180 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5181 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5182 if (ctxt->error != NULL)
5183 ctxt->error(ctxt->userData,
5184 "Found forbidden pattern data/except//element(ref)\n");
5185 ctxt->nbErrors++;
5186 }
5187 if (flags & XML_RELAXNG_IN_LIST) {
5188 if (ctxt->error != NULL)
5189 ctxt->error(ctxt->userData,
5190 "Found forbidden pattern list//element(ref)\n");
5191 ctxt->nbErrors++;
5192 }
5193 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5194 if (ctxt->error != NULL)
5195 ctxt->error(ctxt->userData,
5196 "Found forbidden pattern attribute//element(ref)\n");
5197 ctxt->nbErrors++;
5198 }
5199 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5200 if (ctxt->error != NULL)
5201 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005202 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005203 ctxt->nbErrors++;
5204 }
5205 /*
5206 * reset since in the simple form elements are only child
5207 * of grammar/define
5208 */
5209 nflags = 0;
5210 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5211 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5212 if (ctxt->error != NULL)
5213 ctxt->error(ctxt->userData,
5214 "Element %s attributes have a content type error\n",
5215 cur->name);
5216 ctxt->nbErrors++;
5217 }
5218 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5219 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5220 if (ctxt->error != NULL)
5221 ctxt->error(ctxt->userData,
5222 "Element %s has a content type error\n",
5223 cur->name);
5224 ctxt->nbErrors++;
5225 } else {
5226 ret = XML_RELAXNG_CONTENT_COMPLEX;
5227 }
5228 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5229 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5230 if (ctxt->error != NULL)
5231 ctxt->error(ctxt->userData,
5232 "Found forbidden pattern attribute//attribute\n");
5233 ctxt->nbErrors++;
5234 }
5235 if (flags & XML_RELAXNG_IN_LIST) {
5236 if (ctxt->error != NULL)
5237 ctxt->error(ctxt->userData,
5238 "Found forbidden pattern list//attribute\n");
5239 ctxt->nbErrors++;
5240 }
5241 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5242 if (ctxt->error != NULL)
5243 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005244 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005245 ctxt->nbErrors++;
5246 }
5247 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5248 if (ctxt->error != NULL)
5249 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005250 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005251 ctxt->nbErrors++;
5252 }
5253 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5254 if (ctxt->error != NULL)
5255 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005256 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005257 ctxt->nbErrors++;
5258 }
5259 if (flags & XML_RELAXNG_IN_START) {
5260 if (ctxt->error != NULL)
5261 ctxt->error(ctxt->userData,
5262 "Found forbidden pattern start//attribute\n");
5263 ctxt->nbErrors++;
5264 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005265 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5266 if (cur->ns == NULL) {
5267 if (ctxt->error != NULL)
5268 ctxt->error(ctxt->userData,
5269 "Found anyName attribute without oneOrMore ancestor\n");
5270 ctxt->nbErrors++;
5271 } else {
5272 if (ctxt->error != NULL)
5273 ctxt->error(ctxt->userData,
5274 "Found nsName attribute without oneOrMore ancestor\n");
5275 ctxt->nbErrors++;
5276 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005277 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005278 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5279 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5280 ret = XML_RELAXNG_CONTENT_EMPTY;
5281 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5282 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5283 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5284 if (ctxt->error != NULL)
5285 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005286 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005287 ctxt->nbErrors++;
5288 }
5289 if (flags & XML_RELAXNG_IN_START) {
5290 if (ctxt->error != NULL)
5291 ctxt->error(ctxt->userData,
5292 "Found forbidden pattern start//oneOrMore\n");
5293 ctxt->nbErrors++;
5294 }
5295 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5296 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5297 ret = xmlRelaxNGGroupContentType(ret, ret);
5298 } else if (cur->type == XML_RELAXNG_LIST) {
5299 if (flags & XML_RELAXNG_IN_LIST) {
5300 if (ctxt->error != NULL)
5301 ctxt->error(ctxt->userData,
5302 "Found forbidden pattern list//list\n");
5303 ctxt->nbErrors++;
5304 }
5305 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5306 if (ctxt->error != NULL)
5307 ctxt->error(ctxt->userData,
5308 "Found forbidden pattern data/except//list\n");
5309 ctxt->nbErrors++;
5310 }
5311 if (flags & XML_RELAXNG_IN_START) {
5312 if (ctxt->error != NULL)
5313 ctxt->error(ctxt->userData,
5314 "Found forbidden pattern start//list\n");
5315 ctxt->nbErrors++;
5316 }
5317 nflags = flags | XML_RELAXNG_IN_LIST;
5318 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5319 } else if (cur->type == XML_RELAXNG_GROUP) {
5320 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5321 if (ctxt->error != NULL)
5322 ctxt->error(ctxt->userData,
5323 "Found forbidden pattern data/except//group\n");
5324 ctxt->nbErrors++;
5325 }
5326 if (flags & XML_RELAXNG_IN_START) {
5327 if (ctxt->error != NULL)
5328 ctxt->error(ctxt->userData,
5329 "Found forbidden pattern start//group\n");
5330 ctxt->nbErrors++;
5331 }
5332 if (flags & XML_RELAXNG_IN_ONEORMORE)
5333 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5334 else
5335 nflags = flags;
5336 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5337 /*
5338 * The 7.3 Attribute derivation rule for groups is plugged there
5339 */
5340 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5341 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5342 if (flags & XML_RELAXNG_IN_LIST) {
5343 if (ctxt->error != NULL)
5344 ctxt->error(ctxt->userData,
5345 "Found forbidden pattern list//interleave\n");
5346 ctxt->nbErrors++;
5347 }
5348 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5349 if (ctxt->error != NULL)
5350 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005351 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005352 ctxt->nbErrors++;
5353 }
5354 if (flags & XML_RELAXNG_IN_START) {
5355 if (ctxt->error != NULL)
5356 ctxt->error(ctxt->userData,
5357 "Found forbidden pattern start//interleave\n");
5358 ctxt->nbErrors++;
5359 }
5360 if (flags & XML_RELAXNG_IN_ONEORMORE)
5361 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5362 else
5363 nflags = flags;
5364 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5365 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5366 if ((cur->parent != NULL) &&
5367 (cur->parent->type == XML_RELAXNG_DATATYPE))
5368 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5369 else
5370 nflags = flags;
5371 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5372 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5373 if (flags & XML_RELAXNG_IN_START) {
5374 if (ctxt->error != NULL)
5375 ctxt->error(ctxt->userData,
5376 "Found forbidden pattern start//data\n");
5377 ctxt->nbErrors++;
5378 }
5379 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5380 ret = XML_RELAXNG_CONTENT_SIMPLE;
5381 } else if (cur->type == XML_RELAXNG_VALUE) {
5382 if (flags & XML_RELAXNG_IN_START) {
5383 if (ctxt->error != NULL)
5384 ctxt->error(ctxt->userData,
5385 "Found forbidden pattern start//value\n");
5386 ctxt->nbErrors++;
5387 }
5388 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5389 ret = XML_RELAXNG_CONTENT_SIMPLE;
5390 } else if (cur->type == XML_RELAXNG_TEXT) {
5391 if (flags & XML_RELAXNG_IN_LIST) {
5392 if (ctxt->error != NULL)
5393 ctxt->error(ctxt->userData,
5394 "Found forbidden pattern list//text\n");
5395 ctxt->nbErrors++;
5396 }
5397 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5398 if (ctxt->error != NULL)
5399 ctxt->error(ctxt->userData,
5400 "Found forbidden pattern data/except//text\n");
5401 ctxt->nbErrors++;
5402 }
5403 if (flags & XML_RELAXNG_IN_START) {
5404 if (ctxt->error != NULL)
5405 ctxt->error(ctxt->userData,
5406 "Found forbidden pattern start//text\n");
5407 ctxt->nbErrors++;
5408 }
5409 ret = XML_RELAXNG_CONTENT_COMPLEX;
5410 } else if (cur->type == XML_RELAXNG_EMPTY) {
5411 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5412 if (ctxt->error != NULL)
5413 ctxt->error(ctxt->userData,
5414 "Found forbidden pattern data/except//empty\n");
5415 ctxt->nbErrors++;
5416 }
5417 if (flags & XML_RELAXNG_IN_START) {
5418 if (ctxt->error != NULL)
5419 ctxt->error(ctxt->userData,
5420 "Found forbidden pattern start//empty\n");
5421 ctxt->nbErrors++;
5422 }
5423 ret = XML_RELAXNG_CONTENT_EMPTY;
5424 } else if (cur->type == XML_RELAXNG_CHOICE) {
5425 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5426 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5427 } else {
5428 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5429 }
5430 cur = cur->next;
5431 if (ptype == XML_RELAXNG_GROUP) {
5432 val = xmlRelaxNGGroupContentType(val, ret);
5433 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5434 tmp = xmlRelaxNGGroupContentType(val, ret);
5435 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5436 tmp = xmlRelaxNGMaxContentType(val, ret);
5437 } else if (ptype == XML_RELAXNG_CHOICE) {
5438 val = xmlRelaxNGMaxContentType(val, ret);
5439 } else if (ptype == XML_RELAXNG_LIST) {
5440 val = XML_RELAXNG_CONTENT_SIMPLE;
5441 } else if (ptype == XML_RELAXNG_EXCEPT) {
5442 if (ret == XML_RELAXNG_CONTENT_ERROR)
5443 val = XML_RELAXNG_CONTENT_ERROR;
5444 else
5445 val = XML_RELAXNG_CONTENT_SIMPLE;
5446 } else {
5447 val = xmlRelaxNGGroupContentType(val, ret);
5448 }
5449
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005450 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005451 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005452}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005453
5454/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005455 * xmlRelaxNGParseGrammar:
5456 * @ctxt: a Relax-NG parser context
5457 * @nodes: grammar children nodes
5458 *
5459 * parse a Relax-NG <grammar> node
5460 *
5461 * Returns the internal xmlRelaxNGGrammarPtr built or
5462 * NULL in case of error
5463 */
5464static xmlRelaxNGGrammarPtr
5465xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5466 xmlRelaxNGGrammarPtr ret, tmp, old;
5467
Daniel Veillardc482e262003-02-26 14:48:48 +00005468#ifdef DEBUG_GRAMMAR
5469 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5470#endif
5471
Daniel Veillard6eadf632003-01-23 18:29:16 +00005472 ret = xmlRelaxNGNewGrammar(ctxt);
5473 if (ret == NULL)
5474 return(NULL);
5475
5476 /*
5477 * Link the new grammar in the tree
5478 */
5479 ret->parent = ctxt->grammar;
5480 if (ctxt->grammar != NULL) {
5481 tmp = ctxt->grammar->children;
5482 if (tmp == NULL) {
5483 ctxt->grammar->children = ret;
5484 } else {
5485 while (tmp->next != NULL)
5486 tmp = tmp->next;
5487 tmp->next = ret;
5488 }
5489 }
5490
5491 old = ctxt->grammar;
5492 ctxt->grammar = ret;
5493 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5494 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005495 if (ctxt->grammar == NULL) {
5496 if (ctxt->error != NULL)
5497 ctxt->error(ctxt->userData,
5498 "Failed to parse <grammar> content\n");
5499 ctxt->nbErrors++;
5500 } else if (ctxt->grammar->start == NULL) {
5501 if (ctxt->error != NULL)
5502 ctxt->error(ctxt->userData,
5503 "Element <grammar> has no <start>\n");
5504 ctxt->nbErrors++;
5505 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506
5507 /*
5508 * Apply 4.17 mergingd rules to defines and starts
5509 */
5510 xmlRelaxNGCombineStart(ctxt, ret);
5511 if (ret->defs != NULL) {
5512 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5513 ctxt);
5514 }
5515
5516 /*
5517 * link together defines and refs in this grammar
5518 */
5519 if (ret->refs != NULL) {
5520 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5521 ctxt);
5522 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005523
Daniel Veillard6eadf632003-01-23 18:29:16 +00005524 ctxt->grammar = old;
5525 return(ret);
5526}
5527
5528/**
5529 * xmlRelaxNGParseDocument:
5530 * @ctxt: a Relax-NG parser context
5531 * @node: the root node of the RelaxNG schema
5532 *
5533 * parse a Relax-NG definition resource and build an internal
5534 * xmlRelaxNG struture which can be used to validate instances.
5535 *
5536 * Returns the internal XML RelaxNG structure built or
5537 * NULL in case of error
5538 */
5539static xmlRelaxNGPtr
5540xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5541 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005542 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005543 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005544
5545 if ((ctxt == NULL) || (node == NULL))
5546 return (NULL);
5547
5548 schema = xmlRelaxNGNewRelaxNG(ctxt);
5549 if (schema == NULL)
5550 return(NULL);
5551
Daniel Veillard276be4a2003-01-24 01:03:34 +00005552 olddefine = ctxt->define;
5553 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005554 if (IS_RELAXNG(node, "grammar")) {
5555 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5556 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005557 xmlRelaxNGGrammarPtr tmp, ret;
5558
5559 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005560 if (schema->topgrammar == NULL) {
5561 return(schema);
5562 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005563 /*
5564 * Link the new grammar in the tree
5565 */
5566 ret->parent = ctxt->grammar;
5567 if (ctxt->grammar != NULL) {
5568 tmp = ctxt->grammar->children;
5569 if (tmp == NULL) {
5570 ctxt->grammar->children = ret;
5571 } else {
5572 while (tmp->next != NULL)
5573 tmp = tmp->next;
5574 tmp->next = ret;
5575 }
5576 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005577 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005578 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005579 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005580 if (old != NULL)
5581 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005582 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005583 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005584 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005585 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005586 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005587 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5588 while ((schema->topgrammar->start != NULL) &&
5589 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5590 (schema->topgrammar->start->next != NULL))
5591 schema->topgrammar->start = schema->topgrammar->start->content;
5592 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5593 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005594 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005595 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005596
5597#ifdef DEBUG
5598 if (schema == NULL)
5599 xmlGenericError(xmlGenericErrorContext,
5600 "xmlRelaxNGParseDocument() failed\n");
5601#endif
5602
5603 return (schema);
5604}
5605
5606/************************************************************************
5607 * *
5608 * Reading RelaxNGs *
5609 * *
5610 ************************************************************************/
5611
5612/**
5613 * xmlRelaxNGNewParserCtxt:
5614 * @URL: the location of the schema
5615 *
5616 * Create an XML RelaxNGs parse context for that file/resource expected
5617 * to contain an XML RelaxNGs file.
5618 *
5619 * Returns the parser context or NULL in case of error
5620 */
5621xmlRelaxNGParserCtxtPtr
5622xmlRelaxNGNewParserCtxt(const char *URL) {
5623 xmlRelaxNGParserCtxtPtr ret;
5624
5625 if (URL == NULL)
5626 return(NULL);
5627
5628 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5629 if (ret == NULL) {
5630 xmlGenericError(xmlGenericErrorContext,
5631 "Failed to allocate new schama parser context for %s\n", URL);
5632 return (NULL);
5633 }
5634 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5635 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005636 ret->error = xmlGenericError;
5637 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005638 return (ret);
5639}
5640
5641/**
5642 * xmlRelaxNGNewMemParserCtxt:
5643 * @buffer: a pointer to a char array containing the schemas
5644 * @size: the size of the array
5645 *
5646 * Create an XML RelaxNGs parse context for that memory buffer expected
5647 * to contain an XML RelaxNGs file.
5648 *
5649 * Returns the parser context or NULL in case of error
5650 */
5651xmlRelaxNGParserCtxtPtr
5652xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5653 xmlRelaxNGParserCtxtPtr ret;
5654
5655 if ((buffer == NULL) || (size <= 0))
5656 return(NULL);
5657
5658 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5659 if (ret == NULL) {
5660 xmlGenericError(xmlGenericErrorContext,
5661 "Failed to allocate new schama parser context\n");
5662 return (NULL);
5663 }
5664 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5665 ret->buffer = buffer;
5666 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005667 ret->error = xmlGenericError;
5668 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005669 return (ret);
5670}
5671
5672/**
5673 * xmlRelaxNGFreeParserCtxt:
5674 * @ctxt: the schema parser context
5675 *
5676 * Free the resources associated to the schema parser context
5677 */
5678void
5679xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5680 if (ctxt == NULL)
5681 return;
5682 if (ctxt->URL != NULL)
5683 xmlFree(ctxt->URL);
5684 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005685 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005686 if (ctxt->interleaves != NULL)
5687 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005688 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005689 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005690 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005691 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005692 if (ctxt->docTab != NULL)
5693 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005694 if (ctxt->incTab != NULL)
5695 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005696 if (ctxt->defTab != NULL) {
5697 int i;
5698
5699 for (i = 0;i < ctxt->defNr;i++)
5700 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5701 xmlFree(ctxt->defTab);
5702 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005703 xmlFree(ctxt);
5704}
5705
Daniel Veillard6eadf632003-01-23 18:29:16 +00005706/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005707 * xmlRelaxNGNormExtSpace:
5708 * @value: a value
5709 *
5710 * Removes the leading and ending spaces of the value
5711 * The string is modified "in situ"
5712 */
5713static void
5714xmlRelaxNGNormExtSpace(xmlChar *value) {
5715 xmlChar *start = value;
5716 xmlChar *cur = value;
5717 if (value == NULL)
5718 return;
5719
5720 while (IS_BLANK(*cur)) cur++;
5721 if (cur == start) {
5722 do {
5723 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5724 if (*cur == 0)
5725 return;
5726 start = cur;
5727 while (IS_BLANK(*cur)) cur++;
5728 if (*cur == 0) {
5729 *start = 0;
5730 return;
5731 }
5732 } while (1);
5733 } else {
5734 do {
5735 while ((*cur != 0) && (!IS_BLANK(*cur)))
5736 *start++ = *cur++;
5737 if (*cur == 0) {
5738 *start = 0;
5739 return;
5740 }
5741 /* don't try to normalize the inner spaces */
5742 while (IS_BLANK(*cur)) cur++;
5743 *start++ = *cur++;
5744 if (*cur == 0) {
5745 *start = 0;
5746 return;
5747 }
5748 } while (1);
5749 }
5750}
5751
5752/**
5753 * xmlRelaxNGCheckAttributes:
5754 * @ctxt: a Relax-NG parser context
5755 * @node: a Relax-NG node
5756 *
5757 * Check all the attributes on the given node
5758 */
5759static void
5760xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5761 xmlAttrPtr cur, next;
5762
5763 cur = node->properties;
5764 while (cur != NULL) {
5765 next = cur->next;
5766 if ((cur->ns == NULL) ||
5767 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5768 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5769 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5770 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5771 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5772 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005773 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005774 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5775 if (ctxt->error != NULL)
5776 ctxt->error(ctxt->userData,
5777 "Attribute %s is not allowed on %s\n",
5778 cur->name, node->name);
5779 ctxt->nbErrors++;
5780 }
5781 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5782 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5783 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5784 if (ctxt->error != NULL)
5785 ctxt->error(ctxt->userData,
5786 "Attribute %s is not allowed on %s\n",
5787 cur->name, node->name);
5788 ctxt->nbErrors++;
5789 }
5790 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
5791 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
5792 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
5793 if (ctxt->error != NULL)
5794 ctxt->error(ctxt->userData,
5795 "Attribute %s is not allowed on %s\n",
5796 cur->name, node->name);
5797 ctxt->nbErrors++;
5798 }
5799 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
5800 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
5801 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5802 if (ctxt->error != NULL)
5803 ctxt->error(ctxt->userData,
5804 "Attribute %s is not allowed on %s\n",
5805 cur->name, node->name);
5806 ctxt->nbErrors++;
5807 }
5808 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
5809 xmlChar *val;
5810 xmlURIPtr uri;
5811
5812 val = xmlNodeListGetString(node->doc, cur->children, 1);
5813 if (val != NULL) {
5814 if (val[0] != 0) {
5815 uri = xmlParseURI((const char *) val);
5816 if (uri == NULL) {
5817 if (ctxt->error != NULL)
5818 ctxt->error(ctxt->userData,
5819 "Attribute %s contains invalid URI %s\n",
5820 cur->name, val);
5821 ctxt->nbErrors++;
5822 } else {
5823 if (uri->scheme == NULL) {
5824 if (ctxt->error != NULL)
5825 ctxt->error(ctxt->userData,
5826 "Attribute %s URI %s is not absolute\n",
5827 cur->name, val);
5828 ctxt->nbErrors++;
5829 }
5830 if (uri->fragment != NULL) {
5831 if (ctxt->error != NULL)
5832 ctxt->error(ctxt->userData,
5833 "Attribute %s URI %s has a fragment ID\n",
5834 cur->name, val);
5835 ctxt->nbErrors++;
5836 }
5837 xmlFreeURI(uri);
5838 }
5839 }
5840 xmlFree(val);
5841 }
5842 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
5843 if (ctxt->error != NULL)
5844 ctxt->error(ctxt->userData,
5845 "Unknown attribute %s on %s\n",
5846 cur->name, node->name);
5847 ctxt->nbErrors++;
5848 }
5849 }
5850 cur = next;
5851 }
5852}
5853
5854/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00005855 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005856 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00005857 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00005858 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00005859 * Cleanup the subtree from unwanted nodes for parsing, resolve
5860 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00005861 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005862static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00005863xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00005864 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005865
Daniel Veillard6eadf632003-01-23 18:29:16 +00005866 delete = NULL;
5867 cur = root;
5868 while (cur != NULL) {
5869 if (delete != NULL) {
5870 xmlUnlinkNode(delete);
5871 xmlFreeNode(delete);
5872 delete = NULL;
5873 }
5874 if (cur->type == XML_ELEMENT_NODE) {
5875 /*
5876 * Simplification 4.1. Annotations
5877 */
5878 if ((cur->ns == NULL) ||
5879 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00005880 if ((cur->parent != NULL) &&
5881 (cur->parent->type == XML_ELEMENT_NODE) &&
5882 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
5883 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
5884 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
5885 if (ctxt->error != NULL)
5886 ctxt->error(ctxt->userData,
5887 "element %s doesn't allow foreign elements\n",
5888 cur->parent->name);
5889 ctxt->nbErrors++;
5890 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005891 delete = cur;
5892 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005893 } else {
5894 xmlRelaxNGCleanupAttributes(ctxt, cur);
5895 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
5896 xmlChar *href, *ns, *base, *URL;
5897 xmlRelaxNGDocumentPtr docu;
5898 xmlNodePtr tmp;
5899
5900 ns = xmlGetProp(cur, BAD_CAST "ns");
5901 if (ns == NULL) {
5902 tmp = cur->parent;
5903 while ((tmp != NULL) &&
5904 (tmp->type == XML_ELEMENT_NODE)) {
5905 ns = xmlGetProp(tmp, BAD_CAST "ns");
5906 if (ns != NULL)
5907 break;
5908 tmp = tmp->parent;
5909 }
5910 }
5911 href = xmlGetProp(cur, BAD_CAST "href");
5912 if (href == NULL) {
5913 if (ctxt->error != NULL)
5914 ctxt->error(ctxt->userData,
5915 "xmlRelaxNGParse: externalRef has no href attribute\n");
5916 ctxt->nbErrors++;
5917 delete = cur;
5918 goto skip_children;
5919 }
5920 base = xmlNodeGetBase(cur->doc, cur);
5921 URL = xmlBuildURI(href, base);
5922 if (URL == NULL) {
5923 if (ctxt->error != NULL)
5924 ctxt->error(ctxt->userData,
5925 "Failed to compute URL for externalRef %s\n", href);
5926 ctxt->nbErrors++;
5927 if (href != NULL)
5928 xmlFree(href);
5929 if (base != NULL)
5930 xmlFree(base);
5931 delete = cur;
5932 goto skip_children;
5933 }
5934 if (href != NULL)
5935 xmlFree(href);
5936 if (base != NULL)
5937 xmlFree(base);
5938 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
5939 if (docu == NULL) {
5940 if (ctxt->error != NULL)
5941 ctxt->error(ctxt->userData,
5942 "Failed to load externalRef %s\n", URL);
5943 ctxt->nbErrors++;
5944 xmlFree(URL);
5945 delete = cur;
5946 goto skip_children;
5947 }
5948 if (ns != NULL)
5949 xmlFree(ns);
5950 xmlFree(URL);
5951 cur->_private = docu;
5952 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5953 xmlChar *href, *ns, *base, *URL;
5954 xmlRelaxNGIncludePtr incl;
5955 xmlNodePtr tmp;
5956
5957 href = xmlGetProp(cur, BAD_CAST "href");
5958 if (href == NULL) {
5959 if (ctxt->error != NULL)
5960 ctxt->error(ctxt->userData,
5961 "xmlRelaxNGParse: include has no href attribute\n");
5962 ctxt->nbErrors++;
5963 delete = cur;
5964 goto skip_children;
5965 }
5966 base = xmlNodeGetBase(cur->doc, cur);
5967 URL = xmlBuildURI(href, base);
5968 if (URL == NULL) {
5969 if (ctxt->error != NULL)
5970 ctxt->error(ctxt->userData,
5971 "Failed to compute URL for include %s\n", href);
5972 ctxt->nbErrors++;
5973 if (href != NULL)
5974 xmlFree(href);
5975 if (base != NULL)
5976 xmlFree(base);
5977 delete = cur;
5978 goto skip_children;
5979 }
5980 if (href != NULL)
5981 xmlFree(href);
5982 if (base != NULL)
5983 xmlFree(base);
5984 ns = xmlGetProp(cur, BAD_CAST "ns");
5985 if (ns == NULL) {
5986 tmp = cur->parent;
5987 while ((tmp != NULL) &&
5988 (tmp->type == XML_ELEMENT_NODE)) {
5989 ns = xmlGetProp(tmp, BAD_CAST "ns");
5990 if (ns != NULL)
5991 break;
5992 tmp = tmp->parent;
5993 }
5994 }
5995 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5996 if (ns != NULL)
5997 xmlFree(ns);
5998 if (incl == NULL) {
5999 if (ctxt->error != NULL)
6000 ctxt->error(ctxt->userData,
6001 "Failed to load include %s\n", URL);
6002 ctxt->nbErrors++;
6003 xmlFree(URL);
6004 delete = cur;
6005 goto skip_children;
6006 }
6007 xmlFree(URL);
6008 cur->_private = incl;
6009 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6010 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6011 xmlChar *name, *ns;
6012 xmlNodePtr text = NULL;
6013
6014 /*
6015 * Simplification 4.8. name attribute of element
6016 * and attribute elements
6017 */
6018 name = xmlGetProp(cur, BAD_CAST "name");
6019 if (name != NULL) {
6020 if (cur->children == NULL) {
6021 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6022 name);
6023 } else {
6024 xmlNodePtr node;
6025 node = xmlNewNode(cur->ns, BAD_CAST "name");
6026 if (node != NULL) {
6027 xmlAddPrevSibling(cur->children, node);
6028 text = xmlNewText(name);
6029 xmlAddChild(node, text);
6030 text = node;
6031 }
6032 }
6033 if (text == NULL) {
6034 if (ctxt->error != NULL)
6035 ctxt->error(ctxt->userData,
6036 "Failed to create a name %s element\n", name);
6037 ctxt->nbErrors++;
6038 }
6039 xmlUnsetProp(cur, BAD_CAST "name");
6040 xmlFree(name);
6041 ns = xmlGetProp(cur, BAD_CAST "ns");
6042 if (ns != NULL) {
6043 if (text != NULL) {
6044 xmlSetProp(text, BAD_CAST "ns", ns);
6045 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6046 }
6047 xmlFree(ns);
6048 } else if (xmlStrEqual(cur->name,
6049 BAD_CAST "attribute")) {
6050 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6051 }
6052 }
6053 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6054 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6055 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6056 /*
6057 * Simplification 4.8. name attribute of element
6058 * and attribute elements
6059 */
6060 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6061 xmlNodePtr node;
6062 xmlChar *ns = NULL;
6063
6064 node = cur->parent;
6065 while ((node != NULL) &&
6066 (node->type == XML_ELEMENT_NODE)) {
6067 ns = xmlGetProp(node, BAD_CAST "ns");
6068 if (ns != NULL) {
6069 break;
6070 }
6071 node = node->parent;
6072 }
6073 if (ns == NULL) {
6074 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6075 } else {
6076 xmlSetProp(cur, BAD_CAST "ns", ns);
6077 xmlFree(ns);
6078 }
6079 }
6080 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6081 xmlChar *name, *local, *prefix;
6082
6083 /*
6084 * Simplification: 4.10. QNames
6085 */
6086 name = xmlNodeGetContent(cur);
6087 if (name != NULL) {
6088 local = xmlSplitQName2(name, &prefix);
6089 if (local != NULL) {
6090 xmlNsPtr ns;
6091
6092 ns = xmlSearchNs(cur->doc, cur, prefix);
6093 if (ns == NULL) {
6094 if (ctxt->error != NULL)
6095 ctxt->error(ctxt->userData,
6096 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6097 ctxt->nbErrors++;
6098 } else {
6099 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6100 xmlNodeSetContent(cur, local);
6101 }
6102 xmlFree(local);
6103 xmlFree(prefix);
6104 }
6105 xmlFree(name);
6106 }
6107 }
6108 /*
6109 * 4.16
6110 */
6111 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6112 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6113 if (ctxt->error != NULL)
6114 ctxt->error(ctxt->userData,
6115 "Found nsName/except//nsName forbidden construct\n");
6116 ctxt->nbErrors++;
6117 }
6118 }
6119 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6120 (cur != root)) {
6121 int oldflags = ctxt->flags;
6122
6123 /*
6124 * 4.16
6125 */
6126 if ((cur->parent != NULL) &&
6127 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6128 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6129 xmlRelaxNGCleanupTree(ctxt, cur);
6130 ctxt->flags = oldflags;
6131 goto skip_children;
6132 } else if ((cur->parent != NULL) &&
6133 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6134 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6135 xmlRelaxNGCleanupTree(ctxt, cur);
6136 ctxt->flags = oldflags;
6137 goto skip_children;
6138 }
6139 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6140 /*
6141 * 4.16
6142 */
6143 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6144 if (ctxt->error != NULL)
6145 ctxt->error(ctxt->userData,
6146 "Found anyName/except//anyName forbidden construct\n");
6147 ctxt->nbErrors++;
6148 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6149 if (ctxt->error != NULL)
6150 ctxt->error(ctxt->userData,
6151 "Found nsName/except//anyName forbidden construct\n");
6152 ctxt->nbErrors++;
6153 }
6154 }
6155 /*
6156 * Thisd is not an else since "include" is transformed
6157 * into a div
6158 */
6159 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6160 xmlChar *ns;
6161 xmlNodePtr child, ins, tmp;
6162
6163 /*
6164 * implements rule 4.11
6165 */
6166
6167 ns = xmlGetProp(cur, BAD_CAST "ns");
6168
6169 child = cur->children;
6170 ins = cur;
6171 while (child != NULL) {
6172 if (ns != NULL) {
6173 if (!xmlHasProp(child, BAD_CAST "ns")) {
6174 xmlSetProp(child, BAD_CAST "ns", ns);
6175 }
6176 }
6177 tmp = child->next;
6178 xmlUnlinkNode(child);
6179 ins = xmlAddNextSibling(ins, child);
6180 child = tmp;
6181 }
6182 if (ns != NULL)
6183 xmlFree(ns);
6184 delete = cur;
6185 goto skip_children;
6186 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006187 }
6188 }
6189 /*
6190 * Simplification 4.2 whitespaces
6191 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006192 else if ((cur->type == XML_TEXT_NODE) ||
6193 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006194 if (IS_BLANK_NODE(cur)) {
6195 if (cur->parent->type == XML_ELEMENT_NODE) {
6196 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6197 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6198 delete = cur;
6199 } else {
6200 delete = cur;
6201 goto skip_children;
6202 }
6203 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006204 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006205 delete = cur;
6206 goto skip_children;
6207 }
6208
6209 /*
6210 * Skip to next node
6211 */
6212 if (cur->children != NULL) {
6213 if ((cur->children->type != XML_ENTITY_DECL) &&
6214 (cur->children->type != XML_ENTITY_REF_NODE) &&
6215 (cur->children->type != XML_ENTITY_NODE)) {
6216 cur = cur->children;
6217 continue;
6218 }
6219 }
6220skip_children:
6221 if (cur->next != NULL) {
6222 cur = cur->next;
6223 continue;
6224 }
6225
6226 do {
6227 cur = cur->parent;
6228 if (cur == NULL)
6229 break;
6230 if (cur == root) {
6231 cur = NULL;
6232 break;
6233 }
6234 if (cur->next != NULL) {
6235 cur = cur->next;
6236 break;
6237 }
6238 } while (cur != NULL);
6239 }
6240 if (delete != NULL) {
6241 xmlUnlinkNode(delete);
6242 xmlFreeNode(delete);
6243 delete = NULL;
6244 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006245}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006246
Daniel Veillardc5312d72003-02-21 17:14:10 +00006247/**
6248 * xmlRelaxNGCleanupDoc:
6249 * @ctxt: a Relax-NG parser context
6250 * @doc: an xmldocPtr document pointer
6251 *
6252 * Cleanup the document from unwanted nodes for parsing, resolve
6253 * Include and externalRef lookups.
6254 *
6255 * Returns the cleaned up document or NULL in case of error
6256 */
6257static xmlDocPtr
6258xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6259 xmlNodePtr root;
6260
6261 /*
6262 * Extract the root
6263 */
6264 root = xmlDocGetRootElement(doc);
6265 if (root == NULL) {
6266 if (ctxt->error != NULL)
6267 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6268 ctxt->URL);
6269 ctxt->nbErrors++;
6270 return (NULL);
6271 }
6272 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006273 return(doc);
6274}
6275
6276/**
6277 * xmlRelaxNGParse:
6278 * @ctxt: a Relax-NG parser context
6279 *
6280 * parse a schema definition resource and build an internal
6281 * XML Shema struture which can be used to validate instances.
6282 * *WARNING* this interface is highly subject to change
6283 *
6284 * Returns the internal XML RelaxNG structure built from the resource or
6285 * NULL in case of error
6286 */
6287xmlRelaxNGPtr
6288xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6289{
6290 xmlRelaxNGPtr ret = NULL;
6291 xmlDocPtr doc;
6292 xmlNodePtr root;
6293
6294 xmlRelaxNGInitTypes();
6295
6296 if (ctxt == NULL)
6297 return (NULL);
6298
6299 /*
6300 * First step is to parse the input document into an DOM/Infoset
6301 */
6302 if (ctxt->URL != NULL) {
6303 doc = xmlParseFile((const char *) ctxt->URL);
6304 if (doc == NULL) {
6305 if (ctxt->error != NULL)
6306 ctxt->error(ctxt->userData,
6307 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6308 ctxt->nbErrors++;
6309 return (NULL);
6310 }
6311 } else if (ctxt->buffer != NULL) {
6312 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6313 if (doc == NULL) {
6314 if (ctxt->error != NULL)
6315 ctxt->error(ctxt->userData,
6316 "xmlRelaxNGParse: could not parse schemas\n");
6317 ctxt->nbErrors++;
6318 return (NULL);
6319 }
6320 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6321 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6322 } else {
6323 if (ctxt->error != NULL)
6324 ctxt->error(ctxt->userData,
6325 "xmlRelaxNGParse: nothing to parse\n");
6326 ctxt->nbErrors++;
6327 return (NULL);
6328 }
6329 ctxt->document = doc;
6330
6331 /*
6332 * Some preprocessing of the document content
6333 */
6334 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6335 if (doc == NULL) {
6336 xmlFreeDoc(ctxt->document);
6337 ctxt->document = NULL;
6338 return(NULL);
6339 }
6340
Daniel Veillard6eadf632003-01-23 18:29:16 +00006341 /*
6342 * Then do the parsing for good
6343 */
6344 root = xmlDocGetRootElement(doc);
6345 if (root == NULL) {
6346 if (ctxt->error != NULL)
6347 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6348 ctxt->URL);
6349 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006350 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006351 return (NULL);
6352 }
6353 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006354 if (ret == NULL) {
6355 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006356 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006357 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006358
6359 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006360 * Check the ref/defines links
6361 */
6362 /*
6363 * try to preprocess interleaves
6364 */
6365 if (ctxt->interleaves != NULL) {
6366 xmlHashScan(ctxt->interleaves,
6367 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6368 }
6369
6370 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006371 * if there was a parsing error return NULL
6372 */
6373 if (ctxt->nbErrors > 0) {
6374 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006375 ctxt->document = NULL;
6376 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006377 return(NULL);
6378 }
6379
6380 /*
6381 * Transfer the pointer for cleanup at the schema level.
6382 */
6383 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006384 ctxt->document = NULL;
6385 ret->documents = ctxt->documents;
6386 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006387
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006388 ret->includes = ctxt->includes;
6389 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006390 ret->defNr = ctxt->defNr;
6391 ret->defTab = ctxt->defTab;
6392 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006393 if (ctxt->idref == 1)
6394 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006395
6396 return (ret);
6397}
6398
6399/**
6400 * xmlRelaxNGSetParserErrors:
6401 * @ctxt: a Relax-NG validation context
6402 * @err: the error callback
6403 * @warn: the warning callback
6404 * @ctx: contextual data for the callbacks
6405 *
6406 * Set the callback functions used to handle errors for a validation context
6407 */
6408void
6409xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6410 xmlRelaxNGValidityErrorFunc err,
6411 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6412 if (ctxt == NULL)
6413 return;
6414 ctxt->error = err;
6415 ctxt->warning = warn;
6416 ctxt->userData = ctx;
6417}
6418/************************************************************************
6419 * *
6420 * Dump back a compiled form *
6421 * *
6422 ************************************************************************/
6423static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6424
6425/**
6426 * xmlRelaxNGDumpDefines:
6427 * @output: the file output
6428 * @defines: a list of define structures
6429 *
6430 * Dump a RelaxNG structure back
6431 */
6432static void
6433xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6434 while (defines != NULL) {
6435 xmlRelaxNGDumpDefine(output, defines);
6436 defines = defines->next;
6437 }
6438}
6439
6440/**
6441 * xmlRelaxNGDumpDefine:
6442 * @output: the file output
6443 * @define: a define structure
6444 *
6445 * Dump a RelaxNG structure back
6446 */
6447static void
6448xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6449 if (define == NULL)
6450 return;
6451 switch(define->type) {
6452 case XML_RELAXNG_EMPTY:
6453 fprintf(output, "<empty/>\n");
6454 break;
6455 case XML_RELAXNG_NOT_ALLOWED:
6456 fprintf(output, "<notAllowed/>\n");
6457 break;
6458 case XML_RELAXNG_TEXT:
6459 fprintf(output, "<text/>\n");
6460 break;
6461 case XML_RELAXNG_ELEMENT:
6462 fprintf(output, "<element>\n");
6463 if (define->name != NULL) {
6464 fprintf(output, "<name");
6465 if (define->ns != NULL)
6466 fprintf(output, " ns=\"%s\"", define->ns);
6467 fprintf(output, ">%s</name>\n", define->name);
6468 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006469 xmlRelaxNGDumpDefines(output, define->attrs);
6470 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006471 fprintf(output, "</element>\n");
6472 break;
6473 case XML_RELAXNG_LIST:
6474 fprintf(output, "<list>\n");
6475 xmlRelaxNGDumpDefines(output, define->content);
6476 fprintf(output, "</list>\n");
6477 break;
6478 case XML_RELAXNG_ONEORMORE:
6479 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006480 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006481 fprintf(output, "</oneOrMore>\n");
6482 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006483 case XML_RELAXNG_ZEROORMORE:
6484 fprintf(output, "<zeroOrMore>\n");
6485 xmlRelaxNGDumpDefines(output, define->content);
6486 fprintf(output, "</zeroOrMore>\n");
6487 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006488 case XML_RELAXNG_CHOICE:
6489 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006490 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006491 fprintf(output, "</choice>\n");
6492 break;
6493 case XML_RELAXNG_GROUP:
6494 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006495 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006496 fprintf(output, "</group>\n");
6497 break;
6498 case XML_RELAXNG_INTERLEAVE:
6499 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006500 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006501 fprintf(output, "</interleave>\n");
6502 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006503 case XML_RELAXNG_OPTIONAL:
6504 fprintf(output, "<optional>\n");
6505 xmlRelaxNGDumpDefines(output, define->content);
6506 fprintf(output, "</optional>\n");
6507 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508 case XML_RELAXNG_ATTRIBUTE:
6509 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006510 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006511 fprintf(output, "</attribute>\n");
6512 break;
6513 case XML_RELAXNG_DEF:
6514 fprintf(output, "<define");
6515 if (define->name != NULL)
6516 fprintf(output, " name=\"%s\"", define->name);
6517 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006518 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006519 fprintf(output, "</define>\n");
6520 break;
6521 case XML_RELAXNG_REF:
6522 fprintf(output, "<ref");
6523 if (define->name != NULL)
6524 fprintf(output, " name=\"%s\"", define->name);
6525 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006526 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006527 fprintf(output, "</ref>\n");
6528 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006529 case XML_RELAXNG_PARENTREF:
6530 fprintf(output, "<parentRef");
6531 if (define->name != NULL)
6532 fprintf(output, " name=\"%s\"", define->name);
6533 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006534 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006535 fprintf(output, "</parentRef>\n");
6536 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006537 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006538 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006539 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006540 fprintf(output, "</externalRef>\n");
6541 break;
6542 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006543 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006544 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006545 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006546 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006547 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006548 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006549 TODO
6550 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006551 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006552 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006553 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006554 }
6555}
6556
6557/**
6558 * xmlRelaxNGDumpGrammar:
6559 * @output: the file output
6560 * @grammar: a grammar structure
6561 * @top: is this a top grammar
6562 *
6563 * Dump a RelaxNG structure back
6564 */
6565static void
6566xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6567{
6568 if (grammar == NULL)
6569 return;
6570
6571 fprintf(output, "<grammar");
6572 if (top)
6573 fprintf(output,
6574 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6575 switch(grammar->combine) {
6576 case XML_RELAXNG_COMBINE_UNDEFINED:
6577 break;
6578 case XML_RELAXNG_COMBINE_CHOICE:
6579 fprintf(output, " combine=\"choice\"");
6580 break;
6581 case XML_RELAXNG_COMBINE_INTERLEAVE:
6582 fprintf(output, " combine=\"interleave\"");
6583 break;
6584 default:
6585 fprintf(output, " <!-- invalid combine value -->");
6586 }
6587 fprintf(output, ">\n");
6588 if (grammar->start == NULL) {
6589 fprintf(output, " <!-- grammar had no start -->");
6590 } else {
6591 fprintf(output, "<start>\n");
6592 xmlRelaxNGDumpDefine(output, grammar->start);
6593 fprintf(output, "</start>\n");
6594 }
6595 /* TODO ? Dump the defines ? */
6596 fprintf(output, "</grammar>\n");
6597}
6598
6599/**
6600 * xmlRelaxNGDump:
6601 * @output: the file output
6602 * @schema: a schema structure
6603 *
6604 * Dump a RelaxNG structure back
6605 */
6606void
6607xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6608{
6609 if (schema == NULL) {
6610 fprintf(output, "RelaxNG empty or failed to compile\n");
6611 return;
6612 }
6613 fprintf(output, "RelaxNG: ");
6614 if (schema->doc == NULL) {
6615 fprintf(output, "no document\n");
6616 } else if (schema->doc->URL != NULL) {
6617 fprintf(output, "%s\n", schema->doc->URL);
6618 } else {
6619 fprintf(output, "\n");
6620 }
6621 if (schema->topgrammar == NULL) {
6622 fprintf(output, "RelaxNG has no top grammar\n");
6623 return;
6624 }
6625 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6626}
6627
Daniel Veillardfebcca42003-02-16 15:44:18 +00006628/**
6629 * xmlRelaxNGDumpTree:
6630 * @output: the file output
6631 * @schema: a schema structure
6632 *
6633 * Dump the transformed RelaxNG tree.
6634 */
6635void
6636xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6637{
6638 if (schema == NULL) {
6639 fprintf(output, "RelaxNG empty or failed to compile\n");
6640 return;
6641 }
6642 if (schema->doc == NULL) {
6643 fprintf(output, "no document\n");
6644 } else {
6645 xmlDocDump(output, schema->doc);
6646 }
6647}
6648
Daniel Veillard6eadf632003-01-23 18:29:16 +00006649/************************************************************************
6650 * *
6651 * Validation implementation *
6652 * *
6653 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006654static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6655 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006656static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6657 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006658
6659/**
6660 * xmlRelaxNGSkipIgnored:
6661 * @ctxt: a schema validation context
6662 * @node: the top node.
6663 *
6664 * Skip ignorable nodes in that context
6665 *
6666 * Returns the new sibling or NULL in case of error.
6667 */
6668static xmlNodePtr
6669xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6670 xmlNodePtr node) {
6671 /*
6672 * TODO complete and handle entities
6673 */
6674 while ((node != NULL) &&
6675 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006676 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006677 (((node->type == XML_TEXT_NODE) ||
6678 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard6eadf632003-01-23 18:29:16 +00006679 (IS_BLANK_NODE(node))))) {
6680 node = node->next;
6681 }
6682 return(node);
6683}
6684
6685/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006686 * xmlRelaxNGNormalize:
6687 * @ctxt: a schema validation context
6688 * @str: the string to normalize
6689 *
6690 * Implements the normalizeWhiteSpace( s ) function from
6691 * section 6.2.9 of the spec
6692 *
6693 * Returns the new string or NULL in case of error.
6694 */
6695static xmlChar *
6696xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6697 xmlChar *ret, *p;
6698 const xmlChar *tmp;
6699 int len;
6700
6701 if (str == NULL)
6702 return(NULL);
6703 tmp = str;
6704 while (*tmp != 0) tmp++;
6705 len = tmp - str;
6706
6707 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6708 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006709 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006710 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006711 } else {
6712 xmlGenericError(xmlGenericErrorContext,
6713 "xmlRelaxNGNormalize: out of memory\n");
6714 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006715 return(NULL);
6716 }
6717 p = ret;
6718 while (IS_BLANK(*str)) str++;
6719 while (*str != 0) {
6720 if (IS_BLANK(*str)) {
6721 while (IS_BLANK(*str)) str++;
6722 if (*str == 0)
6723 break;
6724 *p++ = ' ';
6725 } else
6726 *p++ = *str++;
6727 }
6728 *p = 0;
6729 return(ret);
6730}
6731
6732/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006733 * xmlRelaxNGValidateDatatype:
6734 * @ctxt: a Relax-NG validation context
6735 * @value: the string value
6736 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006737 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006738 *
6739 * Validate the given value against the dataype
6740 *
6741 * Returns 0 if the validation succeeded or an error code.
6742 */
6743static int
6744xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006745 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006746 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006747 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006748 void *result = NULL;
6749 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006750
6751 if ((define == NULL) || (define->data == NULL)) {
6752 return(-1);
6753 }
6754 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006755 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006756 if ((define->attrs != NULL) &&
6757 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006758 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006759 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006760 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006761 }
6762 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006763 ret = -1;
6764 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006765 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006766 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6767 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006768 return(-1);
6769 } else if (ret == 1) {
6770 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006771 } else if (ret == 2) {
6772 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006773 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006774 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006775 ret = -1;
6776 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006777 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006778 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6779 if (lib->facet != NULL) {
6780 tmp = lib->facet(lib->data, define->name, cur->name,
6781 cur->value, value, result);
6782 if (tmp != 0)
6783 ret = -1;
6784 }
6785 cur = cur->next;
6786 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006787 if ((ret == 0) && (define->content != NULL)) {
6788 const xmlChar *oldvalue, *oldendvalue;
6789
6790 oldvalue = ctxt->state->value;
6791 oldendvalue = ctxt->state->endvalue;
6792 ctxt->state->value = (xmlChar *) value;
6793 ctxt->state->endvalue = NULL;
6794 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6795 ctxt->state->value = (xmlChar *) oldvalue;
6796 ctxt->state->endvalue = (xmlChar *) oldendvalue;
6797 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006798 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6799 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006800 return(ret);
6801}
6802
6803/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006804 * xmlRelaxNGNextValue:
6805 * @ctxt: a Relax-NG validation context
6806 *
6807 * Skip to the next value when validating within a list
6808 *
6809 * Returns 0 if the operation succeeded or an error code.
6810 */
6811static int
6812xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
6813 xmlChar *cur;
6814
6815 cur = ctxt->state->value;
6816 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
6817 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00006818 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006819 return(0);
6820 }
6821 while (*cur != 0) cur++;
6822 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
6823 if (cur == ctxt->state->endvalue)
6824 ctxt->state->value = NULL;
6825 else
6826 ctxt->state->value = cur;
6827 return(0);
6828}
6829
6830/**
6831 * xmlRelaxNGValidateValueList:
6832 * @ctxt: a Relax-NG validation context
6833 * @defines: the list of definitions to verify
6834 *
6835 * Validate the given set of definitions for the current value
6836 *
6837 * Returns 0 if the validation succeeded or an error code.
6838 */
6839static int
6840xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
6841 xmlRelaxNGDefinePtr defines) {
6842 int ret = 0;
6843
6844 while (defines != NULL) {
6845 ret = xmlRelaxNGValidateValue(ctxt, defines);
6846 if (ret != 0)
6847 break;
6848 defines = defines->next;
6849 }
6850 return(ret);
6851}
6852
6853/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006854 * xmlRelaxNGValidateValue:
6855 * @ctxt: a Relax-NG validation context
6856 * @define: the definition to verify
6857 *
6858 * Validate the given definition for the current value
6859 *
6860 * Returns 0 if the validation succeeded or an error code.
6861 */
6862static int
6863xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6864 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00006865 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006866 xmlChar *value;
6867
6868 value = ctxt->state->value;
6869 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006870 case XML_RELAXNG_EMPTY: {
6871 if ((value != NULL) && (value[0] != 0)) {
6872 int idx = 0;
6873
6874 while (IS_BLANK(value[idx]))
6875 idx++;
6876 if (value[idx] != 0)
6877 ret = -1;
6878 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006879 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00006880 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006881 case XML_RELAXNG_TEXT:
6882 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00006883 case XML_RELAXNG_VALUE: {
6884 if (!xmlStrEqual(value, define->value)) {
6885 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006886 xmlRelaxNGTypeLibraryPtr lib;
6887
6888 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
6889 if ((lib != NULL) && (lib->comp != NULL))
6890 ret = lib->comp(lib->data, define->name, value,
6891 define->value);
6892 else
6893 ret = -1;
6894 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006895 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006896 return(-1);
6897 } else if (ret == 1) {
6898 ret = 0;
6899 } else {
6900 ret = -1;
6901 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006902 } else {
6903 xmlChar *nval, *nvalue;
6904
6905 /*
6906 * TODO: trivial optimizations are possible by
6907 * computing at compile-time
6908 */
6909 nval = xmlRelaxNGNormalize(ctxt, define->value);
6910 nvalue = xmlRelaxNGNormalize(ctxt, value);
6911
Daniel Veillardea3f3982003-01-26 19:45:18 +00006912 if ((nval == NULL) || (nvalue == NULL) ||
6913 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00006914 ret = -1;
6915 if (nval != NULL)
6916 xmlFree(nval);
6917 if (nvalue != NULL)
6918 xmlFree(nvalue);
6919 }
6920 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006921 if (ret == 0)
6922 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00006923 break;
6924 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006925 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006926 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
6927 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006928 if (ret == 0)
6929 xmlRelaxNGNextValue(ctxt);
6930
6931 break;
6932 }
6933 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006934 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006935 xmlChar *oldvalue;
6936
6937 oldflags = ctxt->flags;
6938 ctxt->flags |= FLAGS_IGNORABLE;
6939
6940 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006941 while (list != NULL) {
6942 ret = xmlRelaxNGValidateValue(ctxt, list);
6943 if (ret == 0) {
6944 break;
6945 }
6946 ctxt->state->value = oldvalue;
6947 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006948 }
6949 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006950 if (ret != 0) {
6951 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6952 xmlRelaxNGDumpValidError(ctxt);
6953 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00006954 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00006955 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006956 if (ret == 0)
6957 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006958 break;
6959 }
6960 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006961 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006962 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00006963#ifdef DEBUG_LIST
6964 int nb_values = 0;
6965#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006966
6967 oldvalue = ctxt->state->value;
6968 oldend = ctxt->state->endvalue;
6969
6970 val = xmlStrdup(oldvalue);
6971 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006972 val = xmlStrdup(BAD_CAST "");
6973 }
6974 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006975 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006976 return(-1);
6977 }
6978 cur = val;
6979 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006980 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006981 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00006982 cur++;
6983#ifdef DEBUG_LIST
6984 nb_values++;
6985#endif
6986 while (IS_BLANK(*cur))
6987 *cur++ = 0;
6988 } else
6989 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006990 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006991#ifdef DEBUG_LIST
6992 xmlGenericError(xmlGenericErrorContext,
6993 "list value: '%s' found %d items\n", oldvalue, nb_values);
6994 nb_values = 0;
6995#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006996 ctxt->state->endvalue = cur;
6997 cur = val;
6998 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006999
Daniel Veillardfd573f12003-03-16 17:52:32 +00007000 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007001
Daniel Veillardfd573f12003-03-16 17:52:32 +00007002 while (list != NULL) {
7003 if (ctxt->state->value == ctxt->state->endvalue)
7004 ctxt->state->value = NULL;
7005 ret = xmlRelaxNGValidateValue(ctxt, list);
7006 if (ret != 0) {
7007#ifdef DEBUG_LIST
7008 xmlGenericError(xmlGenericErrorContext,
7009 "Failed to validate value: '%s' with %d rule\n",
7010 ctxt->state->value, nb_values);
7011#endif
7012 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007013 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007014#ifdef DEBUG_LIST
7015 nb_values++;
7016#endif
7017 list = list->next;
7018 }
7019
7020 if ((ret == 0) && (ctxt->state->value != NULL) &&
7021 (ctxt->state->value != ctxt->state->endvalue)) {
7022 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7023 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007024 }
7025 xmlFree(val);
7026 ctxt->state->value = oldvalue;
7027 ctxt->state->endvalue = oldend;
7028 break;
7029 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007030 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007031 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7032 if (ret != 0) {
7033 break;
7034 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007035 /* no break on purpose */
7036 case XML_RELAXNG_ZEROORMORE: {
7037 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007038
7039 oldflags = ctxt->flags;
7040 ctxt->flags |= FLAGS_IGNORABLE;
7041 cur = ctxt->state->value;
7042 temp = NULL;
7043 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7044 (temp != cur)) {
7045 temp = cur;
7046 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7047 if (ret != 0) {
7048 ctxt->state->value = temp;
7049 ret = 0;
7050 break;
7051 }
7052 cur = ctxt->state->value;
7053 }
7054 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007055 if (ret != 0) {
7056 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7057 xmlRelaxNGDumpValidError(ctxt);
7058 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007059 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007060 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007061 break;
7062 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007063 case XML_RELAXNG_EXCEPT: {
7064 xmlRelaxNGDefinePtr list;
7065
7066 list = define->content;
7067 while (list != NULL) {
7068 ret = xmlRelaxNGValidateValue(ctxt, list);
7069 if (ret == 0) {
7070 ret = -1;
7071 break;
7072 } else
7073 ret = 0;
7074 list = list->next;
7075 }
7076 break;
7077 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007078 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007079 case XML_RELAXNG_GROUP: {
7080 xmlRelaxNGDefinePtr list;
7081
7082 list = define->content;
7083 while (list != NULL) {
7084 ret = xmlRelaxNGValidateValue(ctxt, list);
7085 if (ret != 0) {
7086 ret = -1;
7087 break;
7088 } else
7089 ret = 0;
7090 list = list->next;
7091 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007092 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007093 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007094 case XML_RELAXNG_REF:
7095 case XML_RELAXNG_PARENTREF:
7096 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7097 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007098 default:
7099 TODO
7100 ret = -1;
7101 }
7102 return(ret);
7103}
7104
7105/**
7106 * xmlRelaxNGValidateValueContent:
7107 * @ctxt: a Relax-NG validation context
7108 * @defines: the list of definitions to verify
7109 *
7110 * Validate the given definitions for the current value
7111 *
7112 * Returns 0 if the validation succeeded or an error code.
7113 */
7114static int
7115xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7116 xmlRelaxNGDefinePtr defines) {
7117 int ret = 0;
7118
7119 while (defines != NULL) {
7120 ret = xmlRelaxNGValidateValue(ctxt, defines);
7121 if (ret != 0)
7122 break;
7123 defines = defines->next;
7124 }
7125 return(ret);
7126}
7127
7128/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007129 * xmlRelaxNGAttributeMatch:
7130 * @ctxt: a Relax-NG validation context
7131 * @define: the definition to check
7132 * @prop: the attribute
7133 *
7134 * Check if the attribute matches the definition nameClass
7135 *
7136 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7137 */
7138static int
7139xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7140 xmlRelaxNGDefinePtr define,
7141 xmlAttrPtr prop) {
7142 int ret;
7143
7144 if (define->name != NULL) {
7145 if (!xmlStrEqual(define->name, prop->name))
7146 return(0);
7147 }
7148 if (define->ns != NULL) {
7149 if (define->ns[0] == 0) {
7150 if (prop->ns != NULL)
7151 return(0);
7152 } else {
7153 if ((prop->ns == NULL) ||
7154 (!xmlStrEqual(define->ns, prop->ns->href)))
7155 return(0);
7156 }
7157 }
7158 if (define->nameClass == NULL)
7159 return(1);
7160 define = define->nameClass;
7161 if (define->type == XML_RELAXNG_EXCEPT) {
7162 xmlRelaxNGDefinePtr list;
7163
7164 list = define->content;
7165 while (list != NULL) {
7166 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7167 if (ret == 1)
7168 return(0);
7169 if (ret < 0)
7170 return(ret);
7171 list = list->next;
7172 }
7173 } else {
7174 TODO
7175 }
7176 return(1);
7177}
7178
7179/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007180 * xmlRelaxNGValidateAttribute:
7181 * @ctxt: a Relax-NG validation context
7182 * @define: the definition to verify
7183 *
7184 * Validate the given attribute definition for that node
7185 *
7186 * Returns 0 if the validation succeeded or an error code.
7187 */
7188static int
7189xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7190 xmlRelaxNGDefinePtr define) {
7191 int ret = 0, i;
7192 xmlChar *value, *oldvalue;
7193 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007194 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007195
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007196 if (ctxt->state->nbAttrLeft <= 0)
7197 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007198 if (define->name != NULL) {
7199 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7200 tmp = ctxt->state->attrs[i];
7201 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7202 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7203 (tmp->ns == NULL)) ||
7204 ((tmp->ns != NULL) &&
7205 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7206 prop = tmp;
7207 break;
7208 }
7209 }
7210 }
7211 if (prop != NULL) {
7212 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7213 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007214 oldseq = ctxt->state->seq;
7215 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007216 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007217 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007218 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007219 if (ctxt->state->value != NULL)
7220 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007221 if (value != NULL)
7222 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007223 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007224 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007225 if (ret == 0) {
7226 /*
7227 * flag the attribute as processed
7228 */
7229 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007230 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007231 }
7232 } else {
7233 ret = -1;
7234 }
7235#ifdef DEBUG
7236 xmlGenericError(xmlGenericErrorContext,
7237 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7238#endif
7239 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007240 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7241 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007242 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007243 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007244 prop = tmp;
7245 break;
7246 }
7247 }
7248 if (prop != NULL) {
7249 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7250 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007251 oldseq = ctxt->state->seq;
7252 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007253 ctxt->state->value = value;
7254 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007255 if (ctxt->state->value != NULL)
7256 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007257 if (value != NULL)
7258 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007259 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007260 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007261 if (ret == 0) {
7262 /*
7263 * flag the attribute as processed
7264 */
7265 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007266 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007267 }
7268 } else {
7269 ret = -1;
7270 }
7271#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007272 if (define->ns != NULL) {
7273 xmlGenericError(xmlGenericErrorContext,
7274 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7275 define->ns, ret);
7276 } else {
7277 xmlGenericError(xmlGenericErrorContext,
7278 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7279 ret);
7280 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007281#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007282 }
7283
7284 return(ret);
7285}
7286
7287/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007288 * xmlRelaxNGValidateAttributeList:
7289 * @ctxt: a Relax-NG validation context
7290 * @define: the list of definition to verify
7291 *
7292 * Validate the given node against the list of attribute definitions
7293 *
7294 * Returns 0 if the validation succeeded or an error code.
7295 */
7296static int
7297xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7298 xmlRelaxNGDefinePtr defines) {
7299 int ret = 0;
7300 while (defines != NULL) {
7301 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7302 ret = -1;
7303 defines = defines->next;
7304 }
7305 return(ret);
7306}
7307
7308/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007309 * xmlRelaxNGNodeMatchesList:
7310 * @node: the node
7311 * @list: a NULL terminated array of definitions
7312 *
7313 * Check if a node can be matched by one of the definitions
7314 *
7315 * Returns 1 if matches 0 otherwise
7316 */
7317static int
7318xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7319 xmlRelaxNGDefinePtr cur;
7320 int i = 0;
7321
7322 if ((node == NULL) || (list == NULL))
7323 return(0);
7324
7325 cur = list[i++];
7326 while (cur != NULL) {
7327 if ((node->type == XML_ELEMENT_NODE) &&
7328 (cur->type == XML_RELAXNG_ELEMENT)) {
7329 if (cur->name == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007330 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7331 if (node->ns == NULL)
7332 return(1);
7333 } else {
7334 if ((node->ns != NULL) &&
7335 (xmlStrEqual(node->ns->href, cur->ns)))
7336 return(1);
7337 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007338 } else if (xmlStrEqual(cur->name, node->name)) {
7339 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7340 if (node->ns == NULL)
7341 return(1);
7342 } else {
7343 if ((node->ns != NULL) &&
7344 (xmlStrEqual(node->ns->href, cur->ns)))
7345 return(1);
7346 }
7347 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007348 } else if (((node->type == XML_TEXT_NODE) ||
7349 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007350 (cur->type == XML_RELAXNG_TEXT)) {
7351 return(1);
7352 }
7353 cur = list[i++];
7354 }
7355 return(0);
7356}
7357
7358/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007359 * xmlRelaxNGValidateInterleave:
7360 * @ctxt: a Relax-NG validation context
7361 * @define: the definition to verify
7362 *
7363 * Validate an interleave definition for a node.
7364 *
7365 * Returns 0 if the validation succeeded or an error code.
7366 */
7367static int
7368xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7369 xmlRelaxNGDefinePtr define) {
7370 int ret = 0, i, nbgroups, left;
7371 int errNr = ctxt->errNr;
7372
7373 xmlRelaxNGValidStatePtr oldstate;
7374 xmlRelaxNGPartitionPtr partitions;
7375 xmlRelaxNGInterleaveGroupPtr group = NULL;
7376 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7377 xmlNodePtr *list = NULL, *lasts = NULL;
7378
7379 if (define->data != NULL) {
7380 partitions = (xmlRelaxNGPartitionPtr) define->data;
7381 nbgroups = partitions->nbgroups;
7382 left = nbgroups;
7383 } else {
7384 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7385 return(-1);
7386 }
7387
7388 /*
7389 * Build arrays to store the first and last node of the chain
7390 * pertaining to each group
7391 */
7392 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7393 if (list == NULL) {
7394 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7395 return(-1);
7396 }
7397 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7398 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7399 if (lasts == NULL) {
7400 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7401 return(-1);
7402 }
7403 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7404
7405 /*
7406 * Walk the sequence of children finding the right group and
7407 * sorting them in sequences.
7408 */
7409 cur = ctxt->state->seq;
7410 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7411 start = cur;
7412 while (cur != NULL) {
7413 ctxt->state->seq = cur;
7414 for (i = 0;i < nbgroups;i++) {
7415 group = partitions->groups[i];
7416 if (group == NULL)
7417 continue;
7418 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7419 break;
7420 }
7421 /*
7422 * We break as soon as an element not matched is found
7423 */
7424 if (i >= nbgroups) {
7425 break;
7426 }
7427 if (lasts[i] != NULL) {
7428 lasts[i]->next = cur;
7429 lasts[i] = cur;
7430 } else {
7431 list[i] = cur;
7432 lasts[i] = cur;
7433 }
7434 if (cur->next != NULL)
7435 lastchg = cur->next;
7436 else
7437 lastchg = cur;
7438 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7439 }
7440 if (ret != 0) {
7441 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7442 ret = -1;
7443 goto done;
7444 }
7445 lastelem = cur;
7446 oldstate = ctxt->state;
7447 for (i = 0;i < nbgroups;i++) {
7448 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7449 group = partitions->groups[i];
7450 if (lasts[i] != NULL) {
7451 last = lasts[i]->next;
7452 lasts[i]->next = NULL;
7453 }
7454 ctxt->state->seq = list[i];
7455 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7456 if (ret != 0)
7457 break;
7458 if (ctxt->state != NULL) {
7459 cur = ctxt->state->seq;
7460 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7461 xmlRelaxNGFreeValidState(oldstate);
7462 oldstate = ctxt->state;
7463 ctxt->state = NULL;
7464 if (cur != NULL) {
7465 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7466 ret = -1;
7467 ctxt->state = oldstate;
7468 goto done;
7469 }
7470 } else if (ctxt->states != NULL) {
7471 int j;
7472 int found = 0;
7473
7474 for (j = 0;j < ctxt->states->nbState;j++) {
7475 cur = ctxt->states->tabState[j]->seq;
7476 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7477 if (cur == NULL) {
7478 found = 1;
7479 break;
7480 }
7481 }
7482 if (ctxt->states->nbState > 0) {
7483 xmlRelaxNGFreeValidState(oldstate);
7484 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7485 }
7486 for (j = 0;j < ctxt->states->nbState - 1;j++) {
7487 xmlRelaxNGFreeValidState(ctxt->states->tabState[j]);
7488 }
7489 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7490 ctxt->states = NULL;
7491 if (found == 0) {
7492 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7493 ret = -1;
7494 ctxt->state = oldstate;
7495 goto done;
7496 }
7497 } else {
7498 ret = -1;
7499 break;
7500 }
7501 if (lasts[i] != NULL) {
7502 lasts[i]->next = last;
7503 }
7504 }
7505 if (ctxt->state != NULL)
7506 xmlRelaxNGFreeValidState(ctxt->state);
7507 ctxt->state = oldstate;
7508 ctxt->state->seq = lastelem;
7509 if (ret != 0) {
7510 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7511 ret = -1;
7512 goto done;
7513 }
7514
7515done:
7516 /*
7517 * builds the next links chain from the prev one
7518 */
7519 cur = lastchg;
7520 while (cur != NULL) {
7521 if ((cur == start) || (cur->prev == NULL))
7522 break;
7523 cur->prev->next = cur;
7524 cur = cur->prev;
7525 }
7526 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007527 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007528 }
7529
7530 xmlFree(list);
7531 xmlFree(lasts);
7532 return(ret);
7533}
7534
7535/**
7536 * xmlRelaxNGValidateDefinitionList:
7537 * @ctxt: a Relax-NG validation context
7538 * @define: the list of definition to verify
7539 *
7540 * Validate the given node content against the (list) of definitions
7541 *
7542 * Returns 0 if the validation succeeded or an error code.
7543 */
7544static int
7545xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7546 xmlRelaxNGDefinePtr defines) {
7547 int ret = 0, res;
7548
7549
Daniel Veillard952379b2003-03-17 15:37:12 +00007550 if (defines == NULL) {
7551 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7552 return(-1);
7553 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007554 while (defines != NULL) {
7555 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7556 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7557 if (res < 0)
7558 ret = -1;
7559 } else {
7560 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7561 return(-1);
7562 }
7563 if (ret < 0)
7564 break;
7565 defines = defines->next;
7566 }
7567
7568 return(ret);
7569}
7570
7571/**
7572 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007573 * @ctxt: a Relax-NG validation context
7574 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007575 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007576 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007577 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007578 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007579 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007580 */
7581static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007582xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7583 xmlRelaxNGDefinePtr define,
7584 xmlNodePtr elem) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007585 int ret, oldflags;
7586
Daniel Veillardfd573f12003-03-16 17:52:32 +00007587 if (define->name != NULL) {
7588 if (!xmlStrEqual(elem->name, define->name)) {
7589 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7590 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007591 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007592 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007593 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7594 if (elem->ns == NULL) {
7595 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7596 elem->name);
7597 return(0);
7598 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7599 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7600 elem->name, define->ns);
7601 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007602 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007603 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7604 (define->name == NULL)) {
7605 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7606 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007607 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007608 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7609 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7610 define->name);
7611 return(0);
7612 }
7613
7614 if (define->nameClass == NULL)
7615 return(1);
7616
7617 define = define->nameClass;
7618 if (define->type == XML_RELAXNG_EXCEPT) {
7619 xmlRelaxNGDefinePtr list;
7620 oldflags = ctxt->flags;
7621 ctxt->flags |= FLAGS_IGNORABLE;
7622
7623 list = define->content;
7624 while (list != NULL) {
7625 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7626 if (ret == 1) {
7627 ctxt->flags = oldflags;
7628 return(0);
7629 }
7630 if (ret < 0) {
7631 ctxt->flags = oldflags;
7632 return(ret);
7633 }
7634 list = list->next;
7635 }
7636 ret = 1;
7637 ctxt->flags = oldflags;
7638 } else if (define->type == XML_RELAXNG_CHOICE) {
7639 xmlRelaxNGDefinePtr list;
7640
7641 oldflags = ctxt->flags;
7642 ctxt->flags |= FLAGS_IGNORABLE;
7643
7644 list = define->nameClass;
7645 while (list != NULL) {
7646 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7647 if (ret == 1) {
7648 ctxt->flags = oldflags;
7649 return(1);
7650 }
7651 if (ret < 0) {
7652 ctxt->flags = oldflags;
7653 return(ret);
7654 }
7655 list = list->next;
7656 }
7657 if (ret != 0) {
7658 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7659 xmlRelaxNGDumpValidError(ctxt);
7660 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007661 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007662 }
7663 ret = 0;
7664 ctxt->flags = oldflags;
7665 } else {
7666 TODO
7667 ret = -1;
7668 }
7669 return(ret);
7670}
7671
7672/**
7673 * xmlRelaxNGValidateElementEnd:
7674 * @ctxt: a Relax-NG validation context
7675 *
7676 * Validate the end of the element, implements check that
7677 * there is nothing left not consumed in the element content
7678 * or in the attribute list.
7679 *
7680 * Returns 0 if the validation succeeded or an error code.
7681 */
7682static int
7683xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
7684 int ret = 0, i;
7685 xmlRelaxNGValidStatePtr state;
7686
7687 state = ctxt->state;
7688 if (state->seq != NULL) {
7689 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
7690 if (state->seq != NULL) {
7691 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
7692 state->node->name, state->seq->name);
7693 ret = -1;
7694 }
7695 }
7696 for (i = 0;i < state->nbAttrs;i++) {
7697 if (state->attrs[i] != NULL) {
7698 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
7699 state->attrs[i]->name, state->node->name);
7700 ret = -1;
7701 }
7702 }
7703 return(ret);
7704}
7705
7706/**
7707 * xmlRelaxNGValidateState:
7708 * @ctxt: a Relax-NG validation context
7709 * @define: the definition to verify
7710 *
7711 * Validate the current state against the definition
7712 *
7713 * Returns 0 if the validation succeeded or an error code.
7714 */
7715static int
7716xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
7717 xmlRelaxNGDefinePtr define) {
7718 xmlNodePtr node;
7719 int ret = 0, i, tmp, oldflags, errNr;
7720 xmlRelaxNGValidStatePtr oldstate, state;
7721
7722 if (define == NULL) {
7723 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
7724 return(-1);
7725 }
7726
7727 if (ctxt->state != NULL) {
7728 node = ctxt->state->seq;
7729 } else {
7730 node = NULL;
7731 }
7732#ifdef DEBUG
7733 for (i = 0;i < ctxt->depth;i++)
7734 xmlGenericError(xmlGenericErrorContext, " ");
7735 xmlGenericError(xmlGenericErrorContext,
7736 "Start validating %s ", xmlRelaxNGDefName(define));
7737 if (define->name != NULL)
7738 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7739 if ((node != NULL) && (node->name != NULL))
7740 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
7741 else
7742 xmlGenericError(xmlGenericErrorContext, "\n");
7743#endif
7744 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007745 switch (define->type) {
7746 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007747 node = xmlRelaxNGSkipIgnored(ctxt, node);
7748 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007749 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007750 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007751 ret = -1;
7752 break;
7753 case XML_RELAXNG_TEXT:
7754 while ((node != NULL) &&
7755 ((node->type == XML_TEXT_NODE) ||
7756 (node->type == XML_COMMENT_NODE) ||
7757 (node->type == XML_PI_NODE) ||
7758 (node->type == XML_CDATA_SECTION_NODE)))
7759 node = node->next;
7760 ctxt->state->seq = node;
7761 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007762 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007763 errNr = ctxt->errNr;
7764 node = xmlRelaxNGSkipIgnored(ctxt, node);
7765 if (node == NULL) {
7766 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
7767 ret = -1;
7768 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7769 xmlRelaxNGDumpValidError(ctxt);
7770 break;
7771 }
7772 if (node->type != XML_ELEMENT_NODE) {
7773 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7774 ret = -1;
7775 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7776 xmlRelaxNGDumpValidError(ctxt);
7777 break;
7778 }
7779 /*
7780 * This node was already validated successfully against
7781 * this definition.
7782 */
7783 if (node->_private == define) {
7784 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7785 break;
7786 }
7787
7788 ret = xmlRelaxNGElementMatch(ctxt, define, node);
7789 if (ret <= 0) {
7790 ret = -1;
7791 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7792 xmlRelaxNGDumpValidError(ctxt);
7793 break;
7794 }
7795 ret = 0;
7796 if (ctxt->errNr != 0) {
7797 while ((ctxt->err != NULL) &&
7798 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
7799 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
7800 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
7801 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
7802 xmlRelaxNGValidErrorPop(ctxt);
7803 }
7804 errNr = ctxt->errNr;
7805
7806 state = xmlRelaxNGNewValidState(ctxt, node);
7807 if (state == NULL) {
7808 ret = -1;
7809 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7810 xmlRelaxNGDumpValidError(ctxt);
7811 break;
7812 }
7813
7814 oldstate = ctxt->state;
7815 ctxt->state = state;
7816 if (define->attrs != NULL) {
7817 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7818 if (tmp != 0) {
7819 ret = -1;
7820 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7821 }
7822 }
7823 if (define->content != NULL) {
7824 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7825 if (tmp != 0) {
7826 ret = -1;
7827 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
7828 }
7829 }
7830 if (ctxt->states != NULL) {
7831 tmp = -1;
7832
7833 oldflags = ctxt->flags;
7834 ctxt->flags |= FLAGS_IGNORABLE;
7835
7836 for (i = 0;i < ctxt->states->nbState;i++) {
7837 state = ctxt->states->tabState[i];
7838 ctxt->state = state;
7839
7840 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7841 tmp = 0;
7842 xmlRelaxNGFreeValidState(state);
7843 }
7844 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7845 ctxt->flags = oldflags;
7846 ctxt->states = NULL;
7847 if ((ret == 0) && (tmp == -1))
7848 ret = -1;
7849 } else {
7850 state = ctxt->state;
7851 if (ret == 0)
7852 ret = xmlRelaxNGValidateElementEnd(ctxt);
7853 xmlRelaxNGFreeValidState(state);
7854 }
7855 ctxt->state = oldstate;
7856 if (oldstate != NULL)
7857 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7858 if (ret == 0) {
7859 node->_private = define;
7860 }
7861 if (ret != 0) {
7862 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7863 xmlRelaxNGDumpValidError(ctxt);
7864 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007865 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007866 }
7867
7868#ifdef DEBUG
7869 xmlGenericError(xmlGenericErrorContext,
7870 "xmlRelaxNGValidateDefinition(): validated %s : %d",
7871 node->name, ret);
7872 if (oldstate == NULL)
7873 xmlGenericError(xmlGenericErrorContext, ": no state\n");
7874 else if (oldstate->seq == NULL)
7875 xmlGenericError(xmlGenericErrorContext, ": done\n");
7876 else if (oldstate->seq->type == XML_ELEMENT_NODE)
7877 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
7878 oldstate->seq->name);
7879 else
7880 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
7881 oldstate->seq->name, oldstate->seq->type);
7882#endif
7883 break;
7884 case XML_RELAXNG_OPTIONAL: {
7885 oldflags = ctxt->flags;
7886 ctxt->flags |= FLAGS_IGNORABLE;
7887 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7888 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7889 if (ret != 0) {
7890 if (ctxt->state != NULL)
7891 xmlRelaxNGFreeValidState(ctxt->state);
7892 ctxt->state = oldstate;
7893 ctxt->flags = oldflags;
7894 ret = 0;
7895 break;
7896 }
7897 if (ctxt->states != NULL) {
7898 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7899 } else {
7900 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
7901 if (ctxt->states == NULL) {
7902 xmlRelaxNGFreeValidState(oldstate);
7903 ctxt->flags = oldflags;
7904 ret = -1;
7905 break;
7906 }
7907 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7908 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
7909 ctxt->state = NULL;
7910 }
7911 ctxt->flags = oldflags;
7912 ret = 0;
7913 break;
7914 }
7915 case XML_RELAXNG_ONEORMORE:
7916 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7917 if (ret != 0) {
7918 break;
7919 }
7920 /* no break on purpose */
7921 case XML_RELAXNG_ZEROORMORE: {
7922 int progress;
7923 xmlRelaxNGStatesPtr states = NULL, res = NULL;
7924 int base, j;
7925
7926 res = xmlRelaxNGNewStates(ctxt, 1);
7927 if (res == NULL) {
7928 ret = -1;
7929 break;
7930 }
7931 /*
7932 * All the input states are also exit states
7933 */
7934 if (ctxt->state != NULL) {
7935 xmlRelaxNGAddStates(ctxt, res,
7936 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
7937 } else {
7938 for (j = 0;j < ctxt->states->nbState;j++) {
7939 xmlRelaxNGAddStates(ctxt, res,
7940 xmlRelaxNGCopyValidState(ctxt,
7941 ctxt->states->tabState[j]));
7942 }
7943 }
7944 oldflags = ctxt->flags;
7945 ctxt->flags |= FLAGS_IGNORABLE;
7946 do {
7947 progress = 0;
7948 base = res->nbState;
7949
7950 if (ctxt->states != NULL) {
7951 states = ctxt->states;
7952 for (i = 0;i < states->nbState;i++) {
7953 ctxt->state = states->tabState[i];
7954 ctxt->states = NULL;
7955 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7956 define->content);
7957 if (ret == 0) {
7958 if (ctxt->state != NULL) {
7959 tmp = xmlRelaxNGAddStates(ctxt, res,
7960 ctxt->state);
7961 ctxt->state = NULL;
7962 if (tmp == 1)
7963 progress = 1;
7964 } else if (ctxt->states != NULL) {
7965 for (j = 0;j < ctxt->states->nbState;j++) {
7966 tmp = xmlRelaxNGAddStates(ctxt, res,
7967 ctxt->states->tabState[j]);
7968 if (tmp == 1)
7969 progress = 1;
7970 }
7971 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7972 ctxt->states = NULL;
7973 }
7974 } else {
7975 if (ctxt->state != NULL) {
7976 xmlRelaxNGFreeValidState(ctxt->state);
7977 ctxt->state = NULL;
7978 }
7979 }
7980 }
7981 } else {
7982 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7983 define->content);
7984 if (ret != 0) {
7985 xmlRelaxNGFreeValidState(ctxt->state);
7986 ctxt->state = NULL;
7987 } else {
7988 base = res->nbState;
7989 if (ctxt->state != NULL) {
7990 tmp = xmlRelaxNGAddStates(ctxt, res,
7991 ctxt->state);
7992 ctxt->state = NULL;
7993 if (tmp == 1)
7994 progress = 1;
7995 } else if (ctxt->states != NULL) {
7996 for (j = 0;j < ctxt->states->nbState;j++) {
7997 tmp = xmlRelaxNGAddStates(ctxt, res,
7998 ctxt->states->tabState[j]);
7999 if (tmp == 1)
8000 progress = 1;
8001 }
8002 if (states == NULL) {
8003 states = ctxt->states;
8004 } else {
8005 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8006 }
8007 ctxt->states = NULL;
8008 }
8009 }
8010 }
8011 if (progress) {
8012 /*
8013 * Collect all the new nodes added at that step
8014 * and make them the new node set
8015 */
8016 if (res->nbState - base == 1) {
8017 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8018 res->tabState[base]);
8019 } else {
8020 if (states == NULL) {
8021 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8022 }
8023 states->nbState = 0;
8024 for (i = base;i < res->nbState;i++)
8025 xmlRelaxNGAddStates(ctxt, states,
8026 xmlRelaxNGCopyValidState(ctxt,
8027 res->tabState[i]));
8028 ctxt->states = states;
8029 }
8030 }
8031 } while (progress == 1);
8032 if (states != NULL) {
8033 xmlRelaxNGFreeStates(ctxt, states);
8034 }
8035 ctxt->states = res;
8036 ctxt->flags = oldflags;
8037 ret = 0;
8038 break;
8039 }
8040 case XML_RELAXNG_CHOICE: {
8041 xmlRelaxNGDefinePtr list = define->content;
8042 xmlRelaxNGStatesPtr states = NULL;
8043
8044
8045 oldflags = ctxt->flags;
8046 errNr = ctxt->errNr;
8047 ctxt->flags |= FLAGS_IGNORABLE;
8048 node = xmlRelaxNGSkipIgnored(ctxt, node);
8049
8050 while (list != NULL) {
8051 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8052 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8053 if (ret == 0) {
8054 if (states == NULL) {
8055 states = xmlRelaxNGNewStates(ctxt, 1);
8056 }
8057 if (ctxt->state != NULL) {
8058 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8059 } else if (ctxt->states != NULL) {
8060 for (i = 0;i < ctxt->states->nbState;i++) {
8061 xmlRelaxNGAddStates(ctxt, states,
8062 ctxt->states->tabState[i]);
8063 }
8064 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8065 ctxt->states = NULL;
8066 }
8067 } else {
8068 xmlRelaxNGFreeValidState(ctxt->state);
8069 }
8070 ctxt->state = oldstate;
8071 list = list->next;
8072 }
8073 if (states != NULL) {
8074 xmlRelaxNGFreeValidState(oldstate);
8075 ctxt->states = states;
8076 ctxt->state = NULL;
8077 ret = 0;
8078 } else {
8079 ctxt->states = NULL;
8080 }
8081 ctxt->flags = oldflags;
8082 if (ret != 0) {
8083 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8084 xmlRelaxNGDumpValidError(ctxt);
8085 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008086 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008087 }
8088 break;
8089 }
8090 case XML_RELAXNG_DEF:
8091 case XML_RELAXNG_GROUP:
8092 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008093 break;
8094 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008095 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008096 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008097 case XML_RELAXNG_ATTRIBUTE:
8098 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8099 break;
8100 case XML_RELAXNG_NOOP:
8101 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008102 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008103 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8104 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008105 case XML_RELAXNG_PARENTREF:
8106 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8107 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008108 case XML_RELAXNG_DATATYPE: {
8109 xmlNodePtr child;
8110 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008111
Daniel Veillardfd573f12003-03-16 17:52:32 +00008112 child = node;
8113 while (child != NULL) {
8114 if (child->type == XML_ELEMENT_NODE) {
8115 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8116 node->parent->name);
8117 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008118 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008119 } else if ((child->type == XML_TEXT_NODE) ||
8120 (child->type == XML_CDATA_SECTION_NODE)) {
8121 content = xmlStrcat(content, child->content);
8122 }
8123 /* TODO: handle entities ... */
8124 child = child->next;
8125 }
8126 if (ret == -1) {
8127 if (content != NULL)
8128 xmlFree(content);
8129 break;
8130 }
8131 if (content == NULL) {
8132 content = xmlStrdup(BAD_CAST "");
8133 if (content == NULL) {
8134 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8135 ret = -1;
8136 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008137 }
8138 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008139 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8140 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008141 if (ret == -1) {
8142 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8143 } else if (ret == 0) {
8144 ctxt->state->seq = NULL;
8145 }
8146 if (content != NULL)
8147 xmlFree(content);
8148 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008149 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008150 case XML_RELAXNG_VALUE: {
8151 xmlChar *content = NULL;
8152 xmlChar *oldvalue;
8153 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008154
Daniel Veillardfd573f12003-03-16 17:52:32 +00008155 child = node;
8156 while (child != NULL) {
8157 if (child->type == XML_ELEMENT_NODE) {
8158 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8159 node->parent->name);
8160 ret = -1;
8161 break;
8162 } else if ((child->type == XML_TEXT_NODE) ||
8163 (child->type == XML_CDATA_SECTION_NODE)) {
8164 content = xmlStrcat(content, child->content);
8165 }
8166 /* TODO: handle entities ... */
8167 child = child->next;
8168 }
8169 if (ret == -1) {
8170 if (content != NULL)
8171 xmlFree(content);
8172 break;
8173 }
8174 if (content == NULL) {
8175 content = xmlStrdup(BAD_CAST "");
8176 if (content == NULL) {
8177 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8178 ret = -1;
8179 break;
8180 }
8181 }
8182 oldvalue = ctxt->state->value;
8183 ctxt->state->value = content;
8184 ret = xmlRelaxNGValidateValue(ctxt, define);
8185 ctxt->state->value = oldvalue;
8186 if (ret == -1) {
8187 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8188 } else if (ret == 0) {
8189 ctxt->state->seq = NULL;
8190 }
8191 if (content != NULL)
8192 xmlFree(content);
8193 break;
8194 }
8195 case XML_RELAXNG_LIST: {
8196 xmlChar *content;
8197 xmlNodePtr child;
8198 xmlChar *oldvalue, *oldendvalue;
8199 int len;
8200
8201 /*
8202 * Make sure it's only text nodes
8203 */
8204
8205 content = NULL;
8206 child = node;
8207 while (child != NULL) {
8208 if (child->type == XML_ELEMENT_NODE) {
8209 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8210 node->parent->name);
8211 ret = -1;
8212 break;
8213 } else if ((child->type == XML_TEXT_NODE) ||
8214 (child->type == XML_CDATA_SECTION_NODE)) {
8215 content = xmlStrcat(content, child->content);
8216 }
8217 /* TODO: handle entities ... */
8218 child = child->next;
8219 }
8220 if (ret == -1) {
8221 if (content != NULL)
8222 xmlFree(content);
8223 break;
8224 }
8225 if (content == NULL) {
8226 content = xmlStrdup(BAD_CAST "");
8227 if (content == NULL) {
8228 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8229 ret = -1;
8230 break;
8231 }
8232 }
8233 len = xmlStrlen(content);
8234 oldvalue = ctxt->state->value;
8235 oldendvalue = ctxt->state->endvalue;
8236 ctxt->state->value = content;
8237 ctxt->state->endvalue = content + len;
8238 ret = xmlRelaxNGValidateValue(ctxt, define);
8239 ctxt->state->value = oldvalue;
8240 ctxt->state->endvalue = oldendvalue;
8241 if (ret == -1) {
8242 VALID_ERR(XML_RELAXNG_ERR_LIST);
8243 } else if ((ret == 0) && (node != NULL)) {
8244 ctxt->state->seq = node->next;
8245 }
8246 if (content != NULL)
8247 xmlFree(content);
8248 break;
8249 }
8250 case XML_RELAXNG_START:
8251 case XML_RELAXNG_EXCEPT:
8252 case XML_RELAXNG_PARAM:
8253 TODO
8254 ret = -1;
8255 break;
8256 }
8257 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008258#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008259 for (i = 0;i < ctxt->depth;i++)
8260 xmlGenericError(xmlGenericErrorContext, " ");
8261 xmlGenericError(xmlGenericErrorContext,
8262 "Validating %s ", xmlRelaxNGDefName(define));
8263 if (define->name != NULL)
8264 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8265 if (ret == 0)
8266 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8267 else
8268 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008269#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008270 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008271}
8272
8273/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008274 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008275 * @ctxt: a Relax-NG validation context
8276 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008277 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008278 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008279 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008280 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008281 */
8282static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008283xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8284 xmlRelaxNGDefinePtr define) {
8285 xmlRelaxNGStatesPtr states, res;
8286 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008287
Daniel Veillardfd573f12003-03-16 17:52:32 +00008288 /*
8289 * We should NOT have both ctxt->state and ctxt->states
8290 */
8291 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8292 TODO
8293 xmlRelaxNGFreeValidState(ctxt->state);
8294 ctxt->state = NULL;
8295 }
8296
8297 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8298 if (ctxt->states != NULL) {
8299 ctxt->state = ctxt->states->tabState[0];
8300 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8301 ctxt->states = NULL;
8302 }
8303 ret = xmlRelaxNGValidateState(ctxt, define);
8304 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8305 TODO
8306 xmlRelaxNGFreeValidState(ctxt->state);
8307 ctxt->state = NULL;
8308 }
8309 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8310 ctxt->state = ctxt->states->tabState[0];
8311 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8312 ctxt->states = NULL;
8313 }
8314 return(ret);
8315 }
8316
8317 states = ctxt->states;
8318 ctxt->states = NULL;
8319 res = NULL;
8320 j = 0;
8321 oldflags = ctxt->flags;
8322 ctxt->flags |= FLAGS_IGNORABLE;
8323 for (i = 0;i < states->nbState;i++) {
8324 ctxt->state = states->tabState[i];
8325 ctxt->states = NULL;
8326 ret = xmlRelaxNGValidateState(ctxt, define);
8327 /*
8328 * We should NOT have both ctxt->state and ctxt->states
8329 */
8330 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8331 TODO
8332 xmlRelaxNGFreeValidState(ctxt->state);
8333 ctxt->state = NULL;
8334 }
8335 if (ret == 0) {
8336 if (ctxt->states == NULL) {
8337 if (res != NULL) {
8338 /* add the state to the container */
8339 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8340 ctxt->state = NULL;
8341 } else {
8342 /* add the state directly in states */
8343 states->tabState[j++] = ctxt->state;
8344 ctxt->state = NULL;
8345 }
8346 } else {
8347 if (res == NULL) {
8348 /* make it the new container and copy other results */
8349 res = ctxt->states;
8350 ctxt->states = NULL;
8351 for (k = 0;k < j;k++)
8352 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8353 } else {
8354 /* add all the new results to res and reff the container */
8355 for (k = 0;k < ctxt->states->nbState;k++)
8356 xmlRelaxNGAddStates(ctxt, res,
8357 ctxt->states->tabState[k]);
8358 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8359 ctxt->states = NULL;
8360 }
8361 }
8362 } else {
8363 if (ctxt->state != NULL) {
8364 xmlRelaxNGFreeValidState(ctxt->state);
8365 ctxt->state = NULL;
8366 } else if (ctxt->states != NULL) {
8367 for (k = 0;k < ctxt->states->nbState;k++)
8368 xmlRelaxNGFreeValidState(ctxt->states->tabState[k]);
8369 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8370 ctxt->states = NULL;
8371 }
8372 }
8373 }
8374 ctxt->flags = oldflags;
8375 if (res != NULL) {
8376 xmlRelaxNGFreeStates(ctxt, states);
8377 ctxt->states = res;
8378 ret = 0;
8379 } else if (j > 1) {
8380 states->nbState = j;
8381 ctxt->states = states;
8382 ret =0;
8383 } else if (j == 1) {
8384 ctxt->state = states->tabState[0];
8385 xmlRelaxNGFreeStates(ctxt, states);
8386 ret = 0;
8387 } else {
8388 ret = -1;
8389 xmlRelaxNGFreeStates(ctxt, states);
8390 if (ctxt->states != NULL) {
8391 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8392 ctxt->states = NULL;
8393 }
8394 }
8395 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8396 TODO
8397 xmlRelaxNGFreeValidState(ctxt->state);
8398 ctxt->state = NULL;
8399 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008400 return(ret);
8401}
8402
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008403/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008404 * xmlRelaxNGValidateDocument:
8405 * @ctxt: a Relax-NG validation context
8406 * @doc: the document
8407 *
8408 * Validate the given document
8409 *
8410 * Returns 0 if the validation succeeded or an error code.
8411 */
8412static int
8413xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8414 int ret;
8415 xmlRelaxNGPtr schema;
8416 xmlRelaxNGGrammarPtr grammar;
8417 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008418 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008419
8420 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8421 return(-1);
8422
8423 schema = ctxt->schema;
8424 grammar = schema->topgrammar;
8425 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008426 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008427 return(-1);
8428 }
8429 state = xmlRelaxNGNewValidState(ctxt, NULL);
8430 ctxt->state = state;
8431 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008432 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8433 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008434 node = state->seq;
8435 node = xmlRelaxNGSkipIgnored(ctxt, node);
8436 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008437 if (ret != -1) {
8438 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8439 ret = -1;
8440 }
8441 }
8442 } else if (ctxt->states != NULL) {
8443 int i;
8444 int tmp = -1;
8445
8446 for (i = 0;i < ctxt->states->nbState;i++) {
8447 state = ctxt->states->tabState[i];
8448 node = state->seq;
8449 node = xmlRelaxNGSkipIgnored(ctxt, node);
8450 if (node == NULL)
8451 tmp = 0;
8452 xmlRelaxNGFreeValidState(state);
8453 }
8454 if (tmp == -1) {
8455 if (ret != -1) {
8456 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8457 ret = -1;
8458 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008459 }
8460 }
8461 xmlRelaxNGFreeValidState(state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008462 if (ret != 0)
8463 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008464 if (ctxt->idref == 1) {
8465 xmlValidCtxt vctxt;
8466
8467 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8468 vctxt.valid = 1;
8469 vctxt.error = ctxt->error;
8470 vctxt.warning = ctxt->warning;
8471 vctxt.userData = ctxt->userData;
8472
8473 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8474 ret = -1;
8475 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008476
8477 return(ret);
8478}
8479
Daniel Veillardfd573f12003-03-16 17:52:32 +00008480/************************************************************************
8481 * *
8482 * Validation interfaces *
8483 * *
8484 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008485/**
8486 * xmlRelaxNGNewValidCtxt:
8487 * @schema: a precompiled XML RelaxNGs
8488 *
8489 * Create an XML RelaxNGs validation context based on the given schema
8490 *
8491 * Returns the validation context or NULL in case of error
8492 */
8493xmlRelaxNGValidCtxtPtr
8494xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8495 xmlRelaxNGValidCtxtPtr ret;
8496
8497 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8498 if (ret == NULL) {
8499 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008500 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008501 return (NULL);
8502 }
8503 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8504 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008505 ret->error = xmlGenericError;
8506 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008507 ret->errNr = 0;
8508 ret->errMax = 0;
8509 ret->err = NULL;
8510 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008511 ret->idref = schema->idref;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008512 return (ret);
8513}
8514
8515/**
8516 * xmlRelaxNGFreeValidCtxt:
8517 * @ctxt: the schema validation context
8518 *
8519 * Free the resources associated to the schema validation context
8520 */
8521void
8522xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
8523 if (ctxt == NULL)
8524 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008525 if (ctxt->states != NULL)
8526 xmlRelaxNGFreeStates(ctxt, ctxt->states);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008527 if (ctxt->errTab != NULL)
8528 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008529 xmlFree(ctxt);
8530}
8531
8532/**
8533 * xmlRelaxNGSetValidErrors:
8534 * @ctxt: a Relax-NG validation context
8535 * @err: the error function
8536 * @warn: the warning function
8537 * @ctx: the functions context
8538 *
8539 * Set the error and warning callback informations
8540 */
8541void
8542xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8543 xmlRelaxNGValidityErrorFunc err,
8544 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8545 if (ctxt == NULL)
8546 return;
8547 ctxt->error = err;
8548 ctxt->warning = warn;
8549 ctxt->userData = ctx;
8550}
8551
8552/**
8553 * xmlRelaxNGValidateDoc:
8554 * @ctxt: a Relax-NG validation context
8555 * @doc: a parsed document tree
8556 *
8557 * Validate a document tree in memory.
8558 *
8559 * Returns 0 if the document is valid, a positive error code
8560 * number otherwise and -1 in case of internal or API error.
8561 */
8562int
8563xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8564 int ret;
8565
8566 if ((ctxt == NULL) || (doc == NULL))
8567 return(-1);
8568
8569 ctxt->doc = doc;
8570
8571 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008572 /*
8573 * TODO: build error codes
8574 */
8575 if (ret == -1)
8576 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008577 return(ret);
8578}
8579
8580#endif /* LIBXML_SCHEMAS_ENABLED */
8581