blob: 8249a964157ea9a80abd5d92da717c4a3fbdc13e [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/**
1882 * xmlRelaxNGDumpValidError:
1883 * @ctxt: the validation context
1884 *
1885 * Show all validation error over a given index.
1886 */
1887static void
1888xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
1889 int i;
1890 xmlRelaxNGValidErrorPtr err;
1891
1892 for (i = 0;i < ctxt->errNr;i++) {
1893 err = &ctxt->errTab[i];
1894 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
1895 err->arg1, err->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001896 if (err->flags & ERROR_IS_DUP) {
1897 if (err->arg1 != NULL)
1898 xmlFree((xmlChar *)err->arg1);
1899 err->arg1 = NULL;
1900 if (err->arg2 != NULL)
1901 xmlFree((xmlChar *)err->arg2);
1902 err->arg2 = NULL;
1903 err->flags = 0;
1904 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001905 }
1906 ctxt->errNr = 0;
1907}
1908/**
1909 * xmlRelaxNGAddValidError:
1910 * @ctxt: the validation context
1911 * @err: the error number
1912 * @arg1: the first argument
1913 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001914 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00001915 *
1916 * Register a validation error, either generating it if it's sure
1917 * or stacking it for later handling if unsure.
1918 */
1919static void
1920xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001921 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001922{
1923 if ((ctxt == NULL) || (ctxt->error == NULL))
1924 return;
1925
1926 /*
1927 * generate the error directly
1928 */
1929 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
1930 xmlNodePtr node, seq;
1931 /*
1932 * Flush first any stacked error which might be the
1933 * real cause of the problem.
1934 */
1935 if (ctxt->errNr != 0)
1936 xmlRelaxNGDumpValidError(ctxt);
1937 if (ctxt->state != NULL) {
1938 node = ctxt->state->node;
1939 seq = ctxt->state->seq;
1940 } else {
1941 node = seq = NULL;
1942 }
1943 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
1944 }
1945 /*
1946 * Stack the error for later processing if needed
1947 */
1948 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001949 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001950 }
1951}
1952
Daniel Veillard6eadf632003-01-23 18:29:16 +00001953
1954/************************************************************************
1955 * *
1956 * Type library hooks *
1957 * *
1958 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00001959static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1960 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001961
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001962/**
1963 * xmlRelaxNGSchemaTypeHave:
1964 * @data: data needed for the library
1965 * @type: the type name
1966 *
1967 * Check if the given type is provided by
1968 * the W3C XMLSchema Datatype library.
1969 *
1970 * Returns 1 if yes, 0 if no and -1 in case of error.
1971 */
1972static int
1973xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00001974 const xmlChar *type) {
1975 xmlSchemaTypePtr typ;
1976
1977 if (type == NULL)
1978 return(-1);
1979 typ = xmlSchemaGetPredefinedType(type,
1980 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1981 if (typ == NULL)
1982 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001983 return(1);
1984}
1985
1986/**
1987 * xmlRelaxNGSchemaTypeCheck:
1988 * @data: data needed for the library
1989 * @type: the type name
1990 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001991 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00001992 *
1993 * Check if the given type and value are validated 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
1999xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002000 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002001 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002002 void **result,
2003 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002004 xmlSchemaTypePtr typ;
2005 int ret;
2006
2007 /*
2008 * TODO: the type should be cached ab provided back, interface subject
2009 * to changes.
2010 * TODO: handle facets, may require an additional interface and keep
2011 * the value returned from the validation.
2012 */
2013 if ((type == NULL) || (value == NULL))
2014 return(-1);
2015 typ = xmlSchemaGetPredefinedType(type,
2016 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2017 if (typ == NULL)
2018 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002019 ret = xmlSchemaValPredefTypeNode(typ, value,
2020 (xmlSchemaValPtr *) result, node);
2021 if (ret == 2) /* special ID error code */
2022 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002023 if (ret == 0)
2024 return(1);
2025 if (ret > 0)
2026 return(0);
2027 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002028}
2029
2030/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002031 * xmlRelaxNGSchemaFacetCheck:
2032 * @data: data needed for the library
2033 * @type: the type name
2034 * @facet: the facet name
2035 * @val: the facet value
2036 * @strval: the string value
2037 * @value: the value to check
2038 *
2039 * Function provided by a type library to check a value facet
2040 *
2041 * Returns 1 if yes, 0 if no and -1 in case of error.
2042 */
2043static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002044xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002045 const xmlChar *facetname, const xmlChar *val,
2046 const xmlChar *strval, void *value) {
2047 xmlSchemaFacetPtr facet;
2048 xmlSchemaTypePtr typ;
2049 int ret;
2050
2051 if ((type == NULL) || (strval == NULL))
2052 return(-1);
2053 typ = xmlSchemaGetPredefinedType(type,
2054 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2055 if (typ == NULL)
2056 return(-1);
2057
2058 facet = xmlSchemaNewFacet();
2059 if (facet == NULL)
2060 return(-1);
2061
2062 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2063 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2064 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2065 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2066 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2067 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2068 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2069 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2070 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2071 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2072 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2073 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2074 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2075 facet->type = XML_SCHEMA_FACET_PATTERN;
2076 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2077 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2078 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2079 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2080 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2081 facet->type = XML_SCHEMA_FACET_LENGTH;
2082 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2083 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2084 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2085 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2086 } else {
2087 xmlSchemaFreeFacet(facet);
2088 return(-1);
2089 }
2090 facet->value = xmlStrdup(val);
2091 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2092 if (ret != 0) {
2093 xmlSchemaFreeFacet(facet);
2094 return(-1);
2095 }
2096 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2097 xmlSchemaFreeFacet(facet);
2098 if (ret != 0)
2099 return(-1);
2100 return(0);
2101}
2102
2103/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002104 * xmlRelaxNGSchemaTypeCompare:
2105 * @data: data needed for the library
2106 * @type: the type name
2107 * @value1: the first value
2108 * @value2: the second value
2109 *
2110 * Compare two values accordingly a type from the W3C XMLSchema
2111 * Datatype library.
2112 *
2113 * Returns 1 if yes, 0 if no and -1 in case of error.
2114 */
2115static int
2116xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2117 const xmlChar *type ATTRIBUTE_UNUSED,
2118 const xmlChar *value1 ATTRIBUTE_UNUSED,
2119 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2120 TODO
2121 return(1);
2122}
2123
2124/**
2125 * xmlRelaxNGDefaultTypeHave:
2126 * @data: data needed for the library
2127 * @type: the type name
2128 *
2129 * Check if the given type is provided by
2130 * the default datatype library.
2131 *
2132 * Returns 1 if yes, 0 if no and -1 in case of error.
2133 */
2134static int
2135xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2136 if (type == NULL)
2137 return(-1);
2138 if (xmlStrEqual(type, BAD_CAST "string"))
2139 return(1);
2140 if (xmlStrEqual(type, BAD_CAST "token"))
2141 return(1);
2142 return(0);
2143}
2144
2145/**
2146 * xmlRelaxNGDefaultTypeCheck:
2147 * @data: data needed for the library
2148 * @type: the type name
2149 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002150 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002151 *
2152 * Check if the given type and value are validated by
2153 * the default datatype library.
2154 *
2155 * Returns 1 if yes, 0 if no and -1 in case of error.
2156 */
2157static int
2158xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2159 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002160 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002161 void **result ATTRIBUTE_UNUSED,
2162 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002163 if (value == NULL)
2164 return(-1);
2165 if (xmlStrEqual(type, BAD_CAST "string"))
2166 return(1);
2167 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002168 return(1);
2169 }
2170
2171 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002172}
2173
2174/**
2175 * xmlRelaxNGDefaultTypeCompare:
2176 * @data: data needed for the library
2177 * @type: the type name
2178 * @value1: the first value
2179 * @value2: the second value
2180 *
2181 * Compare two values accordingly a type from the default
2182 * datatype library.
2183 *
2184 * Returns 1 if yes, 0 if no and -1 in case of error.
2185 */
2186static int
2187xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2188 const xmlChar *type ATTRIBUTE_UNUSED,
2189 const xmlChar *value1 ATTRIBUTE_UNUSED,
2190 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002191 int ret = -1;
2192
2193 if (xmlStrEqual(type, BAD_CAST "string")) {
2194 ret = xmlStrEqual(value1, value2);
2195 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2196 if (!xmlStrEqual(value1, value2)) {
2197 xmlChar *nval, *nvalue;
2198
2199 /*
2200 * TODO: trivial optimizations are possible by
2201 * computing at compile-time
2202 */
2203 nval = xmlRelaxNGNormalize(NULL, value1);
2204 nvalue = xmlRelaxNGNormalize(NULL, value2);
2205
Daniel Veillardd4310742003-02-18 21:12:46 +00002206 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002207 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002208 else if (xmlStrEqual(nval, nvalue))
2209 ret = 1;
2210 else
2211 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002212 if (nval != NULL)
2213 xmlFree(nval);
2214 if (nvalue != NULL)
2215 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002216 } else
2217 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002218 }
2219 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002220}
2221
2222static int xmlRelaxNGTypeInitialized = 0;
2223static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2224
2225/**
2226 * xmlRelaxNGFreeTypeLibrary:
2227 * @lib: the type library structure
2228 * @namespace: the URI bound to the library
2229 *
2230 * Free the structure associated to the type library
2231 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002232static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002233xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2234 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2235 if (lib == NULL)
2236 return;
2237 if (lib->namespace != NULL)
2238 xmlFree((xmlChar *)lib->namespace);
2239 xmlFree(lib);
2240}
2241
2242/**
2243 * xmlRelaxNGRegisterTypeLibrary:
2244 * @namespace: the URI bound to the library
2245 * @data: data associated to the library
2246 * @have: the provide function
2247 * @check: the checking function
2248 * @comp: the comparison function
2249 *
2250 * Register a new type library
2251 *
2252 * Returns 0 in case of success and -1 in case of error.
2253 */
2254static int
2255xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2256 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002257 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2258 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002259 xmlRelaxNGTypeLibraryPtr lib;
2260 int ret;
2261
2262 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2263 (check == NULL) || (comp == NULL))
2264 return(-1);
2265 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2266 xmlGenericError(xmlGenericErrorContext,
2267 "Relax-NG types library '%s' already registered\n",
2268 namespace);
2269 return(-1);
2270 }
2271 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2272 if (lib == NULL) {
2273 xmlGenericError(xmlGenericErrorContext,
2274 "Relax-NG types library '%s' malloc() failed\n",
2275 namespace);
2276 return (-1);
2277 }
2278 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2279 lib->namespace = xmlStrdup(namespace);
2280 lib->data = data;
2281 lib->have = have;
2282 lib->comp = comp;
2283 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002284 lib->facet = facet;
2285 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002286 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2287 if (ret < 0) {
2288 xmlGenericError(xmlGenericErrorContext,
2289 "Relax-NG types library failed to register '%s'\n",
2290 namespace);
2291 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2292 return(-1);
2293 }
2294 return(0);
2295}
2296
2297/**
2298 * xmlRelaxNGInitTypes:
2299 *
2300 * Initilize the default type libraries.
2301 *
2302 * Returns 0 in case of success and -1 in case of error.
2303 */
2304static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002305xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002306 if (xmlRelaxNGTypeInitialized != 0)
2307 return(0);
2308 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2309 if (xmlRelaxNGRegisteredTypes == NULL) {
2310 xmlGenericError(xmlGenericErrorContext,
2311 "Failed to allocate sh table for Relax-NG types\n");
2312 return(-1);
2313 }
2314 xmlRelaxNGRegisterTypeLibrary(
2315 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2316 NULL,
2317 xmlRelaxNGSchemaTypeHave,
2318 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002319 xmlRelaxNGSchemaTypeCompare,
2320 xmlRelaxNGSchemaFacetCheck,
2321 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002322 xmlRelaxNGRegisterTypeLibrary(
2323 xmlRelaxNGNs,
2324 NULL,
2325 xmlRelaxNGDefaultTypeHave,
2326 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002327 xmlRelaxNGDefaultTypeCompare,
2328 NULL,
2329 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002330 xmlRelaxNGTypeInitialized = 1;
2331 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002332}
2333
2334/**
2335 * xmlRelaxNGCleanupTypes:
2336 *
2337 * Cleanup the default Schemas type library associated to RelaxNG
2338 */
2339void
2340xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002341 if (xmlRelaxNGTypeInitialized == 0)
2342 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002343 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002344 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2345 xmlRelaxNGFreeTypeLibrary);
2346 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002347}
2348
2349/************************************************************************
2350 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002351 * Compiling element content into regexp *
2352 * *
2353 * Sometime the element content can be compiled into a pure regexp, *
2354 * This allows a faster execution and streamability at that level *
2355 * *
2356 ************************************************************************/
2357
2358/**
2359 * xmlRelaxNGIsCompileable:
2360 * @define: the definition to check
2361 *
2362 * Check if a definition is nullable.
2363 *
2364 * Returns 1 if yes, 0 if no and -1 in case of error
2365 */
2366static int
2367xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2368 if (def == NULL) {
2369 return(-1);
2370 }
2371 switch(def->type) {
2372 case XML_RELAXNG_REF:
2373 case XML_RELAXNG_EXTERNALREF:
2374 case XML_RELAXNG_PARENTREF:
2375 case XML_RELAXNG_NOOP:
2376 case XML_RELAXNG_START:
2377 return(xmlRelaxNGIsCompileable(def->content));
2378 case XML_RELAXNG_TEXT:
2379 case XML_RELAXNG_DATATYPE:
2380 case XML_RELAXNG_LIST:
2381 case XML_RELAXNG_PARAM:
2382 case XML_RELAXNG_VALUE:
2383
2384 case XML_RELAXNG_EMPTY:
2385 case XML_RELAXNG_ELEMENT:
2386 return(1);
2387 case XML_RELAXNG_OPTIONAL:
2388 case XML_RELAXNG_ZEROORMORE:
2389 case XML_RELAXNG_ONEORMORE:
2390 case XML_RELAXNG_CHOICE:
2391 case XML_RELAXNG_GROUP:
2392 case XML_RELAXNG_DEF: {
2393 xmlRelaxNGDefinePtr list;
2394 int ret;
2395
2396 list = def->content;
2397 while (list != NULL) {
2398 ret = xmlRelaxNGIsCompileable(list);
2399 if (ret != 1)
2400 return(ret);
2401 list = list->next;
2402 }
2403 return(1);
2404 }
2405 case XML_RELAXNG_EXCEPT:
2406 case XML_RELAXNG_ATTRIBUTE:
2407 case XML_RELAXNG_INTERLEAVE:
2408 return(0);
2409 case XML_RELAXNG_NOT_ALLOWED:
2410 return(-1);
2411 }
2412 return(-1);
2413}
2414
2415/************************************************************************
2416 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002417 * Parsing functions *
2418 * *
2419 ************************************************************************/
2420
2421static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2422 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2423static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2424 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2425static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002426 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002427static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2428 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002429static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2430 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002431static int xmlRelaxNGParseGrammarContent(
2432 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002433static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2434 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2435 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002436static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2437 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002438static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2439 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002440
2441
2442#define IS_BLANK_NODE(n) \
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002443 ((((n)->type == XML_TEXT_NODE) || \
2444 ((n)->type == XML_CDATA_SECTION_NODE)) && \
2445 (xmlRelaxNGIsBlank((n)->content)))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002446
2447/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002448 * xmlRelaxNGIsNullable:
2449 * @define: the definition to verify
2450 *
2451 * Check if a definition is nullable.
2452 *
2453 * Returns 1 if yes, 0 if no and -1 in case of error
2454 */
2455static int
2456xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2457 int ret;
2458 if (define == NULL)
2459 return(-1);
2460
2461 if (define->flags & IS_NULLABLE)
2462 return(1);
2463 if (define->flags & IS_NOT_NULLABLE)
2464 return(0);
2465 switch (define->type) {
2466 case XML_RELAXNG_EMPTY:
2467 case XML_RELAXNG_TEXT:
2468 ret = 1; break;
2469 case XML_RELAXNG_NOOP:
2470 case XML_RELAXNG_DEF:
2471 case XML_RELAXNG_REF:
2472 case XML_RELAXNG_EXTERNALREF:
2473 case XML_RELAXNG_PARENTREF:
2474 case XML_RELAXNG_ONEORMORE:
2475 ret = xmlRelaxNGIsNullable(define->content);
2476 break;
2477 case XML_RELAXNG_EXCEPT:
2478 case XML_RELAXNG_NOT_ALLOWED:
2479 case XML_RELAXNG_ELEMENT:
2480 case XML_RELAXNG_DATATYPE:
2481 case XML_RELAXNG_PARAM:
2482 case XML_RELAXNG_VALUE:
2483 case XML_RELAXNG_LIST:
2484 case XML_RELAXNG_ATTRIBUTE:
2485 ret = 0; break;
2486 case XML_RELAXNG_CHOICE: {
2487 xmlRelaxNGDefinePtr list = define->content;
2488
2489 while (list != NULL) {
2490 ret = xmlRelaxNGIsNullable(list);
2491 if (ret != 0)
2492 goto done;
2493 list = list->next;
2494 }
2495 ret = 0; break;
2496 }
2497 case XML_RELAXNG_START:
2498 case XML_RELAXNG_INTERLEAVE:
2499 case XML_RELAXNG_GROUP: {
2500 xmlRelaxNGDefinePtr list = define->content;
2501
2502 while (list != NULL) {
2503 ret = xmlRelaxNGIsNullable(list);
2504 if (ret != 1)
2505 goto done;
2506 list = list->next;
2507 }
2508 return(1);
2509 }
2510 default:
2511 return(-1);
2512 }
2513done:
2514 if (ret == 0)
2515 define->flags |= IS_NOT_NULLABLE;
2516 if (ret == 1)
2517 define->flags |= IS_NULLABLE;
2518 return(ret);
2519}
2520
2521/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002522 * xmlRelaxNGIsBlank:
2523 * @str: a string
2524 *
2525 * Check if a string is ignorable c.f. 4.2. Whitespace
2526 *
2527 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2528 */
2529static int
2530xmlRelaxNGIsBlank(xmlChar *str) {
2531 if (str == NULL)
2532 return(1);
2533 while (*str != 0) {
2534 if (!(IS_BLANK(*str))) return(0);
2535 str++;
2536 }
2537 return(1);
2538}
2539
Daniel Veillard6eadf632003-01-23 18:29:16 +00002540/**
2541 * xmlRelaxNGGetDataTypeLibrary:
2542 * @ctxt: a Relax-NG parser context
2543 * @node: the current data or value element
2544 *
2545 * Applies algorithm from 4.3. datatypeLibrary attribute
2546 *
2547 * Returns the datatypeLibary value or NULL if not found
2548 */
2549static xmlChar *
2550xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2551 xmlNodePtr node) {
2552 xmlChar *ret, *escape;
2553
Daniel Veillard6eadf632003-01-23 18:29:16 +00002554 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2555 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2556 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002557 if (ret[0] == 0) {
2558 xmlFree(ret);
2559 return(NULL);
2560 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002561 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002562 if (escape == NULL) {
2563 return(ret);
2564 }
2565 xmlFree(ret);
2566 return(escape);
2567 }
2568 }
2569 node = node->parent;
2570 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002571 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2572 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002573 if (ret[0] == 0) {
2574 xmlFree(ret);
2575 return(NULL);
2576 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002577 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2578 if (escape == NULL) {
2579 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002580 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002581 xmlFree(ret);
2582 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002583 }
2584 node = node->parent;
2585 }
2586 return(NULL);
2587}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002588
2589/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002590 * xmlRelaxNGParseValue:
2591 * @ctxt: a Relax-NG parser context
2592 * @node: the data node.
2593 *
2594 * parse the content of a RelaxNG value node.
2595 *
2596 * Returns the definition pointer or NULL in case of error
2597 */
2598static xmlRelaxNGDefinePtr
2599xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2600 xmlRelaxNGDefinePtr def = NULL;
2601 xmlRelaxNGTypeLibraryPtr lib;
2602 xmlChar *type;
2603 xmlChar *library;
2604 int tmp;
2605
Daniel Veillardfd573f12003-03-16 17:52:32 +00002606 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002607 if (def == NULL)
2608 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002609 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002610
2611 type = xmlGetProp(node, BAD_CAST "type");
2612 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002613 xmlRelaxNGNormExtSpace(type);
2614 if (xmlValidateNCName(type, 0)) {
2615 if (ctxt->error != NULL)
2616 ctxt->error(ctxt->userData,
2617 "value type '%s' is not an NCName\n",
2618 type);
2619 ctxt->nbErrors++;
2620 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002621 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2622 if (library == NULL)
2623 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2624
2625 def->name = type;
2626 def->ns = library;
2627
2628 lib = (xmlRelaxNGTypeLibraryPtr)
2629 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2630 if (lib == NULL) {
2631 if (ctxt->error != NULL)
2632 ctxt->error(ctxt->userData,
2633 "Use of unregistered type library '%s'\n",
2634 library);
2635 ctxt->nbErrors++;
2636 def->data = NULL;
2637 } else {
2638 def->data = lib;
2639 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002640 if (ctxt->error != NULL)
2641 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002642 "Internal error with type library '%s': no 'have'\n",
2643 library);
2644 ctxt->nbErrors++;
2645 } else {
2646 tmp = lib->have(lib->data, def->name);
2647 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002648 if (ctxt->error != NULL)
2649 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002650 "Error type '%s' is not exported by type library '%s'\n",
2651 def->name, library);
2652 ctxt->nbErrors++;
2653 }
2654 }
2655 }
2656 }
2657 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002658 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002659 } else if (((node->children->type != XML_TEXT_NODE) &&
2660 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002661 (node->children->next != NULL)) {
2662 if (ctxt->error != NULL)
2663 ctxt->error(ctxt->userData,
2664 "Expecting a single text value for <value>content\n");
2665 ctxt->nbErrors++;
2666 } else {
2667 def->value = xmlNodeGetContent(node);
2668 if (def->value == NULL) {
2669 if (ctxt->error != NULL)
2670 ctxt->error(ctxt->userData,
2671 "Element <value> has no content\n");
2672 ctxt->nbErrors++;
2673 }
2674 }
2675 /* TODO check ahead of time that the value is okay per the type */
2676 return(def);
2677}
2678
2679/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002680 * xmlRelaxNGParseData:
2681 * @ctxt: a Relax-NG parser context
2682 * @node: the data node.
2683 *
2684 * parse the content of a RelaxNG data node.
2685 *
2686 * Returns the definition pointer or NULL in case of error
2687 */
2688static xmlRelaxNGDefinePtr
2689xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002690 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002691 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002692 xmlRelaxNGTypeLibraryPtr lib;
2693 xmlChar *type;
2694 xmlChar *library;
2695 xmlNodePtr content;
2696 int tmp;
2697
2698 type = xmlGetProp(node, BAD_CAST "type");
2699 if (type == NULL) {
2700 if (ctxt->error != NULL)
2701 ctxt->error(ctxt->userData,
2702 "data has no type\n");
2703 ctxt->nbErrors++;
2704 return(NULL);
2705 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002706 xmlRelaxNGNormExtSpace(type);
2707 if (xmlValidateNCName(type, 0)) {
2708 if (ctxt->error != NULL)
2709 ctxt->error(ctxt->userData,
2710 "data type '%s' is not an NCName\n",
2711 type);
2712 ctxt->nbErrors++;
2713 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002714 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2715 if (library == NULL)
2716 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2717
Daniel Veillardfd573f12003-03-16 17:52:32 +00002718 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002719 if (def == NULL) {
2720 xmlFree(type);
2721 return(NULL);
2722 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002723 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002724 def->name = type;
2725 def->ns = library;
2726
2727 lib = (xmlRelaxNGTypeLibraryPtr)
2728 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2729 if (lib == NULL) {
2730 if (ctxt->error != NULL)
2731 ctxt->error(ctxt->userData,
2732 "Use of unregistered type library '%s'\n",
2733 library);
2734 ctxt->nbErrors++;
2735 def->data = NULL;
2736 } else {
2737 def->data = lib;
2738 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002739 if (ctxt->error != NULL)
2740 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002741 "Internal error with type library '%s': no 'have'\n",
2742 library);
2743 ctxt->nbErrors++;
2744 } else {
2745 tmp = lib->have(lib->data, def->name);
2746 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002747 if (ctxt->error != NULL)
2748 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002749 "Error type '%s' is not exported by type library '%s'\n",
2750 def->name, library);
2751 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002752 } else if ((xmlStrEqual(library, BAD_CAST
2753 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2754 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2755 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2756 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002757 }
2758 }
2759 }
2760 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002761
2762 /*
2763 * Handle optional params
2764 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002765 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002766 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2767 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002768 if (xmlStrEqual(library,
2769 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2770 if (ctxt->error != NULL)
2771 ctxt->error(ctxt->userData,
2772 "Type library '%s' does not allow type parameters\n",
2773 library);
2774 ctxt->nbErrors++;
2775 content = content->next;
2776 while ((content != NULL) &&
2777 (xmlStrEqual(content->name, BAD_CAST "param")))
2778 content = content->next;
2779 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002780 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002781 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002782 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002783 param->name = xmlGetProp(content, BAD_CAST "name");
2784 if (param->name == NULL) {
2785 if (ctxt->error != NULL)
2786 ctxt->error(ctxt->userData,
2787 "param has no name\n");
2788 ctxt->nbErrors++;
2789 }
2790 param->value = xmlNodeGetContent(content);
2791 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002792 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002793 } else {
2794 lastparam->next = param;
2795 lastparam = param;
2796 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002797 if (lib != NULL) {
2798 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002799 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002800 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002801 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002802 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002803 /*
2804 * Handle optional except
2805 */
2806 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2807 xmlNodePtr child;
2808 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2809
Daniel Veillardfd573f12003-03-16 17:52:32 +00002810 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00002811 if (except == NULL) {
2812 return(def);
2813 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002814 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00002815 child = content->children;
2816 if (last == NULL) {
2817 def->content = except;
2818 } else {
2819 last->next = except;
2820 }
2821 if (child == NULL) {
2822 if (ctxt->error != NULL)
2823 ctxt->error(ctxt->userData,
2824 "except has no content\n");
2825 ctxt->nbErrors++;
2826 }
2827 while (child != NULL) {
2828 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2829 if (tmp2 != NULL) {
2830 if (last2 == NULL) {
2831 except->content = last2 = tmp2;
2832 } else {
2833 last2->next = tmp2;
2834 last2 = tmp2;
2835 }
2836 }
2837 child = child->next;
2838 }
2839 content = content->next;
2840 }
2841 /*
2842 * Check there is no unhandled data
2843 */
2844 if (content != NULL) {
2845 if (ctxt->error != NULL)
2846 ctxt->error(ctxt->userData,
2847 "Element data has unexpected content %s\n", content->name);
2848 ctxt->nbErrors++;
2849 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002850
2851 return(def);
2852}
2853
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002854static const xmlChar *invalidName = BAD_CAST "\1";
2855
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002856/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002857 * xmlRelaxNGCompareNameClasses:
2858 * @defs1: the first element/attribute defs
2859 * @defs2: the second element/attribute defs
2860 * @name: the restriction on the name
2861 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002862 *
2863 * Compare the 2 lists of element definitions. The comparison is
2864 * that if both lists do not accept the same QNames, it returns 1
2865 * If the 2 lists can accept the same QName the comparison returns 0
2866 *
2867 * Returns 1 disttinct, 0 if equal
2868 */
2869static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002870xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2871 xmlRelaxNGDefinePtr def2) {
2872 int ret = 1;
2873 xmlNode node;
2874 xmlNs ns;
2875 xmlRelaxNGValidCtxt ctxt;
2876 ctxt.flags = FLAGS_IGNORABLE;
2877
Daniel Veillard42f12e92003-03-07 18:32:59 +00002878 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
2879
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002880 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2881 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2882 if (def2->type == XML_RELAXNG_TEXT)
2883 return(1);
2884 if (def1->name != NULL) {
2885 node.name = def1->name;
2886 } else {
2887 node.name = invalidName;
2888 }
2889 node.ns = &ns;
2890 if (def1->ns != NULL) {
2891 if (def1->ns[0] == 0) {
2892 node.ns = NULL;
2893 } else {
2894 ns.href = def1->ns;
2895 }
2896 } else {
2897 ns.href = invalidName;
2898 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002899 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002900 if (def1->nameClass != NULL) {
2901 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2902 } else {
2903 ret = 0;
2904 }
2905 } else {
2906 ret = 1;
2907 }
2908 } else if (def1->type == XML_RELAXNG_TEXT) {
2909 if (def2->type == XML_RELAXNG_TEXT)
2910 return(0);
2911 return(1);
2912 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002913 TODO
2914 ret = 0;
2915 } else {
2916 TODO
2917 ret = 0;
2918 }
2919 if (ret == 0)
2920 return(ret);
2921 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2922 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2923 if (def2->name != NULL) {
2924 node.name = def2->name;
2925 } else {
2926 node.name = invalidName;
2927 }
2928 node.ns = &ns;
2929 if (def2->ns != NULL) {
2930 if (def2->ns[0] == 0) {
2931 node.ns = NULL;
2932 } else {
2933 ns.href = def2->ns;
2934 }
2935 } else {
2936 ns.href = invalidName;
2937 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002938 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002939 if (def2->nameClass != NULL) {
2940 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2941 } else {
2942 ret = 0;
2943 }
2944 } else {
2945 ret = 1;
2946 }
2947 } else {
2948 TODO
2949 ret = 0;
2950 }
2951
2952 return(ret);
2953}
2954
2955/**
2956 * xmlRelaxNGCompareElemDefLists:
2957 * @ctxt: a Relax-NG parser context
2958 * @defs1: the first list of element/attribute defs
2959 * @defs2: the second list of element/attribute defs
2960 *
2961 * Compare the 2 lists of element or attribute definitions. The comparison
2962 * is that if both lists do not accept the same QNames, it returns 1
2963 * If the 2 lists can accept the same QName the comparison returns 0
2964 *
2965 * Returns 1 disttinct, 0 if equal
2966 */
2967static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002968xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2969 xmlRelaxNGDefinePtr *def1,
2970 xmlRelaxNGDefinePtr *def2) {
2971 xmlRelaxNGDefinePtr *basedef2 = def2;
2972
Daniel Veillard154877e2003-01-30 12:17:05 +00002973 if ((def1 == NULL) || (def2 == NULL))
2974 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002975 if ((*def1 == NULL) || (*def2 == NULL))
2976 return(1);
2977 while (*def1 != NULL) {
2978 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00002979 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2980 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002981 def2++;
2982 }
2983 def2 = basedef2;
2984 def1++;
2985 }
2986 return(1);
2987}
2988
2989/**
2990 * xmlRelaxNGGetElements:
2991 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00002992 * @def: the definition definition
2993 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002994 *
2995 * Compute the list of top elements a definition can generate
2996 *
2997 * Returns a list of elements or NULL if none was found.
2998 */
2999static xmlRelaxNGDefinePtr *
3000xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003001 xmlRelaxNGDefinePtr def,
3002 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003003 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003004 int len = 0;
3005 int max = 0;
3006
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003007 /*
3008 * Don't run that check in case of error. Infinite recursion
3009 * becomes possible.
3010 */
3011 if (ctxt->nbErrors != 0)
3012 return(NULL);
3013
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003014 parent = NULL;
3015 cur = def;
3016 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003017 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3018 (cur->type == XML_RELAXNG_TEXT))) ||
3019 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003020 if (ret == NULL) {
3021 max = 10;
3022 ret = (xmlRelaxNGDefinePtr *)
3023 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3024 if (ret == NULL) {
3025 if (ctxt->error != NULL)
3026 ctxt->error(ctxt->userData,
3027 "Out of memory in element search\n");
3028 ctxt->nbErrors++;
3029 return(NULL);
3030 }
3031 } else if (max <= len) {
3032 max *= 2;
3033 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3034 if (ret == NULL) {
3035 if (ctxt->error != NULL)
3036 ctxt->error(ctxt->userData,
3037 "Out of memory in element search\n");
3038 ctxt->nbErrors++;
3039 return(NULL);
3040 }
3041 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003042 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003043 ret[len] = NULL;
3044 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3045 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3046 (cur->type == XML_RELAXNG_GROUP) ||
3047 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003048 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3049 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003050 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003051 (cur->type == XML_RELAXNG_REF) ||
3052 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003053 /*
3054 * Don't go within elements or attributes or string values.
3055 * Just gather the element top list
3056 */
3057 if (cur->content != NULL) {
3058 parent = cur;
3059 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003060 tmp = cur;
3061 while (tmp != NULL) {
3062 tmp->parent = parent;
3063 tmp = tmp->next;
3064 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003065 continue;
3066 }
3067 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003068 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003069 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003070 if (cur->next != NULL) {
3071 cur = cur->next;
3072 continue;
3073 }
3074 do {
3075 cur = cur->parent;
3076 if (cur == NULL) break;
3077 if (cur == def) return(ret);
3078 if (cur->next != NULL) {
3079 cur = cur->next;
3080 break;
3081 }
3082 } while (cur != NULL);
3083 }
3084 return(ret);
3085}
3086
3087/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003088 * xmlRelaxNGCheckChoiceDeterminism:
3089 * @ctxt: a Relax-NG parser context
3090 * @def: the choice definition
3091 *
3092 * Also used to find indeterministic pattern in choice
3093 */
3094static void
3095xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3096 xmlRelaxNGDefinePtr def) {
3097 xmlRelaxNGDefinePtr **list;
3098 xmlRelaxNGDefinePtr cur;
3099 int nbchild = 0, i, j, ret;
3100 int is_nullable = 0;
3101 int is_indeterminist = 0;
3102
3103 if ((def == NULL) ||
3104 (def->type != XML_RELAXNG_CHOICE))
3105 return;
3106
3107 /*
3108 * Don't run that check in case of error. Infinite recursion
3109 * becomes possible.
3110 */
3111 if (ctxt->nbErrors != 0)
3112 return;
3113
3114 is_nullable = xmlRelaxNGIsNullable(def);
3115
3116 cur = def->content;
3117 while (cur != NULL) {
3118 nbchild++;
3119 cur = cur->next;
3120 }
3121
3122 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3123 sizeof(xmlRelaxNGDefinePtr *));
3124 if (list == NULL) {
3125 if (ctxt->error != NULL)
3126 ctxt->error(ctxt->userData,
3127 "Out of memory in choice computation\n");
3128 ctxt->nbErrors++;
3129 return;
3130 }
3131 i = 0;
3132 cur = def->content;
3133 while (cur != NULL) {
3134 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
3135 i++;
3136 cur = cur->next;
3137 }
3138
3139 for (i = 0;i < nbchild;i++) {
3140 if (list[i] == NULL)
3141 continue;
3142 for (j = 0;j < i;j++) {
3143 if (list[j] == NULL)
3144 continue;
3145 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3146 if (ret == 0) {
3147 is_indeterminist = 1;
3148 }
3149 }
3150 }
3151 for (i = 0;i < nbchild;i++) {
3152 if (list[i] != NULL)
3153 xmlFree(list[i]);
3154 }
3155
3156 xmlFree(list);
3157 if (is_indeterminist) {
3158 def->flags |= IS_INDETERMINIST;
3159 }
3160}
3161
3162/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003163 * xmlRelaxNGCheckGroupAttrs:
3164 * @ctxt: a Relax-NG parser context
3165 * @def: the group definition
3166 *
3167 * Detects violations of rule 7.3
3168 */
3169static void
3170xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3171 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003172 xmlRelaxNGDefinePtr **list;
3173 xmlRelaxNGDefinePtr cur;
3174 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003175
3176 if ((def == NULL) ||
3177 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003178 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003179 return;
3180
3181 /*
3182 * Don't run that check in case of error. Infinite recursion
3183 * becomes possible.
3184 */
3185 if (ctxt->nbErrors != 0)
3186 return;
3187
Daniel Veillardfd573f12003-03-16 17:52:32 +00003188 cur = def->attrs;
3189 while (cur != NULL) {
3190 nbchild++;
3191 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003192 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003193 cur = def->content;
3194 while (cur != NULL) {
3195 nbchild++;
3196 cur = cur->next;
3197 }
3198
3199 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3200 sizeof(xmlRelaxNGDefinePtr *));
3201 if (list == NULL) {
3202 if (ctxt->error != NULL)
3203 ctxt->error(ctxt->userData,
3204 "Out of memory in group computation\n");
3205 ctxt->nbErrors++;
3206 return;
3207 }
3208 i = 0;
3209 cur = def->attrs;
3210 while (cur != NULL) {
3211 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3212 i++;
3213 cur = cur->next;
3214 }
3215 cur = def->content;
3216 while (cur != NULL) {
3217 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3218 i++;
3219 cur = cur->next;
3220 }
3221
3222 for (i = 0;i < nbchild;i++) {
3223 if (list[i] == NULL)
3224 continue;
3225 for (j = 0;j < i;j++) {
3226 if (list[j] == NULL)
3227 continue;
3228 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3229 if (ret == 0) {
3230 if (ctxt->error != NULL)
3231 ctxt->error(ctxt->userData,
3232 "Attributes conflicts in group\n");
3233 ctxt->nbErrors++;
3234 }
3235 }
3236 }
3237 for (i = 0;i < nbchild;i++) {
3238 if (list[i] != NULL)
3239 xmlFree(list[i]);
3240 }
3241
3242 xmlFree(list);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003243}
3244
3245/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003246 * xmlRelaxNGComputeInterleaves:
3247 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003248 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003249 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003250 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003251 * A lot of work for preprocessing interleave definitions
3252 * is potentially needed to get a decent execution speed at runtime
3253 * - trying to get a total order on the element nodes generated
3254 * by the interleaves, order the list of interleave definitions
3255 * following that order.
3256 * - if <text/> is used to handle mixed content, it is better to
3257 * flag this in the define and simplify the runtime checking
3258 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003259 */
3260static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003261xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3262 xmlRelaxNGParserCtxtPtr ctxt,
3263 xmlChar *name ATTRIBUTE_UNUSED) {
3264 xmlRelaxNGDefinePtr cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003265
Daniel Veillardfd573f12003-03-16 17:52:32 +00003266 xmlRelaxNGPartitionPtr partitions = NULL;
3267 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3268 xmlRelaxNGInterleaveGroupPtr group;
3269 int i,j,ret;
3270 int nbgroups = 0;
3271 int nbchild = 0;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003272
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003273 /*
3274 * Don't run that check in case of error. Infinite recursion
3275 * becomes possible.
3276 */
3277 if (ctxt->nbErrors != 0)
3278 return;
3279
Daniel Veillardfd573f12003-03-16 17:52:32 +00003280#ifdef DEBUG_INTERLEAVE
3281 xmlGenericError(xmlGenericErrorContext,
3282 "xmlRelaxNGComputeInterleaves(%s)\n",
3283 name);
3284#endif
3285 cur = def->content;
3286 while (cur != NULL) {
3287 nbchild++;
3288 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003289 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003290
3291#ifdef DEBUG_INTERLEAVE
3292 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3293#endif
3294 groups = (xmlRelaxNGInterleaveGroupPtr *)
3295 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3296 if (groups == NULL)
3297 goto error;
3298 cur = def->content;
3299 while (cur != NULL) {
3300 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3301 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3302 if (groups[nbgroups] == NULL)
3303 goto error;
3304 groups[nbgroups]->rule = cur;
3305 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3306 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3307 nbgroups++;
3308 cur = cur->next;
3309 }
3310#ifdef DEBUG_INTERLEAVE
3311 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3312#endif
3313
3314 /*
3315 * Let's check that all rules makes a partitions according to 7.4
3316 */
3317 partitions = (xmlRelaxNGPartitionPtr)
3318 xmlMalloc(sizeof(xmlRelaxNGPartition));
3319 if (partitions == NULL)
3320 goto error;
3321 partitions->nbgroups = nbgroups;
3322 for (i = 0;i < nbgroups;i++) {
3323 group = groups[i];
3324 for (j = i+1;j < nbgroups;j++) {
3325 if (groups[j] == NULL)
3326 continue;
3327 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3328 groups[j]->defs);
3329 if (ret == 0) {
3330 if (ctxt->error != NULL)
3331 ctxt->error(ctxt->userData,
3332 "Element or text conflicts in interleave\n");
3333 ctxt->nbErrors++;
3334 }
3335 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3336 groups[j]->attrs);
3337 if (ret == 0) {
3338 if (ctxt->error != NULL)
3339 ctxt->error(ctxt->userData,
3340 "Attributes conflicts in interleave\n");
3341 ctxt->nbErrors++;
3342 }
3343 }
3344 }
3345 partitions->groups = groups;
3346
3347 /*
3348 * and save the partition list back in the def
3349 */
3350 def->data = partitions;
3351 return;
3352
3353error:
3354 if (ctxt->error != NULL)
3355 ctxt->error(ctxt->userData,
3356 "Out of memory in interleave computation\n");
3357 ctxt->nbErrors++;
3358 if (groups != NULL) {
3359 for (i = 0;i < nbgroups;i++)
3360 if (groups[i] != NULL) {
3361 if (groups[i]->defs != NULL)
3362 xmlFree(groups[i]->defs);
3363 xmlFree(groups[i]);
3364 }
3365 xmlFree(groups);
3366 }
3367 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003368}
3369
3370/**
3371 * xmlRelaxNGParseInterleave:
3372 * @ctxt: a Relax-NG parser context
3373 * @node: the data node.
3374 *
3375 * parse the content of a RelaxNG interleave node.
3376 *
3377 * Returns the definition pointer or NULL in case of error
3378 */
3379static xmlRelaxNGDefinePtr
3380xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3381 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003382 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003383 xmlNodePtr child;
3384
Daniel Veillardfd573f12003-03-16 17:52:32 +00003385 def = xmlRelaxNGNewDefine(ctxt, node);
3386 if (def == NULL) {
3387 return(NULL);
3388 }
3389 def->type = XML_RELAXNG_INTERLEAVE;
3390
3391 if (ctxt->interleaves == NULL)
3392 ctxt->interleaves = xmlHashCreate(10);
3393 if (ctxt->interleaves == NULL) {
3394 if (ctxt->error != NULL)
3395 ctxt->error(ctxt->userData,
3396 "Failed to create interleaves hash table\n");
3397 ctxt->nbErrors++;
3398 } else {
3399 char name[32];
3400
3401 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3402 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3403 if (ctxt->error != NULL)
3404 ctxt->error(ctxt->userData,
3405 "Failed to add %s to hash table\n", name);
3406 ctxt->nbErrors++;
3407 }
3408 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003409 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003410 if (child == NULL) {
3411 if (ctxt->error != NULL)
3412 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3413 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003414 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003415 while (child != NULL) {
3416 if (IS_RELAXNG(child, "element")) {
3417 cur = xmlRelaxNGParseElement(ctxt, child);
3418 } else {
3419 cur = xmlRelaxNGParsePattern(ctxt, child);
3420 }
3421 if (cur != NULL) {
3422 cur->parent = def;
3423 if (last == NULL) {
3424 def->content = last = cur;
3425 } else {
3426 last->next = cur;
3427 last = cur;
3428 }
3429 }
3430 child = child->next;
3431 }
3432
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003433 return(def);
3434}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003435
3436/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003437 * xmlRelaxNGParseInclude:
3438 * @ctxt: a Relax-NG parser context
3439 * @node: the include node
3440 *
3441 * Integrate the content of an include node in the current grammar
3442 *
3443 * Returns 0 in case of success or -1 in case of error
3444 */
3445static int
3446xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3447 xmlRelaxNGIncludePtr incl;
3448 xmlNodePtr root;
3449 int ret = 0, tmp;
3450
3451 incl = node->_private;
3452 if (incl == NULL) {
3453 if (ctxt->error != NULL)
3454 ctxt->error(ctxt->userData,
3455 "Include node has no data\n");
3456 ctxt->nbErrors++;
3457 return(-1);
3458 }
3459 root = xmlDocGetRootElement(incl->doc);
3460 if (root == NULL) {
3461 if (ctxt->error != NULL)
3462 ctxt->error(ctxt->userData,
3463 "Include document is empty\n");
3464 ctxt->nbErrors++;
3465 return(-1);
3466 }
3467 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3468 if (ctxt->error != NULL)
3469 ctxt->error(ctxt->userData,
3470 "Include document root is not a grammar\n");
3471 ctxt->nbErrors++;
3472 return(-1);
3473 }
3474
3475 /*
3476 * Merge the definition from both the include and the internal list
3477 */
3478 if (root->children != NULL) {
3479 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3480 if (tmp != 0)
3481 ret = -1;
3482 }
3483 if (node->children != NULL) {
3484 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3485 if (tmp != 0)
3486 ret = -1;
3487 }
3488 return(ret);
3489}
3490
3491/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003492 * xmlRelaxNGParseDefine:
3493 * @ctxt: a Relax-NG parser context
3494 * @node: the define node
3495 *
3496 * parse the content of a RelaxNG define element node.
3497 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003498 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003499 */
3500static int
3501xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3502 xmlChar *name;
3503 int ret = 0, tmp;
3504 xmlRelaxNGDefinePtr def;
3505 const xmlChar *olddefine;
3506
3507 name = xmlGetProp(node, BAD_CAST "name");
3508 if (name == NULL) {
3509 if (ctxt->error != NULL)
3510 ctxt->error(ctxt->userData,
3511 "define has no name\n");
3512 ctxt->nbErrors++;
3513 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003514 xmlRelaxNGNormExtSpace(name);
3515 if (xmlValidateNCName(name, 0)) {
3516 if (ctxt->error != NULL)
3517 ctxt->error(ctxt->userData,
3518 "define name '%s' is not an NCName\n",
3519 name);
3520 ctxt->nbErrors++;
3521 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003522 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003523 if (def == NULL) {
3524 xmlFree(name);
3525 return(-1);
3526 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003527 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003528 def->name = name;
3529 if (node->children == NULL) {
3530 if (ctxt->error != NULL)
3531 ctxt->error(ctxt->userData,
3532 "define has no children\n");
3533 ctxt->nbErrors++;
3534 } else {
3535 olddefine = ctxt->define;
3536 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003537 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003538 ctxt->define = olddefine;
3539 }
3540 if (ctxt->grammar->defs == NULL)
3541 ctxt->grammar->defs = xmlHashCreate(10);
3542 if (ctxt->grammar->defs == NULL) {
3543 if (ctxt->error != NULL)
3544 ctxt->error(ctxt->userData,
3545 "Could not create definition hash\n");
3546 ctxt->nbErrors++;
3547 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003548 } else {
3549 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3550 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003551 xmlRelaxNGDefinePtr prev;
3552
3553 prev = xmlHashLookup(ctxt->grammar->defs, name);
3554 if (prev == NULL) {
3555 if (ctxt->error != NULL)
3556 ctxt->error(ctxt->userData,
3557 "Internal error on define aggregation of %s\n",
3558 name);
3559 ctxt->nbErrors++;
3560 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003561 } else {
3562 while (prev->nextHash != NULL)
3563 prev = prev->nextHash;
3564 prev->nextHash = def;
3565 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003566 }
3567 }
3568 }
3569 return(ret);
3570}
3571
3572/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003573 * xmlRelaxNGProcessExternalRef:
3574 * @ctxt: the parser context
3575 * @node: the externlRef node
3576 *
3577 * Process and compile an externlRef node
3578 *
3579 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3580 */
3581static xmlRelaxNGDefinePtr
3582xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3583 xmlRelaxNGDocumentPtr docu;
3584 xmlNodePtr root, tmp;
3585 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003586 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003587 xmlRelaxNGDefinePtr def;
3588
3589 docu = node->_private;
3590 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003591 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003592 if (def == NULL)
3593 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003594 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003595
3596 if (docu->content == NULL) {
3597 /*
3598 * Then do the parsing for good
3599 */
3600 root = xmlDocGetRootElement(docu->doc);
3601 if (root == NULL) {
3602 if (ctxt->error != NULL)
3603 ctxt->error(ctxt->userData,
3604 "xmlRelaxNGParse: %s is empty\n",
3605 ctxt->URL);
3606 ctxt->nbErrors++;
3607 return (NULL);
3608 }
3609 /*
3610 * ns transmission rules
3611 */
3612 ns = xmlGetProp(root, BAD_CAST "ns");
3613 if (ns == NULL) {
3614 tmp = node;
3615 while ((tmp != NULL) &&
3616 (tmp->type == XML_ELEMENT_NODE)) {
3617 ns = xmlGetProp(tmp, BAD_CAST "ns");
3618 if (ns != NULL) {
3619 break;
3620 }
3621 tmp = tmp->parent;
3622 }
3623 if (ns != NULL) {
3624 xmlSetProp(root, BAD_CAST "ns", ns);
3625 newNs = 1;
3626 xmlFree(ns);
3627 }
3628 } else {
3629 xmlFree(ns);
3630 }
3631
3632 /*
3633 * Parsing to get a precompiled schemas.
3634 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003635 oldflags = ctxt->flags;
3636 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003637 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003638 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003639 if ((docu->schema != NULL) &&
3640 (docu->schema->topgrammar != NULL)) {
3641 docu->content = docu->schema->topgrammar->start;
3642 }
3643
3644 /*
3645 * the externalRef may be reused in a different ns context
3646 */
3647 if (newNs == 1) {
3648 xmlUnsetProp(root, BAD_CAST "ns");
3649 }
3650 }
3651 def->content = docu->content;
3652 } else {
3653 def = NULL;
3654 }
3655 return(def);
3656}
3657
3658/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003659 * xmlRelaxNGParsePattern:
3660 * @ctxt: a Relax-NG parser context
3661 * @node: the pattern node.
3662 *
3663 * parse the content of a RelaxNG pattern node.
3664 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003665 * Returns the definition pointer or NULL in case of error or if no
3666 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003667 */
3668static xmlRelaxNGDefinePtr
3669xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3670 xmlRelaxNGDefinePtr def = NULL;
3671
Daniel Veillardd2298792003-02-14 16:54:11 +00003672 if (node == NULL) {
3673 return(NULL);
3674 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003675 if (IS_RELAXNG(node, "element")) {
3676 def = xmlRelaxNGParseElement(ctxt, node);
3677 } else if (IS_RELAXNG(node, "attribute")) {
3678 def = xmlRelaxNGParseAttribute(ctxt, node);
3679 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003680 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003681 if (def == NULL)
3682 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003683 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003684 if (node->children != NULL) {
3685 if (ctxt->error != NULL)
3686 ctxt->error(ctxt->userData, "empty: had a child node\n");
3687 ctxt->nbErrors++;
3688 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003689 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003690 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003691 if (def == NULL)
3692 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003693 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003694 if (node->children != NULL) {
3695 if (ctxt->error != NULL)
3696 ctxt->error(ctxt->userData, "text: had a child node\n");
3697 ctxt->nbErrors++;
3698 }
3699 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003700 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003701 if (def == NULL)
3702 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003703 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003704 if (node->children == NULL) {
3705 if (ctxt->error != NULL)
3706 ctxt->error(ctxt->userData,
3707 "Element %s is empty\n", node->name);
3708 ctxt->nbErrors++;
3709 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003710 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00003711 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003712 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003713 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003714 if (def == NULL)
3715 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003716 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00003717 if (node->children == NULL) {
3718 if (ctxt->error != NULL)
3719 ctxt->error(ctxt->userData,
3720 "Element %s is empty\n", node->name);
3721 ctxt->nbErrors++;
3722 } else {
3723 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3724 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003725 } else if (IS_RELAXNG(node, "optional")) {
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_OPTIONAL;
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 {
3736 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
3737 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003738 } else if (IS_RELAXNG(node, "choice")) {
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_CHOICE;
3743 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, 0);
3750 }
3751 } else if (IS_RELAXNG(node, "group")) {
3752 def = xmlRelaxNGNewDefine(ctxt, node);
3753 if (def == NULL)
3754 return(NULL);
3755 def->type = XML_RELAXNG_GROUP;
3756 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, 0);
3763 }
3764 } else if (IS_RELAXNG(node, "ref")) {
3765 def = xmlRelaxNGNewDefine(ctxt, node);
3766 if (def == NULL)
3767 return(NULL);
3768 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003769 def->name = xmlGetProp(node, BAD_CAST "name");
3770 if (def->name == NULL) {
3771 if (ctxt->error != NULL)
3772 ctxt->error(ctxt->userData,
3773 "ref has no name\n");
3774 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003775 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003776 xmlRelaxNGNormExtSpace(def->name);
3777 if (xmlValidateNCName(def->name, 0)) {
3778 if (ctxt->error != NULL)
3779 ctxt->error(ctxt->userData,
3780 "ref name '%s' is not an NCName\n",
3781 def->name);
3782 ctxt->nbErrors++;
3783 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003784 }
3785 if (node->children != NULL) {
3786 if (ctxt->error != NULL)
3787 ctxt->error(ctxt->userData,
3788 "ref is not empty\n");
3789 ctxt->nbErrors++;
3790 }
3791 if (ctxt->grammar->refs == NULL)
3792 ctxt->grammar->refs = xmlHashCreate(10);
3793 if (ctxt->grammar->refs == NULL) {
3794 if (ctxt->error != NULL)
3795 ctxt->error(ctxt->userData,
3796 "Could not create references hash\n");
3797 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003798 def = NULL;
3799 } else {
3800 int tmp;
3801
3802 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
3803 if (tmp < 0) {
3804 xmlRelaxNGDefinePtr prev;
3805
3806 prev = (xmlRelaxNGDefinePtr)
3807 xmlHashLookup(ctxt->grammar->refs, def->name);
3808 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003809 if (def->name != NULL) {
3810 if (ctxt->error != NULL)
3811 ctxt->error(ctxt->userData,
3812 "Error refs definitions '%s'\n",
3813 def->name);
3814 } else {
3815 if (ctxt->error != NULL)
3816 ctxt->error(ctxt->userData,
3817 "Error refs definitions\n");
3818 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003819 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003820 def = NULL;
3821 } else {
3822 def->nextHash = prev->nextHash;
3823 prev->nextHash = def;
3824 }
3825 }
3826 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003827 } else if (IS_RELAXNG(node, "data")) {
3828 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003829 } else if (IS_RELAXNG(node, "value")) {
3830 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003831 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003832 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00003833 if (def == NULL)
3834 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003835 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00003836 if (node->children == NULL) {
3837 if (ctxt->error != NULL)
3838 ctxt->error(ctxt->userData,
3839 "Element %s is empty\n", node->name);
3840 ctxt->nbErrors++;
3841 } else {
3842 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
3843 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003844 } else if (IS_RELAXNG(node, "interleave")) {
3845 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003846 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00003847 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003848 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003849 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003850 if (def == NULL)
3851 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003852 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003853 if (node->children != NULL) {
3854 if (ctxt->error != NULL)
3855 ctxt->error(ctxt->userData,
3856 "xmlRelaxNGParse: notAllowed element is not empty\n");
3857 ctxt->nbErrors++;
3858 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003859 } else if (IS_RELAXNG(node, "grammar")) {
3860 xmlRelaxNGGrammarPtr grammar, old;
3861 xmlRelaxNGGrammarPtr oldparent;
3862
Daniel Veillardc482e262003-02-26 14:48:48 +00003863#ifdef DEBUG_GRAMMAR
3864 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
3865#endif
3866
Daniel Veillard419a7682003-02-03 23:22:49 +00003867 oldparent = ctxt->parentgrammar;
3868 old = ctxt->grammar;
3869 ctxt->parentgrammar = old;
3870 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
3871 if (old != NULL) {
3872 ctxt->grammar = old;
3873 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00003874#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00003875 if (grammar != NULL) {
3876 grammar->next = old->next;
3877 old->next = grammar;
3878 }
Daniel Veillardc482e262003-02-26 14:48:48 +00003879#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00003880 }
3881 if (grammar != NULL)
3882 def = grammar->start;
3883 else
3884 def = NULL;
3885 } else if (IS_RELAXNG(node, "parentRef")) {
3886 if (ctxt->parentgrammar == NULL) {
3887 if (ctxt->error != NULL)
3888 ctxt->error(ctxt->userData,
3889 "Use of parentRef without a parent grammar\n");
3890 ctxt->nbErrors++;
3891 return(NULL);
3892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003893 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00003894 if (def == NULL)
3895 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003896 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00003897 def->name = xmlGetProp(node, BAD_CAST "name");
3898 if (def->name == NULL) {
3899 if (ctxt->error != NULL)
3900 ctxt->error(ctxt->userData,
3901 "parentRef has no name\n");
3902 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00003903 } else {
3904 xmlRelaxNGNormExtSpace(def->name);
3905 if (xmlValidateNCName(def->name, 0)) {
3906 if (ctxt->error != NULL)
3907 ctxt->error(ctxt->userData,
3908 "parentRef name '%s' is not an NCName\n",
3909 def->name);
3910 ctxt->nbErrors++;
3911 }
Daniel Veillard419a7682003-02-03 23:22:49 +00003912 }
3913 if (node->children != NULL) {
3914 if (ctxt->error != NULL)
3915 ctxt->error(ctxt->userData,
3916 "parentRef is not empty\n");
3917 ctxt->nbErrors++;
3918 }
3919 if (ctxt->parentgrammar->refs == NULL)
3920 ctxt->parentgrammar->refs = xmlHashCreate(10);
3921 if (ctxt->parentgrammar->refs == NULL) {
3922 if (ctxt->error != NULL)
3923 ctxt->error(ctxt->userData,
3924 "Could not create references hash\n");
3925 ctxt->nbErrors++;
3926 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00003927 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00003928 int tmp;
3929
3930 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3931 if (tmp < 0) {
3932 xmlRelaxNGDefinePtr prev;
3933
3934 prev = (xmlRelaxNGDefinePtr)
3935 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3936 if (prev == NULL) {
3937 if (ctxt->error != NULL)
3938 ctxt->error(ctxt->userData,
3939 "Internal error parentRef definitions '%s'\n",
3940 def->name);
3941 ctxt->nbErrors++;
3942 def = NULL;
3943 } else {
3944 def->nextHash = prev->nextHash;
3945 prev->nextHash = def;
3946 }
3947 }
3948 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003949 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003950 if (node->children == NULL) {
3951 if (ctxt->error != NULL)
3952 ctxt->error(ctxt->userData,
3953 "Mixed is empty\n");
3954 ctxt->nbErrors++;
3955 def = NULL;
3956 } else {
3957 def = xmlRelaxNGParseInterleave(ctxt, node);
3958 if (def != NULL) {
3959 xmlRelaxNGDefinePtr tmp;
3960
3961 if ((def->content != NULL) && (def->content->next != NULL)) {
3962 tmp = xmlRelaxNGNewDefine(ctxt, node);
3963 if (tmp != NULL) {
3964 tmp->type = XML_RELAXNG_GROUP;
3965 tmp->content = def->content;
3966 def->content = tmp;
3967 }
3968 }
3969
3970 tmp = xmlRelaxNGNewDefine(ctxt, node);
3971 if (tmp == NULL)
3972 return(def);
3973 tmp->type = XML_RELAXNG_TEXT;
3974 tmp->next = def->content;
3975 def->content = tmp;
3976 }
3977 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003978 } else {
3979 if (ctxt->error != NULL)
3980 ctxt->error(ctxt->userData,
3981 "Unexpected node %s is not a pattern\n",
3982 node->name);
3983 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003984 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003985 }
3986 return(def);
3987}
3988
3989/**
3990 * xmlRelaxNGParseAttribute:
3991 * @ctxt: a Relax-NG parser context
3992 * @node: the element node
3993 *
3994 * parse the content of a RelaxNG attribute node.
3995 *
3996 * Returns the definition pointer or NULL in case of error.
3997 */
3998static xmlRelaxNGDefinePtr
3999xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004000 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004001 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004002 int old_flags;
4003
Daniel Veillardfd573f12003-03-16 17:52:32 +00004004 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004005 if (ret == NULL)
4006 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004007 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004008 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004009 child = node->children;
4010 if (child == NULL) {
4011 if (ctxt->error != NULL)
4012 ctxt->error(ctxt->userData,
4013 "xmlRelaxNGParseattribute: attribute has no children\n");
4014 ctxt->nbErrors++;
4015 return(ret);
4016 }
4017 old_flags = ctxt->flags;
4018 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004019 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4020 if (cur != NULL)
4021 child = child->next;
4022
Daniel Veillardd2298792003-02-14 16:54:11 +00004023 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004024 cur = xmlRelaxNGParsePattern(ctxt, child);
4025 if (cur != NULL) {
4026 switch (cur->type) {
4027 case XML_RELAXNG_EMPTY:
4028 case XML_RELAXNG_NOT_ALLOWED:
4029 case XML_RELAXNG_TEXT:
4030 case XML_RELAXNG_ELEMENT:
4031 case XML_RELAXNG_DATATYPE:
4032 case XML_RELAXNG_VALUE:
4033 case XML_RELAXNG_LIST:
4034 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004035 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004036 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004037 case XML_RELAXNG_DEF:
4038 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004039 case XML_RELAXNG_ZEROORMORE:
4040 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004041 case XML_RELAXNG_CHOICE:
4042 case XML_RELAXNG_GROUP:
4043 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004044 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004045 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004046 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004047 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004048 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004049 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004050 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004051 if (ctxt->error != NULL)
4052 ctxt->error(ctxt->userData,
4053 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004054 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004055 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004056 case XML_RELAXNG_NOOP:
4057 TODO
4058 if (ctxt->error != NULL)
4059 ctxt->error(ctxt->userData,
4060 "Internal error, noop found\n");
4061 ctxt->nbErrors++;
4062 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004063 }
4064 }
4065 child = child->next;
4066 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004067 if (child != NULL) {
4068 if (ctxt->error != NULL)
4069 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4070 ctxt->nbErrors++;
4071 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004072 ctxt->flags = old_flags;
4073 return(ret);
4074}
4075
4076/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004077 * xmlRelaxNGParseExceptNameClass:
4078 * @ctxt: a Relax-NG parser context
4079 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004080 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004081 *
4082 * parse the content of a RelaxNG nameClass node.
4083 *
4084 * Returns the definition pointer or NULL in case of error.
4085 */
4086static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004087xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4088 xmlNodePtr node, int attr) {
4089 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4090 xmlNodePtr child;
4091
Daniel Veillardd2298792003-02-14 16:54:11 +00004092 if (!IS_RELAXNG(node, "except")) {
4093 if (ctxt->error != NULL)
4094 ctxt->error(ctxt->userData,
4095 "Expecting an except node\n");
4096 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004097 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004098 }
4099 if (node->next != NULL) {
4100 if (ctxt->error != NULL)
4101 ctxt->error(ctxt->userData,
4102 "exceptNameClass allows only a single except node\n");
4103 ctxt->nbErrors++;
4104 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004105 if (node->children == NULL) {
4106 if (ctxt->error != NULL)
4107 ctxt->error(ctxt->userData,
4108 "except has no content\n");
4109 ctxt->nbErrors++;
4110 return(NULL);
4111 }
4112
Daniel Veillardfd573f12003-03-16 17:52:32 +00004113 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004114 if (ret == NULL)
4115 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004116 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004117 child = node->children;
4118 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004119 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004120 if (cur == NULL)
4121 break;
4122 if (attr)
4123 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004124 else
4125 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004126
Daniel Veillard419a7682003-02-03 23:22:49 +00004127 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004128 if (last == NULL) {
4129 ret->content = cur;
4130 } else {
4131 last->next = cur;
4132 }
4133 last = cur;
4134 }
4135 child = child->next;
4136 }
4137
4138 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004139}
4140
4141/**
4142 * xmlRelaxNGParseNameClass:
4143 * @ctxt: a Relax-NG parser context
4144 * @node: the nameClass node
4145 * @def: the current definition
4146 *
4147 * parse the content of a RelaxNG nameClass node.
4148 *
4149 * Returns the definition pointer or NULL in case of error.
4150 */
4151static xmlRelaxNGDefinePtr
4152xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4153 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004154 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004155 xmlChar *val;
4156
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004157 ret = def;
4158 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4159 (IS_RELAXNG(node, "nsName"))) {
4160 if ((def->type != XML_RELAXNG_ELEMENT) &&
4161 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004163 if (ret == NULL)
4164 return(NULL);
4165 ret->parent = def;
4166 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4167 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004168 else
4169 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004170 }
4171 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004172 if (IS_RELAXNG(node, "name")) {
4173 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004174 xmlRelaxNGNormExtSpace(val);
4175 if (xmlValidateNCName(val, 0)) {
4176 if (ctxt->error != NULL) {
4177 if (node->parent != NULL)
4178 ctxt->error(ctxt->userData,
4179 "Element %s name '%s' is not an NCName\n",
4180 node->parent->name, val);
4181 else
4182 ctxt->error(ctxt->userData,
4183 "name '%s' is not an NCName\n",
4184 val);
4185 }
4186 ctxt->nbErrors++;
4187 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004188 ret->name = val;
4189 val = xmlGetProp(node, BAD_CAST "ns");
4190 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004191 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4192 (val != NULL) &&
4193 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4194 ctxt->error(ctxt->userData,
4195 "Attribute with namespace '%s' is not allowed\n",
4196 val);
4197 ctxt->nbErrors++;
4198 }
4199 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4200 (val != NULL) &&
4201 (val[0] == 0) &&
4202 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4203 ctxt->error(ctxt->userData,
4204 "Attribute with QName 'xmlns' is not allowed\n",
4205 val);
4206 ctxt->nbErrors++;
4207 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004208 } else if (IS_RELAXNG(node, "anyName")) {
4209 ret->name = NULL;
4210 ret->ns = NULL;
4211 if (node->children != NULL) {
4212 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004213 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4214 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004215 }
4216 } else if (IS_RELAXNG(node, "nsName")) {
4217 ret->name = NULL;
4218 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4219 if (ret->ns == NULL) {
4220 if (ctxt->error != NULL)
4221 ctxt->error(ctxt->userData,
4222 "nsName has no ns attribute\n");
4223 ctxt->nbErrors++;
4224 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004225 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4226 (ret->ns != NULL) &&
4227 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4228 ctxt->error(ctxt->userData,
4229 "Attribute with namespace '%s' is not allowed\n",
4230 ret->ns);
4231 ctxt->nbErrors++;
4232 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004233 if (node->children != NULL) {
4234 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004235 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4236 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004237 }
4238 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004239 xmlNodePtr child;
4240 xmlRelaxNGDefinePtr last = NULL;
4241
4242 ret = xmlRelaxNGNewDefine(ctxt, node);
4243 if (ret == NULL)
4244 return(NULL);
4245 ret->parent = def;
4246 ret->type = XML_RELAXNG_CHOICE;
4247
Daniel Veillardd2298792003-02-14 16:54:11 +00004248 if (node->children == NULL) {
4249 if (ctxt->error != NULL)
4250 ctxt->error(ctxt->userData,
4251 "Element choice is empty\n");
4252 ctxt->nbErrors++;
4253 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004254
4255 child = node->children;
4256 while (child != NULL) {
4257 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4258 if (tmp != NULL) {
4259 if (last == NULL) {
4260 last = ret->nameClass = tmp;
4261 } else {
4262 last->next = tmp;
4263 last = tmp;
4264 }
4265 }
4266 child = child->next;
4267 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004268 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004269 } else {
4270 if (ctxt->error != NULL)
4271 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004272 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004273 node->name);
4274 ctxt->nbErrors++;
4275 return(NULL);
4276 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004277 if (ret != def) {
4278 if (def->nameClass == NULL) {
4279 def->nameClass = ret;
4280 } else {
4281 tmp = def->nameClass;
4282 while (tmp->next != NULL) {
4283 tmp = tmp->next;
4284 }
4285 tmp->next = ret;
4286 }
4287 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004288 return(ret);
4289}
4290
4291/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004292 * xmlRelaxNGParseElement:
4293 * @ctxt: a Relax-NG parser context
4294 * @node: the element node
4295 *
4296 * parse the content of a RelaxNG element node.
4297 *
4298 * Returns the definition pointer or NULL in case of error.
4299 */
4300static xmlRelaxNGDefinePtr
4301xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4302 xmlRelaxNGDefinePtr ret, cur, last;
4303 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004304 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004305
Daniel Veillardfd573f12003-03-16 17:52:32 +00004306 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004307 if (ret == NULL)
4308 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004309 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004310 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004311 child = node->children;
4312 if (child == NULL) {
4313 if (ctxt->error != NULL)
4314 ctxt->error(ctxt->userData,
4315 "xmlRelaxNGParseElement: element has no children\n");
4316 ctxt->nbErrors++;
4317 return(ret);
4318 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004319 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4320 if (cur != NULL)
4321 child = child->next;
4322
Daniel Veillard6eadf632003-01-23 18:29:16 +00004323 if (child == NULL) {
4324 if (ctxt->error != NULL)
4325 ctxt->error(ctxt->userData,
4326 "xmlRelaxNGParseElement: element has no content\n");
4327 ctxt->nbErrors++;
4328 return(ret);
4329 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004330 olddefine = ctxt->define;
4331 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004332 last = NULL;
4333 while (child != NULL) {
4334 cur = xmlRelaxNGParsePattern(ctxt, child);
4335 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004336 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004337 switch (cur->type) {
4338 case XML_RELAXNG_EMPTY:
4339 case XML_RELAXNG_NOT_ALLOWED:
4340 case XML_RELAXNG_TEXT:
4341 case XML_RELAXNG_ELEMENT:
4342 case XML_RELAXNG_DATATYPE:
4343 case XML_RELAXNG_VALUE:
4344 case XML_RELAXNG_LIST:
4345 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004346 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004347 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004348 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004349 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004350 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004351 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004352 case XML_RELAXNG_CHOICE:
4353 case XML_RELAXNG_GROUP:
4354 case XML_RELAXNG_INTERLEAVE:
4355 if (last == NULL) {
4356 ret->content = last = cur;
4357 } else {
4358 if ((last->type == XML_RELAXNG_ELEMENT) &&
4359 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004360 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004361 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004362 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004363 ret->content->content = last;
4364 } else {
4365 ret->content = last;
4366 }
4367 }
4368 last->next = cur;
4369 last = cur;
4370 }
4371 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004372 case XML_RELAXNG_ATTRIBUTE:
4373 cur->next = ret->attrs;
4374 ret->attrs = cur;
4375 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004376 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004377 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004378 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004379 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004380 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004381 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004382 case XML_RELAXNG_NOOP:
4383 TODO
4384 if (ctxt->error != NULL)
4385 ctxt->error(ctxt->userData,
4386 "Internal error, noop found\n");
4387 ctxt->nbErrors++;
4388 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004389 }
4390 }
4391 child = child->next;
4392 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004393 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004394 return(ret);
4395}
4396
4397/**
4398 * xmlRelaxNGParsePatterns:
4399 * @ctxt: a Relax-NG parser context
4400 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004401 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004402 *
4403 * parse the content of a RelaxNG start node.
4404 *
4405 * Returns the definition pointer or NULL in case of error.
4406 */
4407static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004408xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4409 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004410 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004411
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004412 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004413 while (nodes != NULL) {
4414 if (IS_RELAXNG(nodes, "element")) {
4415 cur = xmlRelaxNGParseElement(ctxt, nodes);
4416 if (def == NULL) {
4417 def = last = cur;
4418 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004419 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4420 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004421 def = xmlRelaxNGNewDefine(ctxt, nodes);
4422 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004423 def->content = last;
4424 }
4425 last->next = cur;
4426 last = cur;
4427 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004428 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004429 } else {
4430 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004431 if (cur != NULL) {
4432 if (def == NULL) {
4433 def = last = cur;
4434 } else {
4435 last->next = cur;
4436 last = cur;
4437 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004438 }
4439 }
4440 nodes = nodes->next;
4441 }
4442 return(def);
4443}
4444
4445/**
4446 * xmlRelaxNGParseStart:
4447 * @ctxt: a Relax-NG parser context
4448 * @nodes: start children nodes
4449 *
4450 * parse the content of a RelaxNG start node.
4451 *
4452 * Returns 0 in case of success, -1 in case of error
4453 */
4454static int
4455xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4456 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004457 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004458
Daniel Veillardd2298792003-02-14 16:54:11 +00004459 if (nodes == NULL) {
4460 if (ctxt->error != NULL)
4461 ctxt->error(ctxt->userData,
4462 "start has no children\n");
4463 ctxt->nbErrors++;
4464 return(-1);
4465 }
4466 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004467 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004468 if (def == NULL)
4469 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004470 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004471 if (nodes->children != NULL) {
4472 if (ctxt->error != NULL)
4473 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004474 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004475 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004476 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004477 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004478 if (def == NULL)
4479 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004481 if (nodes->children != NULL) {
4482 if (ctxt->error != NULL)
4483 ctxt->error(ctxt->userData,
4484 "element notAllowed is not empty\n");
4485 ctxt->nbErrors++;
4486 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004487 } else {
4488 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004489 }
4490 if (ctxt->grammar->start != NULL) {
4491 last = ctxt->grammar->start;
4492 while (last->next != NULL)
4493 last = last->next;
4494 last->next = def;
4495 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004496 ctxt->grammar->start = def;
4497 }
4498 nodes = nodes->next;
4499 if (nodes != NULL) {
4500 if (ctxt->error != NULL)
4501 ctxt->error(ctxt->userData,
4502 "start more than one children\n");
4503 ctxt->nbErrors++;
4504 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004505 }
4506 return(ret);
4507}
4508
4509/**
4510 * xmlRelaxNGParseGrammarContent:
4511 * @ctxt: a Relax-NG parser context
4512 * @nodes: grammar children nodes
4513 *
4514 * parse the content of a RelaxNG grammar node.
4515 *
4516 * Returns 0 in case of success, -1 in case of error
4517 */
4518static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004519xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004520{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004521 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004522
4523 if (nodes == NULL) {
4524 if (ctxt->error != NULL)
4525 ctxt->error(ctxt->userData,
4526 "grammar has no children\n");
4527 ctxt->nbErrors++;
4528 return(-1);
4529 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004530 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004531 if (IS_RELAXNG(nodes, "start")) {
4532 if (nodes->children == NULL) {
4533 if (ctxt->error != NULL)
4534 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004535 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004536 ctxt->nbErrors++;
4537 } else {
4538 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4539 if (tmp != 0)
4540 ret = -1;
4541 }
4542 } else if (IS_RELAXNG(nodes, "define")) {
4543 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4544 if (tmp != 0)
4545 ret = -1;
4546 } else if (IS_RELAXNG(nodes, "include")) {
4547 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4548 if (tmp != 0)
4549 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004550 } else {
4551 if (ctxt->error != NULL)
4552 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004553 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004554 ctxt->nbErrors++;
4555 ret = -1;
4556 }
4557 nodes = nodes->next;
4558 }
4559 return (ret);
4560}
4561
4562/**
4563 * xmlRelaxNGCheckReference:
4564 * @ref: the ref
4565 * @ctxt: a Relax-NG parser context
4566 * @name: the name associated to the defines
4567 *
4568 * Applies the 4.17. combine attribute rule for all the define
4569 * element of a given grammar using the same name.
4570 */
4571static void
4572xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4573 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4574 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004575 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004576
4577 grammar = ctxt->grammar;
4578 if (grammar == NULL) {
4579 if (ctxt->error != NULL)
4580 ctxt->error(ctxt->userData,
4581 "Internal error: no grammar in CheckReference %s\n",
4582 name);
4583 ctxt->nbErrors++;
4584 return;
4585 }
4586 if (ref->content != NULL) {
4587 if (ctxt->error != NULL)
4588 ctxt->error(ctxt->userData,
4589 "Internal error: reference has content in CheckReference %s\n",
4590 name);
4591 ctxt->nbErrors++;
4592 return;
4593 }
4594 if (grammar->defs != NULL) {
4595 def = xmlHashLookup(grammar->defs, name);
4596 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004597 cur = ref;
4598 while (cur != NULL) {
4599 cur->content = def;
4600 cur = cur->nextHash;
4601 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004602 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004603 if (ctxt->error != NULL)
4604 ctxt->error(ctxt->userData,
4605 "Reference %s has no matching definition\n",
4606 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004607 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004608 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004609 } else {
4610 if (ctxt->error != NULL)
4611 ctxt->error(ctxt->userData,
4612 "Reference %s has no matching definition\n",
4613 name);
4614 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004615 }
4616 /*
4617 * TODO: make a closure and verify there is no loop !
4618 */
4619}
4620
4621/**
4622 * xmlRelaxNGCheckCombine:
4623 * @define: the define(s) list
4624 * @ctxt: a Relax-NG parser context
4625 * @name: the name associated to the defines
4626 *
4627 * Applies the 4.17. combine attribute rule for all the define
4628 * element of a given grammar using the same name.
4629 */
4630static void
4631xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4632 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4633 xmlChar *combine;
4634 int choiceOrInterleave = -1;
4635 int missing = 0;
4636 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4637
4638 if (define->nextHash == NULL)
4639 return;
4640 cur = define;
4641 while (cur != NULL) {
4642 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4643 if (combine != NULL) {
4644 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4645 if (choiceOrInterleave == -1)
4646 choiceOrInterleave = 1;
4647 else if (choiceOrInterleave == 0) {
4648 if (ctxt->error != NULL)
4649 ctxt->error(ctxt->userData,
4650 "Defines for %s use both 'choice' and 'interleave'\n",
4651 name);
4652 ctxt->nbErrors++;
4653 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004654 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004655 if (choiceOrInterleave == -1)
4656 choiceOrInterleave = 0;
4657 else if (choiceOrInterleave == 1) {
4658 if (ctxt->error != NULL)
4659 ctxt->error(ctxt->userData,
4660 "Defines for %s use both 'choice' and 'interleave'\n",
4661 name);
4662 ctxt->nbErrors++;
4663 }
4664 } else {
4665 if (ctxt->error != NULL)
4666 ctxt->error(ctxt->userData,
4667 "Defines for %s use unknown combine value '%s''\n",
4668 name, combine);
4669 ctxt->nbErrors++;
4670 }
4671 xmlFree(combine);
4672 } else {
4673 if (missing == 0)
4674 missing = 1;
4675 else {
4676 if (ctxt->error != NULL)
4677 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004678 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004679 name);
4680 ctxt->nbErrors++;
4681 }
4682 }
4683
4684 cur = cur->nextHash;
4685 }
4686#ifdef DEBUG
4687 xmlGenericError(xmlGenericErrorContext,
4688 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4689 name, choiceOrInterleave);
4690#endif
4691 if (choiceOrInterleave == -1)
4692 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004693 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004694 if (cur == NULL)
4695 return;
4696 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004697 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004698 else
4699 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004700 tmp = define;
4701 last = NULL;
4702 while (tmp != NULL) {
4703 if (tmp->content != NULL) {
4704 if (tmp->content->next != NULL) {
4705 /*
4706 * we need first to create a wrapper.
4707 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00004708 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 if (tmp2 == NULL)
4710 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004711 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004712 tmp2->content = tmp->content;
4713 } else {
4714 tmp2 = tmp->content;
4715 }
4716 if (last == NULL) {
4717 cur->content = tmp2;
4718 } else {
4719 last->next = tmp2;
4720 }
4721 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 }
Daniel Veillard952379b2003-03-17 15:37:12 +00004723 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004724 tmp = tmp->nextHash;
4725 }
4726 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004727 if (choiceOrInterleave == 0) {
4728 if (ctxt->interleaves == NULL)
4729 ctxt->interleaves = xmlHashCreate(10);
4730 if (ctxt->interleaves == NULL) {
4731 if (ctxt->error != NULL)
4732 ctxt->error(ctxt->userData,
4733 "Failed to create interleaves hash table\n");
4734 ctxt->nbErrors++;
4735 } else {
4736 char tmpname[32];
4737
4738 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4739 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4740 if (ctxt->error != NULL)
4741 ctxt->error(ctxt->userData,
4742 "Failed to add %s to hash table\n", tmpname);
4743 ctxt->nbErrors++;
4744 }
4745 }
4746 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004747}
4748
4749/**
4750 * xmlRelaxNGCombineStart:
4751 * @ctxt: a Relax-NG parser context
4752 * @grammar: the grammar
4753 *
4754 * Applies the 4.17. combine rule for all the start
4755 * element of a given grammar.
4756 */
4757static void
4758xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
4759 xmlRelaxNGGrammarPtr grammar) {
4760 xmlRelaxNGDefinePtr starts;
4761 xmlChar *combine;
4762 int choiceOrInterleave = -1;
4763 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004764 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004765
Daniel Veillard2df2de22003-02-17 23:34:33 +00004766 starts = grammar->start;
4767 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00004768 return;
4769 cur = starts;
4770 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00004771 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
4772 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
4773 combine = NULL;
4774 if (ctxt->error != NULL)
4775 ctxt->error(ctxt->userData,
4776 "Internal error: start element not found\n");
4777 ctxt->nbErrors++;
4778 } else {
4779 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
4780 }
4781
Daniel Veillard6eadf632003-01-23 18:29:16 +00004782 if (combine != NULL) {
4783 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4784 if (choiceOrInterleave == -1)
4785 choiceOrInterleave = 1;
4786 else if (choiceOrInterleave == 0) {
4787 if (ctxt->error != NULL)
4788 ctxt->error(ctxt->userData,
4789 "<start> use both 'choice' and 'interleave'\n");
4790 ctxt->nbErrors++;
4791 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00004792 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004793 if (choiceOrInterleave == -1)
4794 choiceOrInterleave = 0;
4795 else if (choiceOrInterleave == 1) {
4796 if (ctxt->error != NULL)
4797 ctxt->error(ctxt->userData,
4798 "<start> use both 'choice' and 'interleave'\n");
4799 ctxt->nbErrors++;
4800 }
4801 } else {
4802 if (ctxt->error != NULL)
4803 ctxt->error(ctxt->userData,
4804 "<start> uses unknown combine value '%s''\n", combine);
4805 ctxt->nbErrors++;
4806 }
4807 xmlFree(combine);
4808 } else {
4809 if (missing == 0)
4810 missing = 1;
4811 else {
4812 if (ctxt->error != NULL)
4813 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004814 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00004815 ctxt->nbErrors++;
4816 }
4817 }
4818
Daniel Veillard2df2de22003-02-17 23:34:33 +00004819 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004820 }
4821#ifdef DEBUG
4822 xmlGenericError(xmlGenericErrorContext,
4823 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
4824 choiceOrInterleave);
4825#endif
4826 if (choiceOrInterleave == -1)
4827 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004828 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004829 if (cur == NULL)
4830 return;
4831 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004832 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004833 else
4834 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004835 cur->content = grammar->start;
4836 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004837 if (choiceOrInterleave == 0) {
4838 if (ctxt->interleaves == NULL)
4839 ctxt->interleaves = xmlHashCreate(10);
4840 if (ctxt->interleaves == NULL) {
4841 if (ctxt->error != NULL)
4842 ctxt->error(ctxt->userData,
4843 "Failed to create interleaves hash table\n");
4844 ctxt->nbErrors++;
4845 } else {
4846 char tmpname[32];
4847
4848 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
4849 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
4850 if (ctxt->error != NULL)
4851 ctxt->error(ctxt->userData,
4852 "Failed to add %s to hash table\n", tmpname);
4853 ctxt->nbErrors++;
4854 }
4855 }
4856 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004857}
4858
4859/**
Daniel Veillardd4310742003-02-18 21:12:46 +00004860 * xmlRelaxNGCheckCycles:
4861 * @ctxt: a Relax-NG parser context
4862 * @nodes: grammar children nodes
4863 * @depth: the counter
4864 *
4865 * Check for cycles.
4866 *
4867 * Returns 0 if check passed, and -1 in case of error
4868 */
4869static int
4870xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
4871 xmlRelaxNGDefinePtr cur, int depth) {
4872 int ret = 0;
4873
4874 while ((ret == 0) && (cur != NULL)) {
4875 if ((cur->type == XML_RELAXNG_REF) ||
4876 (cur->type == XML_RELAXNG_PARENTREF)) {
4877 if (cur->depth == -1) {
4878 cur->depth = depth;
4879 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4880 cur->depth = -2;
4881 } else if (depth == cur->depth) {
4882 if (ctxt->error != NULL)
4883 ctxt->error(ctxt->userData,
4884 "Detected a cycle in %s references\n", cur->name);
4885 ctxt->nbErrors++;
4886 return(-1);
4887 }
4888 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4889 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4890 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004891 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00004892 }
4893 cur = cur->next;
4894 }
4895 return(ret);
4896}
4897
4898/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00004899 * xmlRelaxNGTryUnlink:
4900 * @ctxt: a Relax-NG parser context
4901 * @cur: the definition to unlink
4902 * @parent: the parent definition
4903 * @prev: the previous sibling definition
4904 *
4905 * Try to unlink a definition. If not possble make it a NOOP
4906 *
4907 * Returns the new prev definition
4908 */
4909static xmlRelaxNGDefinePtr
4910xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4911 xmlRelaxNGDefinePtr cur,
4912 xmlRelaxNGDefinePtr parent,
4913 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004914 if (prev != NULL) {
4915 prev->next = cur->next;
4916 } else {
4917 if (parent != NULL) {
4918 if (parent->content == cur)
4919 parent->content = cur->next;
4920 else if (parent->attrs == cur)
4921 parent->attrs = cur->next;
4922 else if (parent->nameClass == cur)
4923 parent->nameClass = cur->next;
4924 } else {
4925 cur->type = XML_RELAXNG_NOOP;
4926 prev = cur;
4927 }
4928 }
4929 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004930}
4931
4932/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00004933 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004934 * @ctxt: a Relax-NG parser context
4935 * @nodes: grammar children nodes
4936 *
4937 * Check for simplification of empty and notAllowed
4938 */
4939static void
4940xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4941 xmlRelaxNGDefinePtr cur,
4942 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004943 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004944
Daniel Veillardfd573f12003-03-16 17:52:32 +00004945 while (cur != NULL) {
4946 if ((cur->type == XML_RELAXNG_REF) ||
4947 (cur->type == XML_RELAXNG_PARENTREF)) {
4948 if (cur->depth != -3) {
4949 cur->depth = -3;
4950 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004951 }
4952 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004953 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004954 if ((parent != NULL) &&
4955 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4956 (parent->type == XML_RELAXNG_LIST) ||
4957 (parent->type == XML_RELAXNG_GROUP) ||
4958 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00004959 (parent->type == XML_RELAXNG_ONEORMORE) ||
4960 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004961 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004962 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004963 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004964 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00004965 (parent->type == XML_RELAXNG_CHOICE)) {
4966 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4967 } else
4968 prev = cur;
4969 } else if (cur->type == XML_RELAXNG_EMPTY){
4970 cur->parent = parent;
4971 if ((parent != NULL) &&
4972 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4973 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004974 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004975 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00004976 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004977 if ((parent != NULL) &&
4978 ((parent->type == XML_RELAXNG_GROUP) ||
4979 (parent->type == XML_RELAXNG_INTERLEAVE))) {
4980 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4981 } else
4982 prev = cur;
4983 } else {
4984 cur->parent = parent;
4985 if (cur->content != NULL)
4986 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4987 if (cur->attrs != NULL)
4988 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
4989 if (cur->nameClass != NULL)
4990 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
4991 /*
4992 * This may result in a simplification
4993 */
4994 if ((cur->type == XML_RELAXNG_GROUP) ||
4995 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4996 if (cur->content == NULL)
4997 cur->type = XML_RELAXNG_EMPTY;
4998 else if (cur->content->next == NULL) {
4999 if ((parent == NULL) && (prev == NULL)) {
5000 cur->type = XML_RELAXNG_NOOP;
5001 } else if (prev == NULL) {
5002 parent->content = cur->content;
5003 cur->content->next = cur->next;
5004 cur = cur->content;
5005 } else {
5006 cur->content->next = cur->next;
5007 prev->next = cur->content;
5008 cur = cur->content;
5009 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005010 }
5011 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005012 /*
5013 * the current node may have been transformed back
5014 */
5015 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5016 (cur->content != NULL) &&
5017 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5018 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5019 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5020 if ((parent != NULL) &&
5021 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5022 (parent->type == XML_RELAXNG_LIST) ||
5023 (parent->type == XML_RELAXNG_GROUP) ||
5024 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5025 (parent->type == XML_RELAXNG_ONEORMORE) ||
5026 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5027 parent->type = XML_RELAXNG_NOT_ALLOWED;
5028 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005029 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005030 if ((parent != NULL) &&
5031 (parent->type == XML_RELAXNG_CHOICE)) {
5032 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5033 } else
5034 prev = cur;
5035 } else if (cur->type == XML_RELAXNG_EMPTY){
5036 if ((parent != NULL) &&
5037 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5038 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5039 parent->type = XML_RELAXNG_EMPTY;
5040 break;
5041 }
5042 if ((parent != NULL) &&
5043 ((parent->type == XML_RELAXNG_GROUP) ||
5044 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5045 (parent->type == XML_RELAXNG_CHOICE))) {
5046 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5047 } else
5048 prev = cur;
5049 } else {
5050 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005051 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005052 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005053 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005054 }
5055}
5056
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005057/**
5058 * xmlRelaxNGGroupContentType:
5059 * @ct1: the first content type
5060 * @ct2: the second content type
5061 *
5062 * Try to group 2 content types
5063 *
5064 * Returns the content type
5065 */
5066static xmlRelaxNGContentType
5067xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5068 xmlRelaxNGContentType ct2) {
5069 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5070 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5071 return(XML_RELAXNG_CONTENT_ERROR);
5072 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5073 return(ct2);
5074 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5075 return(ct1);
5076 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5077 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5078 return(XML_RELAXNG_CONTENT_COMPLEX);
5079 return(XML_RELAXNG_CONTENT_ERROR);
5080}
5081
5082/**
5083 * xmlRelaxNGMaxContentType:
5084 * @ct1: the first content type
5085 * @ct2: the second content type
5086 *
5087 * Compute the max content-type
5088 *
5089 * Returns the content type
5090 */
5091static xmlRelaxNGContentType
5092xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5093 xmlRelaxNGContentType ct2) {
5094 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5095 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5096 return(XML_RELAXNG_CONTENT_ERROR);
5097 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5098 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5099 return(XML_RELAXNG_CONTENT_SIMPLE);
5100 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5101 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5102 return(XML_RELAXNG_CONTENT_COMPLEX);
5103 return(XML_RELAXNG_CONTENT_EMPTY);
5104}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005105
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005106/**
5107 * xmlRelaxNGCheckRules:
5108 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005109 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005110 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005111 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005112 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005113 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005114 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005115 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005116 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005117static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005118xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5119 xmlRelaxNGDefinePtr cur, int flags,
5120 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005121 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005122 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005123
Daniel Veillardfd573f12003-03-16 17:52:32 +00005124 while (cur != NULL) {
5125 ret = XML_RELAXNG_CONTENT_EMPTY;
5126 if ((cur->type == XML_RELAXNG_REF) ||
5127 (cur->type == XML_RELAXNG_PARENTREF)) {
5128 if (flags & XML_RELAXNG_IN_LIST) {
5129 if (ctxt->error != NULL)
5130 ctxt->error(ctxt->userData,
5131 "Found forbidden pattern list//ref\n");
5132 ctxt->nbErrors++;
5133 }
5134 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5135 if (ctxt->error != NULL)
5136 ctxt->error(ctxt->userData,
5137 "Found forbidden pattern data/except//ref\n");
5138 ctxt->nbErrors++;
5139 }
5140 if (cur->depth > -4) {
5141 cur->depth = -4;
5142 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5143 flags, cur->type);
5144 cur->depth = ret - 15 ;
5145 } else if (cur->depth == -4) {
5146 ret = XML_RELAXNG_CONTENT_COMPLEX;
5147 } else {
5148 ret = (xmlRelaxNGContentType) cur->depth + 15;
5149 }
5150 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5151 /*
5152 * The 7.3 Attribute derivation rule for groups is plugged there
5153 */
5154 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5155 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5156 if (ctxt->error != NULL)
5157 ctxt->error(ctxt->userData,
5158 "Found forbidden pattern data/except//element(ref)\n");
5159 ctxt->nbErrors++;
5160 }
5161 if (flags & XML_RELAXNG_IN_LIST) {
5162 if (ctxt->error != NULL)
5163 ctxt->error(ctxt->userData,
5164 "Found forbidden pattern list//element(ref)\n");
5165 ctxt->nbErrors++;
5166 }
5167 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5168 if (ctxt->error != NULL)
5169 ctxt->error(ctxt->userData,
5170 "Found forbidden pattern attribute//element(ref)\n");
5171 ctxt->nbErrors++;
5172 }
5173 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5174 if (ctxt->error != NULL)
5175 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005176 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005177 ctxt->nbErrors++;
5178 }
5179 /*
5180 * reset since in the simple form elements are only child
5181 * of grammar/define
5182 */
5183 nflags = 0;
5184 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5185 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5186 if (ctxt->error != NULL)
5187 ctxt->error(ctxt->userData,
5188 "Element %s attributes have a content type error\n",
5189 cur->name);
5190 ctxt->nbErrors++;
5191 }
5192 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5193 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5194 if (ctxt->error != NULL)
5195 ctxt->error(ctxt->userData,
5196 "Element %s has a content type error\n",
5197 cur->name);
5198 ctxt->nbErrors++;
5199 } else {
5200 ret = XML_RELAXNG_CONTENT_COMPLEX;
5201 }
5202 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5203 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5204 if (ctxt->error != NULL)
5205 ctxt->error(ctxt->userData,
5206 "Found forbidden pattern attribute//attribute\n");
5207 ctxt->nbErrors++;
5208 }
5209 if (flags & XML_RELAXNG_IN_LIST) {
5210 if (ctxt->error != NULL)
5211 ctxt->error(ctxt->userData,
5212 "Found forbidden pattern list//attribute\n");
5213 ctxt->nbErrors++;
5214 }
5215 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5216 if (ctxt->error != NULL)
5217 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005218 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005219 ctxt->nbErrors++;
5220 }
5221 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5222 if (ctxt->error != NULL)
5223 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005224 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005225 ctxt->nbErrors++;
5226 }
5227 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5228 if (ctxt->error != NULL)
5229 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005230 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005231 ctxt->nbErrors++;
5232 }
5233 if (flags & XML_RELAXNG_IN_START) {
5234 if (ctxt->error != NULL)
5235 ctxt->error(ctxt->userData,
5236 "Found forbidden pattern start//attribute\n");
5237 ctxt->nbErrors++;
5238 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005239 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5240 if (cur->ns == NULL) {
5241 if (ctxt->error != NULL)
5242 ctxt->error(ctxt->userData,
5243 "Found anyName attribute without oneOrMore ancestor\n");
5244 ctxt->nbErrors++;
5245 } else {
5246 if (ctxt->error != NULL)
5247 ctxt->error(ctxt->userData,
5248 "Found nsName attribute without oneOrMore ancestor\n");
5249 ctxt->nbErrors++;
5250 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005251 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005252 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5253 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5254 ret = XML_RELAXNG_CONTENT_EMPTY;
5255 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5256 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5257 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5258 if (ctxt->error != NULL)
5259 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005260 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005261 ctxt->nbErrors++;
5262 }
5263 if (flags & XML_RELAXNG_IN_START) {
5264 if (ctxt->error != NULL)
5265 ctxt->error(ctxt->userData,
5266 "Found forbidden pattern start//oneOrMore\n");
5267 ctxt->nbErrors++;
5268 }
5269 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5270 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5271 ret = xmlRelaxNGGroupContentType(ret, ret);
5272 } else if (cur->type == XML_RELAXNG_LIST) {
5273 if (flags & XML_RELAXNG_IN_LIST) {
5274 if (ctxt->error != NULL)
5275 ctxt->error(ctxt->userData,
5276 "Found forbidden pattern list//list\n");
5277 ctxt->nbErrors++;
5278 }
5279 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5280 if (ctxt->error != NULL)
5281 ctxt->error(ctxt->userData,
5282 "Found forbidden pattern data/except//list\n");
5283 ctxt->nbErrors++;
5284 }
5285 if (flags & XML_RELAXNG_IN_START) {
5286 if (ctxt->error != NULL)
5287 ctxt->error(ctxt->userData,
5288 "Found forbidden pattern start//list\n");
5289 ctxt->nbErrors++;
5290 }
5291 nflags = flags | XML_RELAXNG_IN_LIST;
5292 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5293 } else if (cur->type == XML_RELAXNG_GROUP) {
5294 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5295 if (ctxt->error != NULL)
5296 ctxt->error(ctxt->userData,
5297 "Found forbidden pattern data/except//group\n");
5298 ctxt->nbErrors++;
5299 }
5300 if (flags & XML_RELAXNG_IN_START) {
5301 if (ctxt->error != NULL)
5302 ctxt->error(ctxt->userData,
5303 "Found forbidden pattern start//group\n");
5304 ctxt->nbErrors++;
5305 }
5306 if (flags & XML_RELAXNG_IN_ONEORMORE)
5307 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5308 else
5309 nflags = flags;
5310 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5311 /*
5312 * The 7.3 Attribute derivation rule for groups is plugged there
5313 */
5314 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5315 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5316 if (flags & XML_RELAXNG_IN_LIST) {
5317 if (ctxt->error != NULL)
5318 ctxt->error(ctxt->userData,
5319 "Found forbidden pattern list//interleave\n");
5320 ctxt->nbErrors++;
5321 }
5322 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5323 if (ctxt->error != NULL)
5324 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005325 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005326 ctxt->nbErrors++;
5327 }
5328 if (flags & XML_RELAXNG_IN_START) {
5329 if (ctxt->error != NULL)
5330 ctxt->error(ctxt->userData,
5331 "Found forbidden pattern start//interleave\n");
5332 ctxt->nbErrors++;
5333 }
5334 if (flags & XML_RELAXNG_IN_ONEORMORE)
5335 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5336 else
5337 nflags = flags;
5338 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5339 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5340 if ((cur->parent != NULL) &&
5341 (cur->parent->type == XML_RELAXNG_DATATYPE))
5342 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5343 else
5344 nflags = flags;
5345 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5346 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5347 if (flags & XML_RELAXNG_IN_START) {
5348 if (ctxt->error != NULL)
5349 ctxt->error(ctxt->userData,
5350 "Found forbidden pattern start//data\n");
5351 ctxt->nbErrors++;
5352 }
5353 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5354 ret = XML_RELAXNG_CONTENT_SIMPLE;
5355 } else if (cur->type == XML_RELAXNG_VALUE) {
5356 if (flags & XML_RELAXNG_IN_START) {
5357 if (ctxt->error != NULL)
5358 ctxt->error(ctxt->userData,
5359 "Found forbidden pattern start//value\n");
5360 ctxt->nbErrors++;
5361 }
5362 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5363 ret = XML_RELAXNG_CONTENT_SIMPLE;
5364 } else if (cur->type == XML_RELAXNG_TEXT) {
5365 if (flags & XML_RELAXNG_IN_LIST) {
5366 if (ctxt->error != NULL)
5367 ctxt->error(ctxt->userData,
5368 "Found forbidden pattern list//text\n");
5369 ctxt->nbErrors++;
5370 }
5371 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5372 if (ctxt->error != NULL)
5373 ctxt->error(ctxt->userData,
5374 "Found forbidden pattern data/except//text\n");
5375 ctxt->nbErrors++;
5376 }
5377 if (flags & XML_RELAXNG_IN_START) {
5378 if (ctxt->error != NULL)
5379 ctxt->error(ctxt->userData,
5380 "Found forbidden pattern start//text\n");
5381 ctxt->nbErrors++;
5382 }
5383 ret = XML_RELAXNG_CONTENT_COMPLEX;
5384 } else if (cur->type == XML_RELAXNG_EMPTY) {
5385 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5386 if (ctxt->error != NULL)
5387 ctxt->error(ctxt->userData,
5388 "Found forbidden pattern data/except//empty\n");
5389 ctxt->nbErrors++;
5390 }
5391 if (flags & XML_RELAXNG_IN_START) {
5392 if (ctxt->error != NULL)
5393 ctxt->error(ctxt->userData,
5394 "Found forbidden pattern start//empty\n");
5395 ctxt->nbErrors++;
5396 }
5397 ret = XML_RELAXNG_CONTENT_EMPTY;
5398 } else if (cur->type == XML_RELAXNG_CHOICE) {
5399 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5400 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5401 } else {
5402 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5403 }
5404 cur = cur->next;
5405 if (ptype == XML_RELAXNG_GROUP) {
5406 val = xmlRelaxNGGroupContentType(val, ret);
5407 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5408 tmp = xmlRelaxNGGroupContentType(val, ret);
5409 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5410 tmp = xmlRelaxNGMaxContentType(val, ret);
5411 } else if (ptype == XML_RELAXNG_CHOICE) {
5412 val = xmlRelaxNGMaxContentType(val, ret);
5413 } else if (ptype == XML_RELAXNG_LIST) {
5414 val = XML_RELAXNG_CONTENT_SIMPLE;
5415 } else if (ptype == XML_RELAXNG_EXCEPT) {
5416 if (ret == XML_RELAXNG_CONTENT_ERROR)
5417 val = XML_RELAXNG_CONTENT_ERROR;
5418 else
5419 val = XML_RELAXNG_CONTENT_SIMPLE;
5420 } else {
5421 val = xmlRelaxNGGroupContentType(val, ret);
5422 }
5423
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005424 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005425 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005426}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005427
5428/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005429 * xmlRelaxNGParseGrammar:
5430 * @ctxt: a Relax-NG parser context
5431 * @nodes: grammar children nodes
5432 *
5433 * parse a Relax-NG <grammar> node
5434 *
5435 * Returns the internal xmlRelaxNGGrammarPtr built or
5436 * NULL in case of error
5437 */
5438static xmlRelaxNGGrammarPtr
5439xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5440 xmlRelaxNGGrammarPtr ret, tmp, old;
5441
Daniel Veillardc482e262003-02-26 14:48:48 +00005442#ifdef DEBUG_GRAMMAR
5443 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5444#endif
5445
Daniel Veillard6eadf632003-01-23 18:29:16 +00005446 ret = xmlRelaxNGNewGrammar(ctxt);
5447 if (ret == NULL)
5448 return(NULL);
5449
5450 /*
5451 * Link the new grammar in the tree
5452 */
5453 ret->parent = ctxt->grammar;
5454 if (ctxt->grammar != NULL) {
5455 tmp = ctxt->grammar->children;
5456 if (tmp == NULL) {
5457 ctxt->grammar->children = ret;
5458 } else {
5459 while (tmp->next != NULL)
5460 tmp = tmp->next;
5461 tmp->next = ret;
5462 }
5463 }
5464
5465 old = ctxt->grammar;
5466 ctxt->grammar = ret;
5467 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5468 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005469 if (ctxt->grammar == NULL) {
5470 if (ctxt->error != NULL)
5471 ctxt->error(ctxt->userData,
5472 "Failed to parse <grammar> content\n");
5473 ctxt->nbErrors++;
5474 } else if (ctxt->grammar->start == NULL) {
5475 if (ctxt->error != NULL)
5476 ctxt->error(ctxt->userData,
5477 "Element <grammar> has no <start>\n");
5478 ctxt->nbErrors++;
5479 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005480
5481 /*
5482 * Apply 4.17 mergingd rules to defines and starts
5483 */
5484 xmlRelaxNGCombineStart(ctxt, ret);
5485 if (ret->defs != NULL) {
5486 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5487 ctxt);
5488 }
5489
5490 /*
5491 * link together defines and refs in this grammar
5492 */
5493 if (ret->refs != NULL) {
5494 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5495 ctxt);
5496 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005497
Daniel Veillard6eadf632003-01-23 18:29:16 +00005498 ctxt->grammar = old;
5499 return(ret);
5500}
5501
5502/**
5503 * xmlRelaxNGParseDocument:
5504 * @ctxt: a Relax-NG parser context
5505 * @node: the root node of the RelaxNG schema
5506 *
5507 * parse a Relax-NG definition resource and build an internal
5508 * xmlRelaxNG struture which can be used to validate instances.
5509 *
5510 * Returns the internal XML RelaxNG structure built or
5511 * NULL in case of error
5512 */
5513static xmlRelaxNGPtr
5514xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5515 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005516 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005517 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005518
5519 if ((ctxt == NULL) || (node == NULL))
5520 return (NULL);
5521
5522 schema = xmlRelaxNGNewRelaxNG(ctxt);
5523 if (schema == NULL)
5524 return(NULL);
5525
Daniel Veillard276be4a2003-01-24 01:03:34 +00005526 olddefine = ctxt->define;
5527 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005528 if (IS_RELAXNG(node, "grammar")) {
5529 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5530 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005531 xmlRelaxNGGrammarPtr tmp, ret;
5532
5533 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 if (schema->topgrammar == NULL) {
5535 return(schema);
5536 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005537 /*
5538 * Link the new grammar in the tree
5539 */
5540 ret->parent = ctxt->grammar;
5541 if (ctxt->grammar != NULL) {
5542 tmp = ctxt->grammar->children;
5543 if (tmp == NULL) {
5544 ctxt->grammar->children = ret;
5545 } else {
5546 while (tmp->next != NULL)
5547 tmp = tmp->next;
5548 tmp->next = ret;
5549 }
5550 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005551 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005552 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005553 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005554 if (old != NULL)
5555 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005556 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005557 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005558 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005559 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005560 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005561 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5562 while ((schema->topgrammar->start != NULL) &&
5563 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5564 (schema->topgrammar->start->next != NULL))
5565 schema->topgrammar->start = schema->topgrammar->start->content;
5566 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5567 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005568 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005569 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005570
5571#ifdef DEBUG
5572 if (schema == NULL)
5573 xmlGenericError(xmlGenericErrorContext,
5574 "xmlRelaxNGParseDocument() failed\n");
5575#endif
5576
5577 return (schema);
5578}
5579
5580/************************************************************************
5581 * *
5582 * Reading RelaxNGs *
5583 * *
5584 ************************************************************************/
5585
5586/**
5587 * xmlRelaxNGNewParserCtxt:
5588 * @URL: the location of the schema
5589 *
5590 * Create an XML RelaxNGs parse context for that file/resource expected
5591 * to contain an XML RelaxNGs file.
5592 *
5593 * Returns the parser context or NULL in case of error
5594 */
5595xmlRelaxNGParserCtxtPtr
5596xmlRelaxNGNewParserCtxt(const char *URL) {
5597 xmlRelaxNGParserCtxtPtr ret;
5598
5599 if (URL == NULL)
5600 return(NULL);
5601
5602 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5603 if (ret == NULL) {
5604 xmlGenericError(xmlGenericErrorContext,
5605 "Failed to allocate new schama parser context for %s\n", URL);
5606 return (NULL);
5607 }
5608 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5609 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005610 ret->error = xmlGenericError;
5611 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005612 return (ret);
5613}
5614
5615/**
5616 * xmlRelaxNGNewMemParserCtxt:
5617 * @buffer: a pointer to a char array containing the schemas
5618 * @size: the size of the array
5619 *
5620 * Create an XML RelaxNGs parse context for that memory buffer expected
5621 * to contain an XML RelaxNGs file.
5622 *
5623 * Returns the parser context or NULL in case of error
5624 */
5625xmlRelaxNGParserCtxtPtr
5626xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5627 xmlRelaxNGParserCtxtPtr ret;
5628
5629 if ((buffer == NULL) || (size <= 0))
5630 return(NULL);
5631
5632 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5633 if (ret == NULL) {
5634 xmlGenericError(xmlGenericErrorContext,
5635 "Failed to allocate new schama parser context\n");
5636 return (NULL);
5637 }
5638 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5639 ret->buffer = buffer;
5640 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005641 ret->error = xmlGenericError;
5642 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005643 return (ret);
5644}
5645
5646/**
5647 * xmlRelaxNGFreeParserCtxt:
5648 * @ctxt: the schema parser context
5649 *
5650 * Free the resources associated to the schema parser context
5651 */
5652void
5653xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5654 if (ctxt == NULL)
5655 return;
5656 if (ctxt->URL != NULL)
5657 xmlFree(ctxt->URL);
5658 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005659 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005660 if (ctxt->interleaves != NULL)
5661 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005662 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005663 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005664 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005665 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005666 if (ctxt->docTab != NULL)
5667 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005668 if (ctxt->incTab != NULL)
5669 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005670 if (ctxt->defTab != NULL) {
5671 int i;
5672
5673 for (i = 0;i < ctxt->defNr;i++)
5674 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5675 xmlFree(ctxt->defTab);
5676 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005677 xmlFree(ctxt);
5678}
5679
Daniel Veillard6eadf632003-01-23 18:29:16 +00005680/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005681 * xmlRelaxNGNormExtSpace:
5682 * @value: a value
5683 *
5684 * Removes the leading and ending spaces of the value
5685 * The string is modified "in situ"
5686 */
5687static void
5688xmlRelaxNGNormExtSpace(xmlChar *value) {
5689 xmlChar *start = value;
5690 xmlChar *cur = value;
5691 if (value == NULL)
5692 return;
5693
5694 while (IS_BLANK(*cur)) cur++;
5695 if (cur == start) {
5696 do {
5697 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5698 if (*cur == 0)
5699 return;
5700 start = cur;
5701 while (IS_BLANK(*cur)) cur++;
5702 if (*cur == 0) {
5703 *start = 0;
5704 return;
5705 }
5706 } while (1);
5707 } else {
5708 do {
5709 while ((*cur != 0) && (!IS_BLANK(*cur)))
5710 *start++ = *cur++;
5711 if (*cur == 0) {
5712 *start = 0;
5713 return;
5714 }
5715 /* don't try to normalize the inner spaces */
5716 while (IS_BLANK(*cur)) cur++;
5717 *start++ = *cur++;
5718 if (*cur == 0) {
5719 *start = 0;
5720 return;
5721 }
5722 } while (1);
5723 }
5724}
5725
5726/**
5727 * xmlRelaxNGCheckAttributes:
5728 * @ctxt: a Relax-NG parser context
5729 * @node: a Relax-NG node
5730 *
5731 * Check all the attributes on the given node
5732 */
5733static void
5734xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5735 xmlAttrPtr cur, next;
5736
5737 cur = node->properties;
5738 while (cur != NULL) {
5739 next = cur->next;
5740 if ((cur->ns == NULL) ||
5741 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
5742 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5743 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
5744 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
5745 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
5746 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00005747 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00005748 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5749 if (ctxt->error != NULL)
5750 ctxt->error(ctxt->userData,
5751 "Attribute %s is not allowed on %s\n",
5752 cur->name, node->name);
5753 ctxt->nbErrors++;
5754 }
5755 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
5756 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
5757 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
5758 if (ctxt->error != NULL)
5759 ctxt->error(ctxt->userData,
5760 "Attribute %s is not allowed on %s\n",
5761 cur->name, node->name);
5762 ctxt->nbErrors++;
5763 }
5764 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
5765 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
5766 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
5767 if (ctxt->error != NULL)
5768 ctxt->error(ctxt->userData,
5769 "Attribute %s is not allowed on %s\n",
5770 cur->name, node->name);
5771 ctxt->nbErrors++;
5772 }
5773 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
5774 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
5775 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
5776 if (ctxt->error != NULL)
5777 ctxt->error(ctxt->userData,
5778 "Attribute %s is not allowed on %s\n",
5779 cur->name, node->name);
5780 ctxt->nbErrors++;
5781 }
5782 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
5783 xmlChar *val;
5784 xmlURIPtr uri;
5785
5786 val = xmlNodeListGetString(node->doc, cur->children, 1);
5787 if (val != NULL) {
5788 if (val[0] != 0) {
5789 uri = xmlParseURI((const char *) val);
5790 if (uri == NULL) {
5791 if (ctxt->error != NULL)
5792 ctxt->error(ctxt->userData,
5793 "Attribute %s contains invalid URI %s\n",
5794 cur->name, val);
5795 ctxt->nbErrors++;
5796 } else {
5797 if (uri->scheme == NULL) {
5798 if (ctxt->error != NULL)
5799 ctxt->error(ctxt->userData,
5800 "Attribute %s URI %s is not absolute\n",
5801 cur->name, val);
5802 ctxt->nbErrors++;
5803 }
5804 if (uri->fragment != NULL) {
5805 if (ctxt->error != NULL)
5806 ctxt->error(ctxt->userData,
5807 "Attribute %s URI %s has a fragment ID\n",
5808 cur->name, val);
5809 ctxt->nbErrors++;
5810 }
5811 xmlFreeURI(uri);
5812 }
5813 }
5814 xmlFree(val);
5815 }
5816 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
5817 if (ctxt->error != NULL)
5818 ctxt->error(ctxt->userData,
5819 "Unknown attribute %s on %s\n",
5820 cur->name, node->name);
5821 ctxt->nbErrors++;
5822 }
5823 }
5824 cur = next;
5825 }
5826}
5827
5828/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00005829 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005830 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00005831 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00005832 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00005833 * Cleanup the subtree from unwanted nodes for parsing, resolve
5834 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00005835 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00005836static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00005837xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00005838 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005839
Daniel Veillard6eadf632003-01-23 18:29:16 +00005840 delete = NULL;
5841 cur = root;
5842 while (cur != NULL) {
5843 if (delete != NULL) {
5844 xmlUnlinkNode(delete);
5845 xmlFreeNode(delete);
5846 delete = NULL;
5847 }
5848 if (cur->type == XML_ELEMENT_NODE) {
5849 /*
5850 * Simplification 4.1. Annotations
5851 */
5852 if ((cur->ns == NULL) ||
5853 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00005854 if ((cur->parent != NULL) &&
5855 (cur->parent->type == XML_ELEMENT_NODE) &&
5856 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
5857 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
5858 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
5859 if (ctxt->error != NULL)
5860 ctxt->error(ctxt->userData,
5861 "element %s doesn't allow foreign elements\n",
5862 cur->parent->name);
5863 ctxt->nbErrors++;
5864 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005865 delete = cur;
5866 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005867 } else {
5868 xmlRelaxNGCleanupAttributes(ctxt, cur);
5869 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
5870 xmlChar *href, *ns, *base, *URL;
5871 xmlRelaxNGDocumentPtr docu;
5872 xmlNodePtr tmp;
5873
5874 ns = xmlGetProp(cur, BAD_CAST "ns");
5875 if (ns == NULL) {
5876 tmp = cur->parent;
5877 while ((tmp != NULL) &&
5878 (tmp->type == XML_ELEMENT_NODE)) {
5879 ns = xmlGetProp(tmp, BAD_CAST "ns");
5880 if (ns != NULL)
5881 break;
5882 tmp = tmp->parent;
5883 }
5884 }
5885 href = xmlGetProp(cur, BAD_CAST "href");
5886 if (href == NULL) {
5887 if (ctxt->error != NULL)
5888 ctxt->error(ctxt->userData,
5889 "xmlRelaxNGParse: externalRef has no href attribute\n");
5890 ctxt->nbErrors++;
5891 delete = cur;
5892 goto skip_children;
5893 }
5894 base = xmlNodeGetBase(cur->doc, cur);
5895 URL = xmlBuildURI(href, base);
5896 if (URL == NULL) {
5897 if (ctxt->error != NULL)
5898 ctxt->error(ctxt->userData,
5899 "Failed to compute URL for externalRef %s\n", href);
5900 ctxt->nbErrors++;
5901 if (href != NULL)
5902 xmlFree(href);
5903 if (base != NULL)
5904 xmlFree(base);
5905 delete = cur;
5906 goto skip_children;
5907 }
5908 if (href != NULL)
5909 xmlFree(href);
5910 if (base != NULL)
5911 xmlFree(base);
5912 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
5913 if (docu == NULL) {
5914 if (ctxt->error != NULL)
5915 ctxt->error(ctxt->userData,
5916 "Failed to load externalRef %s\n", URL);
5917 ctxt->nbErrors++;
5918 xmlFree(URL);
5919 delete = cur;
5920 goto skip_children;
5921 }
5922 if (ns != NULL)
5923 xmlFree(ns);
5924 xmlFree(URL);
5925 cur->_private = docu;
5926 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5927 xmlChar *href, *ns, *base, *URL;
5928 xmlRelaxNGIncludePtr incl;
5929 xmlNodePtr tmp;
5930
5931 href = xmlGetProp(cur, BAD_CAST "href");
5932 if (href == NULL) {
5933 if (ctxt->error != NULL)
5934 ctxt->error(ctxt->userData,
5935 "xmlRelaxNGParse: include has no href attribute\n");
5936 ctxt->nbErrors++;
5937 delete = cur;
5938 goto skip_children;
5939 }
5940 base = xmlNodeGetBase(cur->doc, cur);
5941 URL = xmlBuildURI(href, base);
5942 if (URL == NULL) {
5943 if (ctxt->error != NULL)
5944 ctxt->error(ctxt->userData,
5945 "Failed to compute URL for include %s\n", href);
5946 ctxt->nbErrors++;
5947 if (href != NULL)
5948 xmlFree(href);
5949 if (base != NULL)
5950 xmlFree(base);
5951 delete = cur;
5952 goto skip_children;
5953 }
5954 if (href != NULL)
5955 xmlFree(href);
5956 if (base != NULL)
5957 xmlFree(base);
5958 ns = xmlGetProp(cur, BAD_CAST "ns");
5959 if (ns == NULL) {
5960 tmp = cur->parent;
5961 while ((tmp != NULL) &&
5962 (tmp->type == XML_ELEMENT_NODE)) {
5963 ns = xmlGetProp(tmp, BAD_CAST "ns");
5964 if (ns != NULL)
5965 break;
5966 tmp = tmp->parent;
5967 }
5968 }
5969 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5970 if (ns != NULL)
5971 xmlFree(ns);
5972 if (incl == NULL) {
5973 if (ctxt->error != NULL)
5974 ctxt->error(ctxt->userData,
5975 "Failed to load include %s\n", URL);
5976 ctxt->nbErrors++;
5977 xmlFree(URL);
5978 delete = cur;
5979 goto skip_children;
5980 }
5981 xmlFree(URL);
5982 cur->_private = incl;
5983 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5984 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
5985 xmlChar *name, *ns;
5986 xmlNodePtr text = NULL;
5987
5988 /*
5989 * Simplification 4.8. name attribute of element
5990 * and attribute elements
5991 */
5992 name = xmlGetProp(cur, BAD_CAST "name");
5993 if (name != NULL) {
5994 if (cur->children == NULL) {
5995 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5996 name);
5997 } else {
5998 xmlNodePtr node;
5999 node = xmlNewNode(cur->ns, BAD_CAST "name");
6000 if (node != NULL) {
6001 xmlAddPrevSibling(cur->children, node);
6002 text = xmlNewText(name);
6003 xmlAddChild(node, text);
6004 text = node;
6005 }
6006 }
6007 if (text == NULL) {
6008 if (ctxt->error != NULL)
6009 ctxt->error(ctxt->userData,
6010 "Failed to create a name %s element\n", name);
6011 ctxt->nbErrors++;
6012 }
6013 xmlUnsetProp(cur, BAD_CAST "name");
6014 xmlFree(name);
6015 ns = xmlGetProp(cur, BAD_CAST "ns");
6016 if (ns != NULL) {
6017 if (text != NULL) {
6018 xmlSetProp(text, BAD_CAST "ns", ns);
6019 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6020 }
6021 xmlFree(ns);
6022 } else if (xmlStrEqual(cur->name,
6023 BAD_CAST "attribute")) {
6024 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6025 }
6026 }
6027 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6028 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6029 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6030 /*
6031 * Simplification 4.8. name attribute of element
6032 * and attribute elements
6033 */
6034 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6035 xmlNodePtr node;
6036 xmlChar *ns = NULL;
6037
6038 node = cur->parent;
6039 while ((node != NULL) &&
6040 (node->type == XML_ELEMENT_NODE)) {
6041 ns = xmlGetProp(node, BAD_CAST "ns");
6042 if (ns != NULL) {
6043 break;
6044 }
6045 node = node->parent;
6046 }
6047 if (ns == NULL) {
6048 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6049 } else {
6050 xmlSetProp(cur, BAD_CAST "ns", ns);
6051 xmlFree(ns);
6052 }
6053 }
6054 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6055 xmlChar *name, *local, *prefix;
6056
6057 /*
6058 * Simplification: 4.10. QNames
6059 */
6060 name = xmlNodeGetContent(cur);
6061 if (name != NULL) {
6062 local = xmlSplitQName2(name, &prefix);
6063 if (local != NULL) {
6064 xmlNsPtr ns;
6065
6066 ns = xmlSearchNs(cur->doc, cur, prefix);
6067 if (ns == NULL) {
6068 if (ctxt->error != NULL)
6069 ctxt->error(ctxt->userData,
6070 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6071 ctxt->nbErrors++;
6072 } else {
6073 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6074 xmlNodeSetContent(cur, local);
6075 }
6076 xmlFree(local);
6077 xmlFree(prefix);
6078 }
6079 xmlFree(name);
6080 }
6081 }
6082 /*
6083 * 4.16
6084 */
6085 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6086 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6087 if (ctxt->error != NULL)
6088 ctxt->error(ctxt->userData,
6089 "Found nsName/except//nsName forbidden construct\n");
6090 ctxt->nbErrors++;
6091 }
6092 }
6093 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6094 (cur != root)) {
6095 int oldflags = ctxt->flags;
6096
6097 /*
6098 * 4.16
6099 */
6100 if ((cur->parent != NULL) &&
6101 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6102 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6103 xmlRelaxNGCleanupTree(ctxt, cur);
6104 ctxt->flags = oldflags;
6105 goto skip_children;
6106 } else if ((cur->parent != NULL) &&
6107 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6108 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6109 xmlRelaxNGCleanupTree(ctxt, cur);
6110 ctxt->flags = oldflags;
6111 goto skip_children;
6112 }
6113 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6114 /*
6115 * 4.16
6116 */
6117 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6118 if (ctxt->error != NULL)
6119 ctxt->error(ctxt->userData,
6120 "Found anyName/except//anyName forbidden construct\n");
6121 ctxt->nbErrors++;
6122 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6123 if (ctxt->error != NULL)
6124 ctxt->error(ctxt->userData,
6125 "Found nsName/except//anyName forbidden construct\n");
6126 ctxt->nbErrors++;
6127 }
6128 }
6129 /*
6130 * Thisd is not an else since "include" is transformed
6131 * into a div
6132 */
6133 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6134 xmlChar *ns;
6135 xmlNodePtr child, ins, tmp;
6136
6137 /*
6138 * implements rule 4.11
6139 */
6140
6141 ns = xmlGetProp(cur, BAD_CAST "ns");
6142
6143 child = cur->children;
6144 ins = cur;
6145 while (child != NULL) {
6146 if (ns != NULL) {
6147 if (!xmlHasProp(child, BAD_CAST "ns")) {
6148 xmlSetProp(child, BAD_CAST "ns", ns);
6149 }
6150 }
6151 tmp = child->next;
6152 xmlUnlinkNode(child);
6153 ins = xmlAddNextSibling(ins, child);
6154 child = tmp;
6155 }
6156 if (ns != NULL)
6157 xmlFree(ns);
6158 delete = cur;
6159 goto skip_children;
6160 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006161 }
6162 }
6163 /*
6164 * Simplification 4.2 whitespaces
6165 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006166 else if ((cur->type == XML_TEXT_NODE) ||
6167 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006168 if (IS_BLANK_NODE(cur)) {
6169 if (cur->parent->type == XML_ELEMENT_NODE) {
6170 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6171 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6172 delete = cur;
6173 } else {
6174 delete = cur;
6175 goto skip_children;
6176 }
6177 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006178 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006179 delete = cur;
6180 goto skip_children;
6181 }
6182
6183 /*
6184 * Skip to next node
6185 */
6186 if (cur->children != NULL) {
6187 if ((cur->children->type != XML_ENTITY_DECL) &&
6188 (cur->children->type != XML_ENTITY_REF_NODE) &&
6189 (cur->children->type != XML_ENTITY_NODE)) {
6190 cur = cur->children;
6191 continue;
6192 }
6193 }
6194skip_children:
6195 if (cur->next != NULL) {
6196 cur = cur->next;
6197 continue;
6198 }
6199
6200 do {
6201 cur = cur->parent;
6202 if (cur == NULL)
6203 break;
6204 if (cur == root) {
6205 cur = NULL;
6206 break;
6207 }
6208 if (cur->next != NULL) {
6209 cur = cur->next;
6210 break;
6211 }
6212 } while (cur != NULL);
6213 }
6214 if (delete != NULL) {
6215 xmlUnlinkNode(delete);
6216 xmlFreeNode(delete);
6217 delete = NULL;
6218 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006219}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006220
Daniel Veillardc5312d72003-02-21 17:14:10 +00006221/**
6222 * xmlRelaxNGCleanupDoc:
6223 * @ctxt: a Relax-NG parser context
6224 * @doc: an xmldocPtr document pointer
6225 *
6226 * Cleanup the document from unwanted nodes for parsing, resolve
6227 * Include and externalRef lookups.
6228 *
6229 * Returns the cleaned up document or NULL in case of error
6230 */
6231static xmlDocPtr
6232xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6233 xmlNodePtr root;
6234
6235 /*
6236 * Extract the root
6237 */
6238 root = xmlDocGetRootElement(doc);
6239 if (root == NULL) {
6240 if (ctxt->error != NULL)
6241 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6242 ctxt->URL);
6243 ctxt->nbErrors++;
6244 return (NULL);
6245 }
6246 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006247 return(doc);
6248}
6249
6250/**
6251 * xmlRelaxNGParse:
6252 * @ctxt: a Relax-NG parser context
6253 *
6254 * parse a schema definition resource and build an internal
6255 * XML Shema struture which can be used to validate instances.
6256 * *WARNING* this interface is highly subject to change
6257 *
6258 * Returns the internal XML RelaxNG structure built from the resource or
6259 * NULL in case of error
6260 */
6261xmlRelaxNGPtr
6262xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6263{
6264 xmlRelaxNGPtr ret = NULL;
6265 xmlDocPtr doc;
6266 xmlNodePtr root;
6267
6268 xmlRelaxNGInitTypes();
6269
6270 if (ctxt == NULL)
6271 return (NULL);
6272
6273 /*
6274 * First step is to parse the input document into an DOM/Infoset
6275 */
6276 if (ctxt->URL != NULL) {
6277 doc = xmlParseFile((const char *) ctxt->URL);
6278 if (doc == NULL) {
6279 if (ctxt->error != NULL)
6280 ctxt->error(ctxt->userData,
6281 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6282 ctxt->nbErrors++;
6283 return (NULL);
6284 }
6285 } else if (ctxt->buffer != NULL) {
6286 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6287 if (doc == NULL) {
6288 if (ctxt->error != NULL)
6289 ctxt->error(ctxt->userData,
6290 "xmlRelaxNGParse: could not parse schemas\n");
6291 ctxt->nbErrors++;
6292 return (NULL);
6293 }
6294 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6295 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6296 } else {
6297 if (ctxt->error != NULL)
6298 ctxt->error(ctxt->userData,
6299 "xmlRelaxNGParse: nothing to parse\n");
6300 ctxt->nbErrors++;
6301 return (NULL);
6302 }
6303 ctxt->document = doc;
6304
6305 /*
6306 * Some preprocessing of the document content
6307 */
6308 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6309 if (doc == NULL) {
6310 xmlFreeDoc(ctxt->document);
6311 ctxt->document = NULL;
6312 return(NULL);
6313 }
6314
Daniel Veillard6eadf632003-01-23 18:29:16 +00006315 /*
6316 * Then do the parsing for good
6317 */
6318 root = xmlDocGetRootElement(doc);
6319 if (root == NULL) {
6320 if (ctxt->error != NULL)
6321 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6322 ctxt->URL);
6323 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006324 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006325 return (NULL);
6326 }
6327 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006328 if (ret == NULL) {
6329 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006330 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006331 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006332
6333 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006334 * Check the ref/defines links
6335 */
6336 /*
6337 * try to preprocess interleaves
6338 */
6339 if (ctxt->interleaves != NULL) {
6340 xmlHashScan(ctxt->interleaves,
6341 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6342 }
6343
6344 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006345 * if there was a parsing error return NULL
6346 */
6347 if (ctxt->nbErrors > 0) {
6348 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006349 ctxt->document = NULL;
6350 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006351 return(NULL);
6352 }
6353
6354 /*
6355 * Transfer the pointer for cleanup at the schema level.
6356 */
6357 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006358 ctxt->document = NULL;
6359 ret->documents = ctxt->documents;
6360 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006361
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006362 ret->includes = ctxt->includes;
6363 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006364 ret->defNr = ctxt->defNr;
6365 ret->defTab = ctxt->defTab;
6366 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006367 if (ctxt->idref == 1)
6368 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006369
6370 return (ret);
6371}
6372
6373/**
6374 * xmlRelaxNGSetParserErrors:
6375 * @ctxt: a Relax-NG validation context
6376 * @err: the error callback
6377 * @warn: the warning callback
6378 * @ctx: contextual data for the callbacks
6379 *
6380 * Set the callback functions used to handle errors for a validation context
6381 */
6382void
6383xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6384 xmlRelaxNGValidityErrorFunc err,
6385 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6386 if (ctxt == NULL)
6387 return;
6388 ctxt->error = err;
6389 ctxt->warning = warn;
6390 ctxt->userData = ctx;
6391}
6392/************************************************************************
6393 * *
6394 * Dump back a compiled form *
6395 * *
6396 ************************************************************************/
6397static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6398
6399/**
6400 * xmlRelaxNGDumpDefines:
6401 * @output: the file output
6402 * @defines: a list of define structures
6403 *
6404 * Dump a RelaxNG structure back
6405 */
6406static void
6407xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6408 while (defines != NULL) {
6409 xmlRelaxNGDumpDefine(output, defines);
6410 defines = defines->next;
6411 }
6412}
6413
6414/**
6415 * xmlRelaxNGDumpDefine:
6416 * @output: the file output
6417 * @define: a define structure
6418 *
6419 * Dump a RelaxNG structure back
6420 */
6421static void
6422xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6423 if (define == NULL)
6424 return;
6425 switch(define->type) {
6426 case XML_RELAXNG_EMPTY:
6427 fprintf(output, "<empty/>\n");
6428 break;
6429 case XML_RELAXNG_NOT_ALLOWED:
6430 fprintf(output, "<notAllowed/>\n");
6431 break;
6432 case XML_RELAXNG_TEXT:
6433 fprintf(output, "<text/>\n");
6434 break;
6435 case XML_RELAXNG_ELEMENT:
6436 fprintf(output, "<element>\n");
6437 if (define->name != NULL) {
6438 fprintf(output, "<name");
6439 if (define->ns != NULL)
6440 fprintf(output, " ns=\"%s\"", define->ns);
6441 fprintf(output, ">%s</name>\n", define->name);
6442 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006443 xmlRelaxNGDumpDefines(output, define->attrs);
6444 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006445 fprintf(output, "</element>\n");
6446 break;
6447 case XML_RELAXNG_LIST:
6448 fprintf(output, "<list>\n");
6449 xmlRelaxNGDumpDefines(output, define->content);
6450 fprintf(output, "</list>\n");
6451 break;
6452 case XML_RELAXNG_ONEORMORE:
6453 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006454 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006455 fprintf(output, "</oneOrMore>\n");
6456 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006457 case XML_RELAXNG_ZEROORMORE:
6458 fprintf(output, "<zeroOrMore>\n");
6459 xmlRelaxNGDumpDefines(output, define->content);
6460 fprintf(output, "</zeroOrMore>\n");
6461 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006462 case XML_RELAXNG_CHOICE:
6463 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006464 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006465 fprintf(output, "</choice>\n");
6466 break;
6467 case XML_RELAXNG_GROUP:
6468 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006469 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006470 fprintf(output, "</group>\n");
6471 break;
6472 case XML_RELAXNG_INTERLEAVE:
6473 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006474 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006475 fprintf(output, "</interleave>\n");
6476 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006477 case XML_RELAXNG_OPTIONAL:
6478 fprintf(output, "<optional>\n");
6479 xmlRelaxNGDumpDefines(output, define->content);
6480 fprintf(output, "</optional>\n");
6481 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006482 case XML_RELAXNG_ATTRIBUTE:
6483 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006484 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006485 fprintf(output, "</attribute>\n");
6486 break;
6487 case XML_RELAXNG_DEF:
6488 fprintf(output, "<define");
6489 if (define->name != NULL)
6490 fprintf(output, " name=\"%s\"", define->name);
6491 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006492 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006493 fprintf(output, "</define>\n");
6494 break;
6495 case XML_RELAXNG_REF:
6496 fprintf(output, "<ref");
6497 if (define->name != NULL)
6498 fprintf(output, " name=\"%s\"", define->name);
6499 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006500 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006501 fprintf(output, "</ref>\n");
6502 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006503 case XML_RELAXNG_PARENTREF:
6504 fprintf(output, "<parentRef");
6505 if (define->name != NULL)
6506 fprintf(output, " name=\"%s\"", define->name);
6507 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006508 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006509 fprintf(output, "</parentRef>\n");
6510 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006511 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006512 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006513 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006514 fprintf(output, "</externalRef>\n");
6515 break;
6516 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006517 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006518 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006519 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006520 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006521 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006522 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006523 TODO
6524 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006525 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006526 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006527 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006528 }
6529}
6530
6531/**
6532 * xmlRelaxNGDumpGrammar:
6533 * @output: the file output
6534 * @grammar: a grammar structure
6535 * @top: is this a top grammar
6536 *
6537 * Dump a RelaxNG structure back
6538 */
6539static void
6540xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6541{
6542 if (grammar == NULL)
6543 return;
6544
6545 fprintf(output, "<grammar");
6546 if (top)
6547 fprintf(output,
6548 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6549 switch(grammar->combine) {
6550 case XML_RELAXNG_COMBINE_UNDEFINED:
6551 break;
6552 case XML_RELAXNG_COMBINE_CHOICE:
6553 fprintf(output, " combine=\"choice\"");
6554 break;
6555 case XML_RELAXNG_COMBINE_INTERLEAVE:
6556 fprintf(output, " combine=\"interleave\"");
6557 break;
6558 default:
6559 fprintf(output, " <!-- invalid combine value -->");
6560 }
6561 fprintf(output, ">\n");
6562 if (grammar->start == NULL) {
6563 fprintf(output, " <!-- grammar had no start -->");
6564 } else {
6565 fprintf(output, "<start>\n");
6566 xmlRelaxNGDumpDefine(output, grammar->start);
6567 fprintf(output, "</start>\n");
6568 }
6569 /* TODO ? Dump the defines ? */
6570 fprintf(output, "</grammar>\n");
6571}
6572
6573/**
6574 * xmlRelaxNGDump:
6575 * @output: the file output
6576 * @schema: a schema structure
6577 *
6578 * Dump a RelaxNG structure back
6579 */
6580void
6581xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6582{
6583 if (schema == NULL) {
6584 fprintf(output, "RelaxNG empty or failed to compile\n");
6585 return;
6586 }
6587 fprintf(output, "RelaxNG: ");
6588 if (schema->doc == NULL) {
6589 fprintf(output, "no document\n");
6590 } else if (schema->doc->URL != NULL) {
6591 fprintf(output, "%s\n", schema->doc->URL);
6592 } else {
6593 fprintf(output, "\n");
6594 }
6595 if (schema->topgrammar == NULL) {
6596 fprintf(output, "RelaxNG has no top grammar\n");
6597 return;
6598 }
6599 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6600}
6601
Daniel Veillardfebcca42003-02-16 15:44:18 +00006602/**
6603 * xmlRelaxNGDumpTree:
6604 * @output: the file output
6605 * @schema: a schema structure
6606 *
6607 * Dump the transformed RelaxNG tree.
6608 */
6609void
6610xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6611{
6612 if (schema == NULL) {
6613 fprintf(output, "RelaxNG empty or failed to compile\n");
6614 return;
6615 }
6616 if (schema->doc == NULL) {
6617 fprintf(output, "no document\n");
6618 } else {
6619 xmlDocDump(output, schema->doc);
6620 }
6621}
6622
Daniel Veillard6eadf632003-01-23 18:29:16 +00006623/************************************************************************
6624 * *
6625 * Validation implementation *
6626 * *
6627 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006628static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6629 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006630static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6631 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006632
6633/**
6634 * xmlRelaxNGSkipIgnored:
6635 * @ctxt: a schema validation context
6636 * @node: the top node.
6637 *
6638 * Skip ignorable nodes in that context
6639 *
6640 * Returns the new sibling or NULL in case of error.
6641 */
6642static xmlNodePtr
6643xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6644 xmlNodePtr node) {
6645 /*
6646 * TODO complete and handle entities
6647 */
6648 while ((node != NULL) &&
6649 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006650 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006651 (((node->type == XML_TEXT_NODE) ||
6652 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard6eadf632003-01-23 18:29:16 +00006653 (IS_BLANK_NODE(node))))) {
6654 node = node->next;
6655 }
6656 return(node);
6657}
6658
6659/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006660 * xmlRelaxNGNormalize:
6661 * @ctxt: a schema validation context
6662 * @str: the string to normalize
6663 *
6664 * Implements the normalizeWhiteSpace( s ) function from
6665 * section 6.2.9 of the spec
6666 *
6667 * Returns the new string or NULL in case of error.
6668 */
6669static xmlChar *
6670xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6671 xmlChar *ret, *p;
6672 const xmlChar *tmp;
6673 int len;
6674
6675 if (str == NULL)
6676 return(NULL);
6677 tmp = str;
6678 while (*tmp != 0) tmp++;
6679 len = tmp - str;
6680
6681 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6682 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006683 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006684 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006685 } else {
6686 xmlGenericError(xmlGenericErrorContext,
6687 "xmlRelaxNGNormalize: out of memory\n");
6688 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006689 return(NULL);
6690 }
6691 p = ret;
6692 while (IS_BLANK(*str)) str++;
6693 while (*str != 0) {
6694 if (IS_BLANK(*str)) {
6695 while (IS_BLANK(*str)) str++;
6696 if (*str == 0)
6697 break;
6698 *p++ = ' ';
6699 } else
6700 *p++ = *str++;
6701 }
6702 *p = 0;
6703 return(ret);
6704}
6705
6706/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006707 * xmlRelaxNGValidateDatatype:
6708 * @ctxt: a Relax-NG validation context
6709 * @value: the string value
6710 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006711 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006712 *
6713 * Validate the given value against the dataype
6714 *
6715 * Returns 0 if the validation succeeded or an error code.
6716 */
6717static int
6718xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006719 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006720 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006721 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006722 void *result = NULL;
6723 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006724
6725 if ((define == NULL) || (define->data == NULL)) {
6726 return(-1);
6727 }
6728 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006729 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006730 if ((define->attrs != NULL) &&
6731 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006732 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006733 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006734 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006735 }
6736 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006737 ret = -1;
6738 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006739 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006740 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6741 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006742 return(-1);
6743 } else if (ret == 1) {
6744 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006745 } else if (ret == 2) {
6746 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006747 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006748 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006749 ret = -1;
6750 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006751 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006752 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
6753 if (lib->facet != NULL) {
6754 tmp = lib->facet(lib->data, define->name, cur->name,
6755 cur->value, value, result);
6756 if (tmp != 0)
6757 ret = -1;
6758 }
6759 cur = cur->next;
6760 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006761 if ((ret == 0) && (define->content != NULL)) {
6762 const xmlChar *oldvalue, *oldendvalue;
6763
6764 oldvalue = ctxt->state->value;
6765 oldendvalue = ctxt->state->endvalue;
6766 ctxt->state->value = (xmlChar *) value;
6767 ctxt->state->endvalue = NULL;
6768 ret = xmlRelaxNGValidateValue(ctxt, define->content);
6769 ctxt->state->value = (xmlChar *) oldvalue;
6770 ctxt->state->endvalue = (xmlChar *) oldendvalue;
6771 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00006772 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
6773 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00006774 return(ret);
6775}
6776
6777/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006778 * xmlRelaxNGNextValue:
6779 * @ctxt: a Relax-NG validation context
6780 *
6781 * Skip to the next value when validating within a list
6782 *
6783 * Returns 0 if the operation succeeded or an error code.
6784 */
6785static int
6786xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
6787 xmlChar *cur;
6788
6789 cur = ctxt->state->value;
6790 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
6791 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00006792 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006793 return(0);
6794 }
6795 while (*cur != 0) cur++;
6796 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
6797 if (cur == ctxt->state->endvalue)
6798 ctxt->state->value = NULL;
6799 else
6800 ctxt->state->value = cur;
6801 return(0);
6802}
6803
6804/**
6805 * xmlRelaxNGValidateValueList:
6806 * @ctxt: a Relax-NG validation context
6807 * @defines: the list of definitions to verify
6808 *
6809 * Validate the given set of definitions for the current value
6810 *
6811 * Returns 0 if the validation succeeded or an error code.
6812 */
6813static int
6814xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
6815 xmlRelaxNGDefinePtr defines) {
6816 int ret = 0;
6817
6818 while (defines != NULL) {
6819 ret = xmlRelaxNGValidateValue(ctxt, defines);
6820 if (ret != 0)
6821 break;
6822 defines = defines->next;
6823 }
6824 return(ret);
6825}
6826
6827/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006828 * xmlRelaxNGValidateValue:
6829 * @ctxt: a Relax-NG validation context
6830 * @define: the definition to verify
6831 *
6832 * Validate the given definition for the current value
6833 *
6834 * Returns 0 if the validation succeeded or an error code.
6835 */
6836static int
6837xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6838 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00006839 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006840 xmlChar *value;
6841
6842 value = ctxt->state->value;
6843 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006844 case XML_RELAXNG_EMPTY: {
6845 if ((value != NULL) && (value[0] != 0)) {
6846 int idx = 0;
6847
6848 while (IS_BLANK(value[idx]))
6849 idx++;
6850 if (value[idx] != 0)
6851 ret = -1;
6852 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006853 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00006854 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006855 case XML_RELAXNG_TEXT:
6856 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00006857 case XML_RELAXNG_VALUE: {
6858 if (!xmlStrEqual(value, define->value)) {
6859 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006860 xmlRelaxNGTypeLibraryPtr lib;
6861
6862 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
6863 if ((lib != NULL) && (lib->comp != NULL))
6864 ret = lib->comp(lib->data, define->name, value,
6865 define->value);
6866 else
6867 ret = -1;
6868 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006869 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006870 return(-1);
6871 } else if (ret == 1) {
6872 ret = 0;
6873 } else {
6874 ret = -1;
6875 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006876 } else {
6877 xmlChar *nval, *nvalue;
6878
6879 /*
6880 * TODO: trivial optimizations are possible by
6881 * computing at compile-time
6882 */
6883 nval = xmlRelaxNGNormalize(ctxt, define->value);
6884 nvalue = xmlRelaxNGNormalize(ctxt, value);
6885
Daniel Veillardea3f3982003-01-26 19:45:18 +00006886 if ((nval == NULL) || (nvalue == NULL) ||
6887 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00006888 ret = -1;
6889 if (nval != NULL)
6890 xmlFree(nval);
6891 if (nvalue != NULL)
6892 xmlFree(nvalue);
6893 }
6894 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006895 if (ret == 0)
6896 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00006897 break;
6898 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006899 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006900 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
6901 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006902 if (ret == 0)
6903 xmlRelaxNGNextValue(ctxt);
6904
6905 break;
6906 }
6907 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006908 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006909 xmlChar *oldvalue;
6910
6911 oldflags = ctxt->flags;
6912 ctxt->flags |= FLAGS_IGNORABLE;
6913
6914 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006915 while (list != NULL) {
6916 ret = xmlRelaxNGValidateValue(ctxt, list);
6917 if (ret == 0) {
6918 break;
6919 }
6920 ctxt->state->value = oldvalue;
6921 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006922 }
6923 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00006924 if (ret != 0) {
6925 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
6926 xmlRelaxNGDumpValidError(ctxt);
6927 } else {
6928 ctxt->errNr = 0;
6929 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006930 if (ret == 0)
6931 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006932 break;
6933 }
6934 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006935 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006936 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00006937#ifdef DEBUG_LIST
6938 int nb_values = 0;
6939#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006940
6941 oldvalue = ctxt->state->value;
6942 oldend = ctxt->state->endvalue;
6943
6944 val = xmlStrdup(oldvalue);
6945 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00006946 val = xmlStrdup(BAD_CAST "");
6947 }
6948 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006949 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006950 return(-1);
6951 }
6952 cur = val;
6953 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00006954 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006955 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00006956 cur++;
6957#ifdef DEBUG_LIST
6958 nb_values++;
6959#endif
6960 while (IS_BLANK(*cur))
6961 *cur++ = 0;
6962 } else
6963 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006964 }
Daniel Veillard416589a2003-02-17 17:25:42 +00006965#ifdef DEBUG_LIST
6966 xmlGenericError(xmlGenericErrorContext,
6967 "list value: '%s' found %d items\n", oldvalue, nb_values);
6968 nb_values = 0;
6969#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006970 ctxt->state->endvalue = cur;
6971 cur = val;
6972 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006973
Daniel Veillardfd573f12003-03-16 17:52:32 +00006974 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006975
Daniel Veillardfd573f12003-03-16 17:52:32 +00006976 while (list != NULL) {
6977 if (ctxt->state->value == ctxt->state->endvalue)
6978 ctxt->state->value = NULL;
6979 ret = xmlRelaxNGValidateValue(ctxt, list);
6980 if (ret != 0) {
6981#ifdef DEBUG_LIST
6982 xmlGenericError(xmlGenericErrorContext,
6983 "Failed to validate value: '%s' with %d rule\n",
6984 ctxt->state->value, nb_values);
6985#endif
6986 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006987 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006988#ifdef DEBUG_LIST
6989 nb_values++;
6990#endif
6991 list = list->next;
6992 }
6993
6994 if ((ret == 0) && (ctxt->state->value != NULL) &&
6995 (ctxt->state->value != ctxt->state->endvalue)) {
6996 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
6997 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006998 }
6999 xmlFree(val);
7000 ctxt->state->value = oldvalue;
7001 ctxt->state->endvalue = oldend;
7002 break;
7003 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007004 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007005 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7006 if (ret != 0) {
7007 break;
7008 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007009 /* no break on purpose */
7010 case XML_RELAXNG_ZEROORMORE: {
7011 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007012
7013 oldflags = ctxt->flags;
7014 ctxt->flags |= FLAGS_IGNORABLE;
7015 cur = ctxt->state->value;
7016 temp = NULL;
7017 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7018 (temp != cur)) {
7019 temp = cur;
7020 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7021 if (ret != 0) {
7022 ctxt->state->value = temp;
7023 ret = 0;
7024 break;
7025 }
7026 cur = ctxt->state->value;
7027 }
7028 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007029 if (ret != 0) {
7030 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7031 xmlRelaxNGDumpValidError(ctxt);
7032 } else {
7033 ctxt->errNr = 0;
7034 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007035 break;
7036 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007037 case XML_RELAXNG_EXCEPT: {
7038 xmlRelaxNGDefinePtr list;
7039
7040 list = define->content;
7041 while (list != NULL) {
7042 ret = xmlRelaxNGValidateValue(ctxt, list);
7043 if (ret == 0) {
7044 ret = -1;
7045 break;
7046 } else
7047 ret = 0;
7048 list = list->next;
7049 }
7050 break;
7051 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007052 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007053 case XML_RELAXNG_GROUP: {
7054 xmlRelaxNGDefinePtr list;
7055
7056 list = define->content;
7057 while (list != NULL) {
7058 ret = xmlRelaxNGValidateValue(ctxt, list);
7059 if (ret != 0) {
7060 ret = -1;
7061 break;
7062 } else
7063 ret = 0;
7064 list = list->next;
7065 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007066 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007067 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007068 case XML_RELAXNG_REF:
7069 case XML_RELAXNG_PARENTREF:
7070 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7071 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007072 default:
7073 TODO
7074 ret = -1;
7075 }
7076 return(ret);
7077}
7078
7079/**
7080 * xmlRelaxNGValidateValueContent:
7081 * @ctxt: a Relax-NG validation context
7082 * @defines: the list of definitions to verify
7083 *
7084 * Validate the given definitions for the current value
7085 *
7086 * Returns 0 if the validation succeeded or an error code.
7087 */
7088static int
7089xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7090 xmlRelaxNGDefinePtr defines) {
7091 int ret = 0;
7092
7093 while (defines != NULL) {
7094 ret = xmlRelaxNGValidateValue(ctxt, defines);
7095 if (ret != 0)
7096 break;
7097 defines = defines->next;
7098 }
7099 return(ret);
7100}
7101
7102/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007103 * xmlRelaxNGAttributeMatch:
7104 * @ctxt: a Relax-NG validation context
7105 * @define: the definition to check
7106 * @prop: the attribute
7107 *
7108 * Check if the attribute matches the definition nameClass
7109 *
7110 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7111 */
7112static int
7113xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7114 xmlRelaxNGDefinePtr define,
7115 xmlAttrPtr prop) {
7116 int ret;
7117
7118 if (define->name != NULL) {
7119 if (!xmlStrEqual(define->name, prop->name))
7120 return(0);
7121 }
7122 if (define->ns != NULL) {
7123 if (define->ns[0] == 0) {
7124 if (prop->ns != NULL)
7125 return(0);
7126 } else {
7127 if ((prop->ns == NULL) ||
7128 (!xmlStrEqual(define->ns, prop->ns->href)))
7129 return(0);
7130 }
7131 }
7132 if (define->nameClass == NULL)
7133 return(1);
7134 define = define->nameClass;
7135 if (define->type == XML_RELAXNG_EXCEPT) {
7136 xmlRelaxNGDefinePtr list;
7137
7138 list = define->content;
7139 while (list != NULL) {
7140 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7141 if (ret == 1)
7142 return(0);
7143 if (ret < 0)
7144 return(ret);
7145 list = list->next;
7146 }
7147 } else {
7148 TODO
7149 }
7150 return(1);
7151}
7152
7153/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007154 * xmlRelaxNGValidateAttribute:
7155 * @ctxt: a Relax-NG validation context
7156 * @define: the definition to verify
7157 *
7158 * Validate the given attribute definition for that node
7159 *
7160 * Returns 0 if the validation succeeded or an error code.
7161 */
7162static int
7163xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7164 xmlRelaxNGDefinePtr define) {
7165 int ret = 0, i;
7166 xmlChar *value, *oldvalue;
7167 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007168 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007169
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007170 if (ctxt->state->nbAttrLeft <= 0)
7171 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007172 if (define->name != NULL) {
7173 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7174 tmp = ctxt->state->attrs[i];
7175 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7176 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7177 (tmp->ns == NULL)) ||
7178 ((tmp->ns != NULL) &&
7179 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7180 prop = tmp;
7181 break;
7182 }
7183 }
7184 }
7185 if (prop != NULL) {
7186 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7187 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007188 oldseq = ctxt->state->seq;
7189 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007190 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007191 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007192 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007193 if (ctxt->state->value != NULL)
7194 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007195 if (value != NULL)
7196 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007197 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007198 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007199 if (ret == 0) {
7200 /*
7201 * flag the attribute as processed
7202 */
7203 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007204 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007205 }
7206 } else {
7207 ret = -1;
7208 }
7209#ifdef DEBUG
7210 xmlGenericError(xmlGenericErrorContext,
7211 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7212#endif
7213 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007214 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7215 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007216 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007217 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007218 prop = tmp;
7219 break;
7220 }
7221 }
7222 if (prop != NULL) {
7223 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7224 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007225 oldseq = ctxt->state->seq;
7226 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007227 ctxt->state->value = value;
7228 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007229 if (ctxt->state->value != NULL)
7230 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007231 if (value != NULL)
7232 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007233 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007234 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007235 if (ret == 0) {
7236 /*
7237 * flag the attribute as processed
7238 */
7239 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007240 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007241 }
7242 } else {
7243 ret = -1;
7244 }
7245#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007246 if (define->ns != NULL) {
7247 xmlGenericError(xmlGenericErrorContext,
7248 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7249 define->ns, ret);
7250 } else {
7251 xmlGenericError(xmlGenericErrorContext,
7252 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7253 ret);
7254 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007255#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007256 }
7257
7258 return(ret);
7259}
7260
7261/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007262 * xmlRelaxNGValidateAttributeList:
7263 * @ctxt: a Relax-NG validation context
7264 * @define: the list of definition to verify
7265 *
7266 * Validate the given node against the list of attribute definitions
7267 *
7268 * Returns 0 if the validation succeeded or an error code.
7269 */
7270static int
7271xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7272 xmlRelaxNGDefinePtr defines) {
7273 int ret = 0;
7274 while (defines != NULL) {
7275 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7276 ret = -1;
7277 defines = defines->next;
7278 }
7279 return(ret);
7280}
7281
7282/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007283 * xmlRelaxNGNodeMatchesList:
7284 * @node: the node
7285 * @list: a NULL terminated array of definitions
7286 *
7287 * Check if a node can be matched by one of the definitions
7288 *
7289 * Returns 1 if matches 0 otherwise
7290 */
7291static int
7292xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7293 xmlRelaxNGDefinePtr cur;
7294 int i = 0;
7295
7296 if ((node == NULL) || (list == NULL))
7297 return(0);
7298
7299 cur = list[i++];
7300 while (cur != NULL) {
7301 if ((node->type == XML_ELEMENT_NODE) &&
7302 (cur->type == XML_RELAXNG_ELEMENT)) {
7303 if (cur->name == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007304 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7305 if (node->ns == NULL)
7306 return(1);
7307 } else {
7308 if ((node->ns != NULL) &&
7309 (xmlStrEqual(node->ns->href, cur->ns)))
7310 return(1);
7311 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007312 } else if (xmlStrEqual(cur->name, node->name)) {
7313 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
7314 if (node->ns == NULL)
7315 return(1);
7316 } else {
7317 if ((node->ns != NULL) &&
7318 (xmlStrEqual(node->ns->href, cur->ns)))
7319 return(1);
7320 }
7321 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007322 } else if (((node->type == XML_TEXT_NODE) ||
7323 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007324 (cur->type == XML_RELAXNG_TEXT)) {
7325 return(1);
7326 }
7327 cur = list[i++];
7328 }
7329 return(0);
7330}
7331
7332/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007333 * xmlRelaxNGValidateInterleave:
7334 * @ctxt: a Relax-NG validation context
7335 * @define: the definition to verify
7336 *
7337 * Validate an interleave definition for a node.
7338 *
7339 * Returns 0 if the validation succeeded or an error code.
7340 */
7341static int
7342xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7343 xmlRelaxNGDefinePtr define) {
7344 int ret = 0, i, nbgroups, left;
7345 int errNr = ctxt->errNr;
7346
7347 xmlRelaxNGValidStatePtr oldstate;
7348 xmlRelaxNGPartitionPtr partitions;
7349 xmlRelaxNGInterleaveGroupPtr group = NULL;
7350 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7351 xmlNodePtr *list = NULL, *lasts = NULL;
7352
7353 if (define->data != NULL) {
7354 partitions = (xmlRelaxNGPartitionPtr) define->data;
7355 nbgroups = partitions->nbgroups;
7356 left = nbgroups;
7357 } else {
7358 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7359 return(-1);
7360 }
7361
7362 /*
7363 * Build arrays to store the first and last node of the chain
7364 * pertaining to each group
7365 */
7366 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7367 if (list == NULL) {
7368 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7369 return(-1);
7370 }
7371 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7372 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7373 if (lasts == NULL) {
7374 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7375 return(-1);
7376 }
7377 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7378
7379 /*
7380 * Walk the sequence of children finding the right group and
7381 * sorting them in sequences.
7382 */
7383 cur = ctxt->state->seq;
7384 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7385 start = cur;
7386 while (cur != NULL) {
7387 ctxt->state->seq = cur;
7388 for (i = 0;i < nbgroups;i++) {
7389 group = partitions->groups[i];
7390 if (group == NULL)
7391 continue;
7392 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7393 break;
7394 }
7395 /*
7396 * We break as soon as an element not matched is found
7397 */
7398 if (i >= nbgroups) {
7399 break;
7400 }
7401 if (lasts[i] != NULL) {
7402 lasts[i]->next = cur;
7403 lasts[i] = cur;
7404 } else {
7405 list[i] = cur;
7406 lasts[i] = cur;
7407 }
7408 if (cur->next != NULL)
7409 lastchg = cur->next;
7410 else
7411 lastchg = cur;
7412 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7413 }
7414 if (ret != 0) {
7415 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7416 ret = -1;
7417 goto done;
7418 }
7419 lastelem = cur;
7420 oldstate = ctxt->state;
7421 for (i = 0;i < nbgroups;i++) {
7422 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7423 group = partitions->groups[i];
7424 if (lasts[i] != NULL) {
7425 last = lasts[i]->next;
7426 lasts[i]->next = NULL;
7427 }
7428 ctxt->state->seq = list[i];
7429 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7430 if (ret != 0)
7431 break;
7432 if (ctxt->state != NULL) {
7433 cur = ctxt->state->seq;
7434 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7435 xmlRelaxNGFreeValidState(oldstate);
7436 oldstate = ctxt->state;
7437 ctxt->state = NULL;
7438 if (cur != NULL) {
7439 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7440 ret = -1;
7441 ctxt->state = oldstate;
7442 goto done;
7443 }
7444 } else if (ctxt->states != NULL) {
7445 int j;
7446 int found = 0;
7447
7448 for (j = 0;j < ctxt->states->nbState;j++) {
7449 cur = ctxt->states->tabState[j]->seq;
7450 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7451 if (cur == NULL) {
7452 found = 1;
7453 break;
7454 }
7455 }
7456 if (ctxt->states->nbState > 0) {
7457 xmlRelaxNGFreeValidState(oldstate);
7458 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7459 }
7460 for (j = 0;j < ctxt->states->nbState - 1;j++) {
7461 xmlRelaxNGFreeValidState(ctxt->states->tabState[j]);
7462 }
7463 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7464 ctxt->states = NULL;
7465 if (found == 0) {
7466 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7467 ret = -1;
7468 ctxt->state = oldstate;
7469 goto done;
7470 }
7471 } else {
7472 ret = -1;
7473 break;
7474 }
7475 if (lasts[i] != NULL) {
7476 lasts[i]->next = last;
7477 }
7478 }
7479 if (ctxt->state != NULL)
7480 xmlRelaxNGFreeValidState(ctxt->state);
7481 ctxt->state = oldstate;
7482 ctxt->state->seq = lastelem;
7483 if (ret != 0) {
7484 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7485 ret = -1;
7486 goto done;
7487 }
7488
7489done:
7490 /*
7491 * builds the next links chain from the prev one
7492 */
7493 cur = lastchg;
7494 while (cur != NULL) {
7495 if ((cur == start) || (cur->prev == NULL))
7496 break;
7497 cur->prev->next = cur;
7498 cur = cur->prev;
7499 }
7500 if (ret == 0) {
7501 ctxt->errNr = errNr;
7502 }
7503
7504 xmlFree(list);
7505 xmlFree(lasts);
7506 return(ret);
7507}
7508
7509/**
7510 * xmlRelaxNGValidateDefinitionList:
7511 * @ctxt: a Relax-NG validation context
7512 * @define: the list of definition to verify
7513 *
7514 * Validate the given node content against the (list) of definitions
7515 *
7516 * Returns 0 if the validation succeeded or an error code.
7517 */
7518static int
7519xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7520 xmlRelaxNGDefinePtr defines) {
7521 int ret = 0, res;
7522
7523
Daniel Veillard952379b2003-03-17 15:37:12 +00007524 if (defines == NULL) {
7525 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7526 return(-1);
7527 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007528 while (defines != NULL) {
7529 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7530 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7531 if (res < 0)
7532 ret = -1;
7533 } else {
7534 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7535 return(-1);
7536 }
7537 if (ret < 0)
7538 break;
7539 defines = defines->next;
7540 }
7541
7542 return(ret);
7543}
7544
7545/**
7546 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007547 * @ctxt: a Relax-NG validation context
7548 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007549 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007550 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007551 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007552 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007553 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007554 */
7555static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007556xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7557 xmlRelaxNGDefinePtr define,
7558 xmlNodePtr elem) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007559 int ret, oldflags;
7560
Daniel Veillardfd573f12003-03-16 17:52:32 +00007561 if (define->name != NULL) {
7562 if (!xmlStrEqual(elem->name, define->name)) {
7563 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7564 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007565 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007566 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007567 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7568 if (elem->ns == NULL) {
7569 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7570 elem->name);
7571 return(0);
7572 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7573 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7574 elem->name, define->ns);
7575 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007576 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007577 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7578 (define->name == NULL)) {
7579 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7580 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007581 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007582 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7583 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7584 define->name);
7585 return(0);
7586 }
7587
7588 if (define->nameClass == NULL)
7589 return(1);
7590
7591 define = define->nameClass;
7592 if (define->type == XML_RELAXNG_EXCEPT) {
7593 xmlRelaxNGDefinePtr list;
7594 oldflags = ctxt->flags;
7595 ctxt->flags |= FLAGS_IGNORABLE;
7596
7597 list = define->content;
7598 while (list != NULL) {
7599 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7600 if (ret == 1) {
7601 ctxt->flags = oldflags;
7602 return(0);
7603 }
7604 if (ret < 0) {
7605 ctxt->flags = oldflags;
7606 return(ret);
7607 }
7608 list = list->next;
7609 }
7610 ret = 1;
7611 ctxt->flags = oldflags;
7612 } else if (define->type == XML_RELAXNG_CHOICE) {
7613 xmlRelaxNGDefinePtr list;
7614
7615 oldflags = ctxt->flags;
7616 ctxt->flags |= FLAGS_IGNORABLE;
7617
7618 list = define->nameClass;
7619 while (list != NULL) {
7620 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7621 if (ret == 1) {
7622 ctxt->flags = oldflags;
7623 return(1);
7624 }
7625 if (ret < 0) {
7626 ctxt->flags = oldflags;
7627 return(ret);
7628 }
7629 list = list->next;
7630 }
7631 if (ret != 0) {
7632 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7633 xmlRelaxNGDumpValidError(ctxt);
7634 } else {
7635 ctxt->errNr = 0;
7636 }
7637 ret = 0;
7638 ctxt->flags = oldflags;
7639 } else {
7640 TODO
7641 ret = -1;
7642 }
7643 return(ret);
7644}
7645
7646/**
7647 * xmlRelaxNGValidateElementEnd:
7648 * @ctxt: a Relax-NG validation context
7649 *
7650 * Validate the end of the element, implements check that
7651 * there is nothing left not consumed in the element content
7652 * or in the attribute list.
7653 *
7654 * Returns 0 if the validation succeeded or an error code.
7655 */
7656static int
7657xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
7658 int ret = 0, i;
7659 xmlRelaxNGValidStatePtr state;
7660
7661 state = ctxt->state;
7662 if (state->seq != NULL) {
7663 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
7664 if (state->seq != NULL) {
7665 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
7666 state->node->name, state->seq->name);
7667 ret = -1;
7668 }
7669 }
7670 for (i = 0;i < state->nbAttrs;i++) {
7671 if (state->attrs[i] != NULL) {
7672 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
7673 state->attrs[i]->name, state->node->name);
7674 ret = -1;
7675 }
7676 }
7677 return(ret);
7678}
7679
7680/**
7681 * xmlRelaxNGValidateState:
7682 * @ctxt: a Relax-NG validation context
7683 * @define: the definition to verify
7684 *
7685 * Validate the current state against the definition
7686 *
7687 * Returns 0 if the validation succeeded or an error code.
7688 */
7689static int
7690xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
7691 xmlRelaxNGDefinePtr define) {
7692 xmlNodePtr node;
7693 int ret = 0, i, tmp, oldflags, errNr;
7694 xmlRelaxNGValidStatePtr oldstate, state;
7695
7696 if (define == NULL) {
7697 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
7698 return(-1);
7699 }
7700
7701 if (ctxt->state != NULL) {
7702 node = ctxt->state->seq;
7703 } else {
7704 node = NULL;
7705 }
7706#ifdef DEBUG
7707 for (i = 0;i < ctxt->depth;i++)
7708 xmlGenericError(xmlGenericErrorContext, " ");
7709 xmlGenericError(xmlGenericErrorContext,
7710 "Start validating %s ", xmlRelaxNGDefName(define));
7711 if (define->name != NULL)
7712 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7713 if ((node != NULL) && (node->name != NULL))
7714 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
7715 else
7716 xmlGenericError(xmlGenericErrorContext, "\n");
7717#endif
7718 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007719 switch (define->type) {
7720 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007721 node = xmlRelaxNGSkipIgnored(ctxt, node);
7722 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007723 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007724 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007725 ret = -1;
7726 break;
7727 case XML_RELAXNG_TEXT:
7728 while ((node != NULL) &&
7729 ((node->type == XML_TEXT_NODE) ||
7730 (node->type == XML_COMMENT_NODE) ||
7731 (node->type == XML_PI_NODE) ||
7732 (node->type == XML_CDATA_SECTION_NODE)))
7733 node = node->next;
7734 ctxt->state->seq = node;
7735 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007736 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007737 errNr = ctxt->errNr;
7738 node = xmlRelaxNGSkipIgnored(ctxt, node);
7739 if (node == NULL) {
7740 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
7741 ret = -1;
7742 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7743 xmlRelaxNGDumpValidError(ctxt);
7744 break;
7745 }
7746 if (node->type != XML_ELEMENT_NODE) {
7747 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7748 ret = -1;
7749 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7750 xmlRelaxNGDumpValidError(ctxt);
7751 break;
7752 }
7753 /*
7754 * This node was already validated successfully against
7755 * this definition.
7756 */
7757 if (node->_private == define) {
7758 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7759 break;
7760 }
7761
7762 ret = xmlRelaxNGElementMatch(ctxt, define, node);
7763 if (ret <= 0) {
7764 ret = -1;
7765 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7766 xmlRelaxNGDumpValidError(ctxt);
7767 break;
7768 }
7769 ret = 0;
7770 if (ctxt->errNr != 0) {
7771 while ((ctxt->err != NULL) &&
7772 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
7773 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
7774 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
7775 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
7776 xmlRelaxNGValidErrorPop(ctxt);
7777 }
7778 errNr = ctxt->errNr;
7779
7780 state = xmlRelaxNGNewValidState(ctxt, node);
7781 if (state == NULL) {
7782 ret = -1;
7783 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7784 xmlRelaxNGDumpValidError(ctxt);
7785 break;
7786 }
7787
7788 oldstate = ctxt->state;
7789 ctxt->state = state;
7790 if (define->attrs != NULL) {
7791 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7792 if (tmp != 0) {
7793 ret = -1;
7794 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7795 }
7796 }
7797 if (define->content != NULL) {
7798 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7799 if (tmp != 0) {
7800 ret = -1;
7801 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
7802 }
7803 }
7804 if (ctxt->states != NULL) {
7805 tmp = -1;
7806
7807 oldflags = ctxt->flags;
7808 ctxt->flags |= FLAGS_IGNORABLE;
7809
7810 for (i = 0;i < ctxt->states->nbState;i++) {
7811 state = ctxt->states->tabState[i];
7812 ctxt->state = state;
7813
7814 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7815 tmp = 0;
7816 xmlRelaxNGFreeValidState(state);
7817 }
7818 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7819 ctxt->flags = oldflags;
7820 ctxt->states = NULL;
7821 if ((ret == 0) && (tmp == -1))
7822 ret = -1;
7823 } else {
7824 state = ctxt->state;
7825 if (ret == 0)
7826 ret = xmlRelaxNGValidateElementEnd(ctxt);
7827 xmlRelaxNGFreeValidState(state);
7828 }
7829 ctxt->state = oldstate;
7830 if (oldstate != NULL)
7831 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
7832 if (ret == 0) {
7833 node->_private = define;
7834 }
7835 if (ret != 0) {
7836 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7837 xmlRelaxNGDumpValidError(ctxt);
7838 } else {
7839 ctxt->errNr = errNr;
7840 }
7841
7842#ifdef DEBUG
7843 xmlGenericError(xmlGenericErrorContext,
7844 "xmlRelaxNGValidateDefinition(): validated %s : %d",
7845 node->name, ret);
7846 if (oldstate == NULL)
7847 xmlGenericError(xmlGenericErrorContext, ": no state\n");
7848 else if (oldstate->seq == NULL)
7849 xmlGenericError(xmlGenericErrorContext, ": done\n");
7850 else if (oldstate->seq->type == XML_ELEMENT_NODE)
7851 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
7852 oldstate->seq->name);
7853 else
7854 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
7855 oldstate->seq->name, oldstate->seq->type);
7856#endif
7857 break;
7858 case XML_RELAXNG_OPTIONAL: {
7859 oldflags = ctxt->flags;
7860 ctxt->flags |= FLAGS_IGNORABLE;
7861 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
7862 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7863 if (ret != 0) {
7864 if (ctxt->state != NULL)
7865 xmlRelaxNGFreeValidState(ctxt->state);
7866 ctxt->state = oldstate;
7867 ctxt->flags = oldflags;
7868 ret = 0;
7869 break;
7870 }
7871 if (ctxt->states != NULL) {
7872 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7873 } else {
7874 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
7875 if (ctxt->states == NULL) {
7876 xmlRelaxNGFreeValidState(oldstate);
7877 ctxt->flags = oldflags;
7878 ret = -1;
7879 break;
7880 }
7881 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
7882 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
7883 ctxt->state = NULL;
7884 }
7885 ctxt->flags = oldflags;
7886 ret = 0;
7887 break;
7888 }
7889 case XML_RELAXNG_ONEORMORE:
7890 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
7891 if (ret != 0) {
7892 break;
7893 }
7894 /* no break on purpose */
7895 case XML_RELAXNG_ZEROORMORE: {
7896 int progress;
7897 xmlRelaxNGStatesPtr states = NULL, res = NULL;
7898 int base, j;
7899
7900 res = xmlRelaxNGNewStates(ctxt, 1);
7901 if (res == NULL) {
7902 ret = -1;
7903 break;
7904 }
7905 /*
7906 * All the input states are also exit states
7907 */
7908 if (ctxt->state != NULL) {
7909 xmlRelaxNGAddStates(ctxt, res,
7910 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
7911 } else {
7912 for (j = 0;j < ctxt->states->nbState;j++) {
7913 xmlRelaxNGAddStates(ctxt, res,
7914 xmlRelaxNGCopyValidState(ctxt,
7915 ctxt->states->tabState[j]));
7916 }
7917 }
7918 oldflags = ctxt->flags;
7919 ctxt->flags |= FLAGS_IGNORABLE;
7920 do {
7921 progress = 0;
7922 base = res->nbState;
7923
7924 if (ctxt->states != NULL) {
7925 states = ctxt->states;
7926 for (i = 0;i < states->nbState;i++) {
7927 ctxt->state = states->tabState[i];
7928 ctxt->states = NULL;
7929 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7930 define->content);
7931 if (ret == 0) {
7932 if (ctxt->state != NULL) {
7933 tmp = xmlRelaxNGAddStates(ctxt, res,
7934 ctxt->state);
7935 ctxt->state = NULL;
7936 if (tmp == 1)
7937 progress = 1;
7938 } else if (ctxt->states != NULL) {
7939 for (j = 0;j < ctxt->states->nbState;j++) {
7940 tmp = xmlRelaxNGAddStates(ctxt, res,
7941 ctxt->states->tabState[j]);
7942 if (tmp == 1)
7943 progress = 1;
7944 }
7945 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7946 ctxt->states = NULL;
7947 }
7948 } else {
7949 if (ctxt->state != NULL) {
7950 xmlRelaxNGFreeValidState(ctxt->state);
7951 ctxt->state = NULL;
7952 }
7953 }
7954 }
7955 } else {
7956 ret = xmlRelaxNGValidateDefinitionList(ctxt,
7957 define->content);
7958 if (ret != 0) {
7959 xmlRelaxNGFreeValidState(ctxt->state);
7960 ctxt->state = NULL;
7961 } else {
7962 base = res->nbState;
7963 if (ctxt->state != NULL) {
7964 tmp = xmlRelaxNGAddStates(ctxt, res,
7965 ctxt->state);
7966 ctxt->state = NULL;
7967 if (tmp == 1)
7968 progress = 1;
7969 } else if (ctxt->states != NULL) {
7970 for (j = 0;j < ctxt->states->nbState;j++) {
7971 tmp = xmlRelaxNGAddStates(ctxt, res,
7972 ctxt->states->tabState[j]);
7973 if (tmp == 1)
7974 progress = 1;
7975 }
7976 if (states == NULL) {
7977 states = ctxt->states;
7978 } else {
7979 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7980 }
7981 ctxt->states = NULL;
7982 }
7983 }
7984 }
7985 if (progress) {
7986 /*
7987 * Collect all the new nodes added at that step
7988 * and make them the new node set
7989 */
7990 if (res->nbState - base == 1) {
7991 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
7992 res->tabState[base]);
7993 } else {
7994 if (states == NULL) {
7995 xmlRelaxNGNewStates(ctxt, res->nbState - base);
7996 }
7997 states->nbState = 0;
7998 for (i = base;i < res->nbState;i++)
7999 xmlRelaxNGAddStates(ctxt, states,
8000 xmlRelaxNGCopyValidState(ctxt,
8001 res->tabState[i]));
8002 ctxt->states = states;
8003 }
8004 }
8005 } while (progress == 1);
8006 if (states != NULL) {
8007 xmlRelaxNGFreeStates(ctxt, states);
8008 }
8009 ctxt->states = res;
8010 ctxt->flags = oldflags;
8011 ret = 0;
8012 break;
8013 }
8014 case XML_RELAXNG_CHOICE: {
8015 xmlRelaxNGDefinePtr list = define->content;
8016 xmlRelaxNGStatesPtr states = NULL;
8017
8018
8019 oldflags = ctxt->flags;
8020 errNr = ctxt->errNr;
8021 ctxt->flags |= FLAGS_IGNORABLE;
8022 node = xmlRelaxNGSkipIgnored(ctxt, node);
8023
8024 while (list != NULL) {
8025 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8026 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8027 if (ret == 0) {
8028 if (states == NULL) {
8029 states = xmlRelaxNGNewStates(ctxt, 1);
8030 }
8031 if (ctxt->state != NULL) {
8032 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8033 } else if (ctxt->states != NULL) {
8034 for (i = 0;i < ctxt->states->nbState;i++) {
8035 xmlRelaxNGAddStates(ctxt, states,
8036 ctxt->states->tabState[i]);
8037 }
8038 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8039 ctxt->states = NULL;
8040 }
8041 } else {
8042 xmlRelaxNGFreeValidState(ctxt->state);
8043 }
8044 ctxt->state = oldstate;
8045 list = list->next;
8046 }
8047 if (states != NULL) {
8048 xmlRelaxNGFreeValidState(oldstate);
8049 ctxt->states = states;
8050 ctxt->state = NULL;
8051 ret = 0;
8052 } else {
8053 ctxt->states = NULL;
8054 }
8055 ctxt->flags = oldflags;
8056 if (ret != 0) {
8057 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8058 xmlRelaxNGDumpValidError(ctxt);
8059 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8060 ctxt->errNr = errNr;
8061 }
8062 break;
8063 }
8064 case XML_RELAXNG_DEF:
8065 case XML_RELAXNG_GROUP:
8066 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008067 break;
8068 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008069 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008070 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008071 case XML_RELAXNG_ATTRIBUTE:
8072 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8073 break;
8074 case XML_RELAXNG_NOOP:
8075 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008076 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008077 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8078 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008079 case XML_RELAXNG_PARENTREF:
8080 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8081 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008082 case XML_RELAXNG_DATATYPE: {
8083 xmlNodePtr child;
8084 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008085
Daniel Veillardfd573f12003-03-16 17:52:32 +00008086 child = node;
8087 while (child != NULL) {
8088 if (child->type == XML_ELEMENT_NODE) {
8089 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8090 node->parent->name);
8091 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008092 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008093 } else if ((child->type == XML_TEXT_NODE) ||
8094 (child->type == XML_CDATA_SECTION_NODE)) {
8095 content = xmlStrcat(content, child->content);
8096 }
8097 /* TODO: handle entities ... */
8098 child = child->next;
8099 }
8100 if (ret == -1) {
8101 if (content != NULL)
8102 xmlFree(content);
8103 break;
8104 }
8105 if (content == NULL) {
8106 content = xmlStrdup(BAD_CAST "");
8107 if (content == NULL) {
8108 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8109 ret = -1;
8110 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008111 }
8112 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008113 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8114 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008115 if (ret == -1) {
8116 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8117 } else if (ret == 0) {
8118 ctxt->state->seq = NULL;
8119 }
8120 if (content != NULL)
8121 xmlFree(content);
8122 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008123 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008124 case XML_RELAXNG_VALUE: {
8125 xmlChar *content = NULL;
8126 xmlChar *oldvalue;
8127 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008128
Daniel Veillardfd573f12003-03-16 17:52:32 +00008129 child = node;
8130 while (child != NULL) {
8131 if (child->type == XML_ELEMENT_NODE) {
8132 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8133 node->parent->name);
8134 ret = -1;
8135 break;
8136 } else if ((child->type == XML_TEXT_NODE) ||
8137 (child->type == XML_CDATA_SECTION_NODE)) {
8138 content = xmlStrcat(content, child->content);
8139 }
8140 /* TODO: handle entities ... */
8141 child = child->next;
8142 }
8143 if (ret == -1) {
8144 if (content != NULL)
8145 xmlFree(content);
8146 break;
8147 }
8148 if (content == NULL) {
8149 content = xmlStrdup(BAD_CAST "");
8150 if (content == NULL) {
8151 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8152 ret = -1;
8153 break;
8154 }
8155 }
8156 oldvalue = ctxt->state->value;
8157 ctxt->state->value = content;
8158 ret = xmlRelaxNGValidateValue(ctxt, define);
8159 ctxt->state->value = oldvalue;
8160 if (ret == -1) {
8161 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8162 } else if (ret == 0) {
8163 ctxt->state->seq = NULL;
8164 }
8165 if (content != NULL)
8166 xmlFree(content);
8167 break;
8168 }
8169 case XML_RELAXNG_LIST: {
8170 xmlChar *content;
8171 xmlNodePtr child;
8172 xmlChar *oldvalue, *oldendvalue;
8173 int len;
8174
8175 /*
8176 * Make sure it's only text nodes
8177 */
8178
8179 content = NULL;
8180 child = node;
8181 while (child != NULL) {
8182 if (child->type == XML_ELEMENT_NODE) {
8183 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8184 node->parent->name);
8185 ret = -1;
8186 break;
8187 } else if ((child->type == XML_TEXT_NODE) ||
8188 (child->type == XML_CDATA_SECTION_NODE)) {
8189 content = xmlStrcat(content, child->content);
8190 }
8191 /* TODO: handle entities ... */
8192 child = child->next;
8193 }
8194 if (ret == -1) {
8195 if (content != NULL)
8196 xmlFree(content);
8197 break;
8198 }
8199 if (content == NULL) {
8200 content = xmlStrdup(BAD_CAST "");
8201 if (content == NULL) {
8202 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8203 ret = -1;
8204 break;
8205 }
8206 }
8207 len = xmlStrlen(content);
8208 oldvalue = ctxt->state->value;
8209 oldendvalue = ctxt->state->endvalue;
8210 ctxt->state->value = content;
8211 ctxt->state->endvalue = content + len;
8212 ret = xmlRelaxNGValidateValue(ctxt, define);
8213 ctxt->state->value = oldvalue;
8214 ctxt->state->endvalue = oldendvalue;
8215 if (ret == -1) {
8216 VALID_ERR(XML_RELAXNG_ERR_LIST);
8217 } else if ((ret == 0) && (node != NULL)) {
8218 ctxt->state->seq = node->next;
8219 }
8220 if (content != NULL)
8221 xmlFree(content);
8222 break;
8223 }
8224 case XML_RELAXNG_START:
8225 case XML_RELAXNG_EXCEPT:
8226 case XML_RELAXNG_PARAM:
8227 TODO
8228 ret = -1;
8229 break;
8230 }
8231 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008232#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008233 for (i = 0;i < ctxt->depth;i++)
8234 xmlGenericError(xmlGenericErrorContext, " ");
8235 xmlGenericError(xmlGenericErrorContext,
8236 "Validating %s ", xmlRelaxNGDefName(define));
8237 if (define->name != NULL)
8238 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8239 if (ret == 0)
8240 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8241 else
8242 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008243#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008244 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008245}
8246
8247/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008248 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008249 * @ctxt: a Relax-NG validation context
8250 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008251 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008252 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008253 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008254 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008255 */
8256static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008257xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8258 xmlRelaxNGDefinePtr define) {
8259 xmlRelaxNGStatesPtr states, res;
8260 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008261
Daniel Veillardfd573f12003-03-16 17:52:32 +00008262 /*
8263 * We should NOT have both ctxt->state and ctxt->states
8264 */
8265 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8266 TODO
8267 xmlRelaxNGFreeValidState(ctxt->state);
8268 ctxt->state = NULL;
8269 }
8270
8271 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8272 if (ctxt->states != NULL) {
8273 ctxt->state = ctxt->states->tabState[0];
8274 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8275 ctxt->states = NULL;
8276 }
8277 ret = xmlRelaxNGValidateState(ctxt, define);
8278 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8279 TODO
8280 xmlRelaxNGFreeValidState(ctxt->state);
8281 ctxt->state = NULL;
8282 }
8283 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8284 ctxt->state = ctxt->states->tabState[0];
8285 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8286 ctxt->states = NULL;
8287 }
8288 return(ret);
8289 }
8290
8291 states = ctxt->states;
8292 ctxt->states = NULL;
8293 res = NULL;
8294 j = 0;
8295 oldflags = ctxt->flags;
8296 ctxt->flags |= FLAGS_IGNORABLE;
8297 for (i = 0;i < states->nbState;i++) {
8298 ctxt->state = states->tabState[i];
8299 ctxt->states = NULL;
8300 ret = xmlRelaxNGValidateState(ctxt, define);
8301 /*
8302 * We should NOT have both ctxt->state and ctxt->states
8303 */
8304 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8305 TODO
8306 xmlRelaxNGFreeValidState(ctxt->state);
8307 ctxt->state = NULL;
8308 }
8309 if (ret == 0) {
8310 if (ctxt->states == NULL) {
8311 if (res != NULL) {
8312 /* add the state to the container */
8313 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8314 ctxt->state = NULL;
8315 } else {
8316 /* add the state directly in states */
8317 states->tabState[j++] = ctxt->state;
8318 ctxt->state = NULL;
8319 }
8320 } else {
8321 if (res == NULL) {
8322 /* make it the new container and copy other results */
8323 res = ctxt->states;
8324 ctxt->states = NULL;
8325 for (k = 0;k < j;k++)
8326 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8327 } else {
8328 /* add all the new results to res and reff the container */
8329 for (k = 0;k < ctxt->states->nbState;k++)
8330 xmlRelaxNGAddStates(ctxt, res,
8331 ctxt->states->tabState[k]);
8332 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8333 ctxt->states = NULL;
8334 }
8335 }
8336 } else {
8337 if (ctxt->state != NULL) {
8338 xmlRelaxNGFreeValidState(ctxt->state);
8339 ctxt->state = NULL;
8340 } else if (ctxt->states != NULL) {
8341 for (k = 0;k < ctxt->states->nbState;k++)
8342 xmlRelaxNGFreeValidState(ctxt->states->tabState[k]);
8343 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8344 ctxt->states = NULL;
8345 }
8346 }
8347 }
8348 ctxt->flags = oldflags;
8349 if (res != NULL) {
8350 xmlRelaxNGFreeStates(ctxt, states);
8351 ctxt->states = res;
8352 ret = 0;
8353 } else if (j > 1) {
8354 states->nbState = j;
8355 ctxt->states = states;
8356 ret =0;
8357 } else if (j == 1) {
8358 ctxt->state = states->tabState[0];
8359 xmlRelaxNGFreeStates(ctxt, states);
8360 ret = 0;
8361 } else {
8362 ret = -1;
8363 xmlRelaxNGFreeStates(ctxt, states);
8364 if (ctxt->states != NULL) {
8365 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8366 ctxt->states = NULL;
8367 }
8368 }
8369 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8370 TODO
8371 xmlRelaxNGFreeValidState(ctxt->state);
8372 ctxt->state = NULL;
8373 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008374 return(ret);
8375}
8376
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008377/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008378 * xmlRelaxNGValidateDocument:
8379 * @ctxt: a Relax-NG validation context
8380 * @doc: the document
8381 *
8382 * Validate the given document
8383 *
8384 * Returns 0 if the validation succeeded or an error code.
8385 */
8386static int
8387xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8388 int ret;
8389 xmlRelaxNGPtr schema;
8390 xmlRelaxNGGrammarPtr grammar;
8391 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008392 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008393
8394 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8395 return(-1);
8396
8397 schema = ctxt->schema;
8398 grammar = schema->topgrammar;
8399 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008400 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008401 return(-1);
8402 }
8403 state = xmlRelaxNGNewValidState(ctxt, NULL);
8404 ctxt->state = state;
8405 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008406 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8407 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008408 node = state->seq;
8409 node = xmlRelaxNGSkipIgnored(ctxt, node);
8410 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008411 if (ret != -1) {
8412 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8413 ret = -1;
8414 }
8415 }
8416 } else if (ctxt->states != NULL) {
8417 int i;
8418 int tmp = -1;
8419
8420 for (i = 0;i < ctxt->states->nbState;i++) {
8421 state = ctxt->states->tabState[i];
8422 node = state->seq;
8423 node = xmlRelaxNGSkipIgnored(ctxt, node);
8424 if (node == NULL)
8425 tmp = 0;
8426 xmlRelaxNGFreeValidState(state);
8427 }
8428 if (tmp == -1) {
8429 if (ret != -1) {
8430 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8431 ret = -1;
8432 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008433 }
8434 }
8435 xmlRelaxNGFreeValidState(state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008436 if (ret != 0)
8437 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008438 if (ctxt->idref == 1) {
8439 xmlValidCtxt vctxt;
8440
8441 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8442 vctxt.valid = 1;
8443 vctxt.error = ctxt->error;
8444 vctxt.warning = ctxt->warning;
8445 vctxt.userData = ctxt->userData;
8446
8447 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8448 ret = -1;
8449 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008450
8451 return(ret);
8452}
8453
Daniel Veillardfd573f12003-03-16 17:52:32 +00008454/************************************************************************
8455 * *
8456 * Validation interfaces *
8457 * *
8458 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008459/**
8460 * xmlRelaxNGNewValidCtxt:
8461 * @schema: a precompiled XML RelaxNGs
8462 *
8463 * Create an XML RelaxNGs validation context based on the given schema
8464 *
8465 * Returns the validation context or NULL in case of error
8466 */
8467xmlRelaxNGValidCtxtPtr
8468xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8469 xmlRelaxNGValidCtxtPtr ret;
8470
8471 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8472 if (ret == NULL) {
8473 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008474 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008475 return (NULL);
8476 }
8477 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8478 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008479 ret->error = xmlGenericError;
8480 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008481 ret->errNr = 0;
8482 ret->errMax = 0;
8483 ret->err = NULL;
8484 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008485 ret->idref = schema->idref;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008486 return (ret);
8487}
8488
8489/**
8490 * xmlRelaxNGFreeValidCtxt:
8491 * @ctxt: the schema validation context
8492 *
8493 * Free the resources associated to the schema validation context
8494 */
8495void
8496xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
8497 if (ctxt == NULL)
8498 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008499 if (ctxt->states != NULL)
8500 xmlRelaxNGFreeStates(ctxt, ctxt->states);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008501 if (ctxt->errTab != NULL)
8502 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008503 xmlFree(ctxt);
8504}
8505
8506/**
8507 * xmlRelaxNGSetValidErrors:
8508 * @ctxt: a Relax-NG validation context
8509 * @err: the error function
8510 * @warn: the warning function
8511 * @ctx: the functions context
8512 *
8513 * Set the error and warning callback informations
8514 */
8515void
8516xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8517 xmlRelaxNGValidityErrorFunc err,
8518 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8519 if (ctxt == NULL)
8520 return;
8521 ctxt->error = err;
8522 ctxt->warning = warn;
8523 ctxt->userData = ctx;
8524}
8525
8526/**
8527 * xmlRelaxNGValidateDoc:
8528 * @ctxt: a Relax-NG validation context
8529 * @doc: a parsed document tree
8530 *
8531 * Validate a document tree in memory.
8532 *
8533 * Returns 0 if the document is valid, a positive error code
8534 * number otherwise and -1 in case of internal or API error.
8535 */
8536int
8537xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8538 int ret;
8539
8540 if ((ctxt == NULL) || (doc == NULL))
8541 return(-1);
8542
8543 ctxt->doc = doc;
8544
8545 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008546 /*
8547 * TODO: build error codes
8548 */
8549 if (ret == -1)
8550 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008551 return(ret);
8552}
8553
8554#endif /* LIBXML_SCHEMAS_ENABLED */
8555