blob: 51330f0c314a5441300bb4e6d02ea495922815b3 [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 Veillard249d7bb2003-03-19 21:02:29 +0000133#define IS_MIXED 8
Daniel Veillarde063f482003-03-21 16:53:17 +0000134#define IS_TRIABLE 16
135#define IS_PROCESSED 32
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000136
Daniel Veillard6eadf632003-01-23 18:29:16 +0000137struct _xmlRelaxNGDefine {
138 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000139 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000140 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000141 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000142 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000143 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000144 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000145 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000146 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000147 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000148 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000149 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000150 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000151 short dflags; /* define related flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000152};
153
154/**
155 * _xmlRelaxNG:
156 *
157 * A RelaxNGs definition
158 */
159struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000160 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000161 xmlRelaxNGGrammarPtr topgrammar;
162 xmlDocPtr doc;
163
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000164 int idref; /* requires idref checking */
165
Daniel Veillard6eadf632003-01-23 18:29:16 +0000166 xmlHashTablePtr defs; /* define */
167 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000168 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
169 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000170 int defNr; /* number of defines used */
171 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000172
Daniel Veillard6eadf632003-01-23 18:29:16 +0000173};
174
Daniel Veillard77648bb2003-02-20 15:03:22 +0000175#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
176#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
177#define XML_RELAXNG_IN_LIST (1 << 2)
178#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
179#define XML_RELAXNG_IN_START (1 << 4)
180#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
181#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
182#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000183#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
184#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000185
186struct _xmlRelaxNGParserCtxt {
187 void *userData; /* user specific data block */
188 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
189 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000190 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000191
192 xmlRelaxNGPtr schema; /* The schema in use */
193 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000194 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000195 int flags; /* parser flags */
196 int nbErrors; /* number of errors at parse time */
197 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000198 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000199 xmlRelaxNGDefinePtr def; /* the current define */
200
201 int nbInterleaves;
202 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000203
Daniel Veillardc482e262003-02-26 14:48:48 +0000204 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
205 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000206 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000207 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000208
Daniel Veillard419a7682003-02-03 23:22:49 +0000209 int defNr; /* number of defines used */
210 int defMax; /* number of defines aloocated */
211 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
212
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213 const char *buffer;
214 int size;
215
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000216 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000217 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000218 int docNr; /* Depth of the parsing stack */
219 int docMax; /* Max depth of the parsing stack */
220 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000221
222 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000223 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000224 int incNr; /* Depth of the include parsing stack */
225 int incMax; /* Max depth of the parsing stack */
226 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000227
228 int idref; /* requires idref checking */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000229};
230
231#define FLAGS_IGNORABLE 1
232#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000233#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000234
235/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000236 * xmlRelaxNGInterleaveGroup:
237 *
238 * A RelaxNGs partition set associated to lists of definitions
239 */
240typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
241typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
242struct _xmlRelaxNGInterleaveGroup {
243 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
244 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000245 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000246};
247
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000248#define IS_DETERMINIST 1
249#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000250/**
251 * xmlRelaxNGPartitions:
252 *
253 * A RelaxNGs partition associated to an interleave group
254 */
255typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
256typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
257struct _xmlRelaxNGPartition {
258 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000259 xmlHashTablePtr triage; /* hash table used to direct nodes to the
260 right group when possible */
261 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000262 xmlRelaxNGInterleaveGroupPtr *groups;
263};
264
265/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000266 * xmlRelaxNGValidState:
267 *
268 * A RelaxNGs validation state
269 */
270#define MAX_ATTR 20
271typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
272typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
273struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000274 xmlNodePtr node; /* the current node */
275 xmlNodePtr seq; /* the sequence of children left to validate */
276 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000277 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000278 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000279 xmlChar *value; /* the value when operating on string */
280 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000281 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000282};
283
284/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000285 * xmlRelaxNGStates:
286 *
287 * A RelaxNGs container for validation state
288 */
289typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
290typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
291struct _xmlRelaxNGStates {
292 int nbState; /* the number of states */
293 int maxState; /* the size of the array */
294 xmlRelaxNGValidStatePtr *tabState;
295};
296
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000297#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000298/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000299 * xmlRelaxNGValidError:
300 *
301 * A RelaxNGs validation error
302 */
303typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
304typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
305struct _xmlRelaxNGValidError {
306 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000307 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000308 xmlNodePtr node; /* the current node */
309 xmlNodePtr seq; /* the current child */
310 const xmlChar * arg1; /* first arg */
311 const xmlChar * arg2; /* second arg */
312};
313
314/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000315 * xmlRelaxNGValidCtxt:
316 *
317 * A RelaxNGs validation context
318 */
319
320struct _xmlRelaxNGValidCtxt {
321 void *userData; /* user specific data block */
322 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
323 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
324
325 xmlRelaxNGPtr schema; /* The schema in use */
326 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000327 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000328 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000329 int idref; /* requires idref checking */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000330
331 /*
332 * Errors accumulated in branches may have to be stacked to be
333 * provided back when it's sure they affect validation.
334 */
335 xmlRelaxNGValidErrorPtr err; /* Last error */
336 int errNr; /* Depth of the error stack */
337 int errMax; /* Max depth of the error stack */
338 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000339
Daniel Veillardfd573f12003-03-16 17:52:32 +0000340 xmlRelaxNGValidStatePtr state; /* the current validation state */
341 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000342
343 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
344 int freeStatesNr;
345 int freeStatesMax;
346 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000347};
348
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000349/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000350 * xmlRelaxNGInclude:
351 *
352 * Structure associated to a RelaxNGs document element
353 */
354struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000355 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000356 xmlChar *href; /* the normalized href value */
357 xmlDocPtr doc; /* the associated XML document */
358 xmlRelaxNGDefinePtr content;/* the definitions */
359 xmlRelaxNGPtr schema; /* the schema */
360};
361
362/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000363 * xmlRelaxNGDocument:
364 *
365 * Structure associated to a RelaxNGs document element
366 */
367struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000368 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000369 xmlChar *href; /* the normalized href value */
370 xmlDocPtr doc; /* the associated XML document */
371 xmlRelaxNGDefinePtr content;/* the definitions */
372 xmlRelaxNGPtr schema; /* the schema */
373};
374
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000375
Daniel Veillard6eadf632003-01-23 18:29:16 +0000376/************************************************************************
377 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000378 * Preliminary type checking interfaces *
379 * *
380 ************************************************************************/
381/**
382 * xmlRelaxNGTypeHave:
383 * @data: data needed for the library
384 * @type: the type name
385 * @value: the value to check
386 *
387 * Function provided by a type library to check if a type is exported
388 *
389 * Returns 1 if yes, 0 if no and -1 in case of error.
390 */
391typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
392
393/**
394 * xmlRelaxNGTypeCheck:
395 * @data: data needed for the library
396 * @type: the type name
397 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000398 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000399 *
400 * Function provided by a type library to check if a value match a type
401 *
402 * Returns 1 if yes, 0 if no and -1 in case of error.
403 */
404typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000405 const xmlChar *value, void **result,
406 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000407
408/**
409 * xmlRelaxNGFacetCheck:
410 * @data: data needed for the library
411 * @type: the type name
412 * @facet: the facet name
413 * @val: the facet value
414 * @strval: the string value
415 * @value: the value to check
416 *
417 * Function provided by a type library to check a value facet
418 *
419 * Returns 1 if yes, 0 if no and -1 in case of error.
420 */
421typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
422 const xmlChar *facet, const xmlChar *val,
423 const xmlChar *strval, void *value);
424
425/**
426 * xmlRelaxNGTypeFree:
427 * @data: data needed for the library
428 * @result: the value to free
429 *
430 * Function provided by a type library to free a returned result
431 */
432typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000433
434/**
435 * xmlRelaxNGTypeCompare:
436 * @data: data needed for the library
437 * @type: the type name
438 * @value1: the first value
439 * @value2: the second value
440 *
441 * Function provided by a type library to compare two values accordingly
442 * to a type.
443 *
444 * Returns 1 if yes, 0 if no and -1 in case of error.
445 */
446typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
447 const xmlChar *value1,
448 const xmlChar *value2);
449typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
450typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
451struct _xmlRelaxNGTypeLibrary {
452 const xmlChar *namespace; /* the datatypeLibrary value */
453 void *data; /* data needed for the library */
454 xmlRelaxNGTypeHave have; /* the export function */
455 xmlRelaxNGTypeCheck check; /* the checking function */
456 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000457 xmlRelaxNGFacetCheck facet; /* the facet check function */
458 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000459};
460
461/************************************************************************
462 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000463 * Allocation functions *
464 * *
465 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000466static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
467static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000468static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000469static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000470static int xmlRelaxNGEqualValidState(
471 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
472 xmlRelaxNGValidStatePtr state1,
473 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000474static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
475 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000476
477/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000478 * xmlRelaxNGFreeDocument:
479 * @docu: a document structure
480 *
481 * Deallocate a RelaxNG document structure.
482 */
483static void
484xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
485{
486 if (docu == NULL)
487 return;
488
489 if (docu->href != NULL)
490 xmlFree(docu->href);
491 if (docu->doc != NULL)
492 xmlFreeDoc(docu->doc);
493 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000494 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000495 xmlFree(docu);
496}
497
498/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000499 * xmlRelaxNGFreeDocumentList:
500 * @docu: a list of document structure
501 *
502 * Deallocate a RelaxNG document structures.
503 */
504static void
505xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
506{
507 xmlRelaxNGDocumentPtr next;
508 while (docu != NULL) {
509 next = docu->next;
510 xmlRelaxNGFreeDocument(docu);
511 docu = next;
512 }
513}
514
515/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000516 * xmlRelaxNGFreeInclude:
517 * @incl: a include structure
518 *
519 * Deallocate a RelaxNG include structure.
520 */
521static void
522xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
523{
524 if (incl == NULL)
525 return;
526
527 if (incl->href != NULL)
528 xmlFree(incl->href);
529 if (incl->doc != NULL)
530 xmlFreeDoc(incl->doc);
531 if (incl->schema != NULL)
532 xmlRelaxNGFree(incl->schema);
533 xmlFree(incl);
534}
535
536/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000537 * xmlRelaxNGFreeIncludeList:
538 * @incl: a include structure list
539 *
540 * Deallocate a RelaxNG include structure.
541 */
542static void
543xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
544{
545 xmlRelaxNGIncludePtr next;
546 while (incl != NULL) {
547 next = incl->next;
548 xmlRelaxNGFreeInclude(incl);
549 incl = next;
550 }
551}
552
553/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000554 * xmlRelaxNGNewRelaxNG:
555 * @ctxt: a Relax-NG validation context (optional)
556 *
557 * Allocate a new RelaxNG structure.
558 *
559 * Returns the newly allocated structure or NULL in case or error
560 */
561static xmlRelaxNGPtr
562xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
563{
564 xmlRelaxNGPtr ret;
565
566 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
567 if (ret == NULL) {
568 if ((ctxt != NULL) && (ctxt->error != NULL))
569 ctxt->error(ctxt->userData, "Out of memory\n");
570 ctxt->nbErrors++;
571 return (NULL);
572 }
573 memset(ret, 0, sizeof(xmlRelaxNG));
574
575 return (ret);
576}
577
578/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000579 * xmlRelaxNGFreeInnerSchema:
580 * @schema: a schema structure
581 *
582 * Deallocate a RelaxNG schema structure.
583 */
584static void
585xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
586{
587 if (schema == NULL)
588 return;
589
590 if (schema->doc != NULL)
591 xmlFreeDoc(schema->doc);
592 if (schema->defTab != NULL) {
593 int i;
594
595 for (i = 0;i < schema->defNr;i++)
596 xmlRelaxNGFreeDefine(schema->defTab[i]);
597 xmlFree(schema->defTab);
598 }
599
600 xmlFree(schema);
601}
602
603/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000604 * xmlRelaxNGFree:
605 * @schema: a schema structure
606 *
607 * Deallocate a RelaxNG structure.
608 */
609void
610xmlRelaxNGFree(xmlRelaxNGPtr schema)
611{
612 if (schema == NULL)
613 return;
614
Daniel Veillard6eadf632003-01-23 18:29:16 +0000615 if (schema->topgrammar != NULL)
616 xmlRelaxNGFreeGrammar(schema->topgrammar);
617 if (schema->doc != NULL)
618 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000619 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000620 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000621 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000622 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000623 if (schema->defTab != NULL) {
624 int i;
625
626 for (i = 0;i < schema->defNr;i++)
627 xmlRelaxNGFreeDefine(schema->defTab[i]);
628 xmlFree(schema->defTab);
629 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000630
631 xmlFree(schema);
632}
633
634/**
635 * xmlRelaxNGNewGrammar:
636 * @ctxt: a Relax-NG validation context (optional)
637 *
638 * Allocate a new RelaxNG grammar.
639 *
640 * Returns the newly allocated structure or NULL in case or error
641 */
642static xmlRelaxNGGrammarPtr
643xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
644{
645 xmlRelaxNGGrammarPtr ret;
646
647 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
648 if (ret == NULL) {
649 if ((ctxt != NULL) && (ctxt->error != NULL))
650 ctxt->error(ctxt->userData, "Out of memory\n");
651 ctxt->nbErrors++;
652 return (NULL);
653 }
654 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
655
656 return (ret);
657}
658
659/**
660 * xmlRelaxNGFreeGrammar:
661 * @grammar: a grammar structure
662 *
663 * Deallocate a RelaxNG grammar structure.
664 */
665static void
666xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
667{
668 if (grammar == NULL)
669 return;
670
Daniel Veillardc482e262003-02-26 14:48:48 +0000671 if (grammar->children != NULL) {
672 xmlRelaxNGFreeGrammar(grammar->children);
673 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000674 if (grammar->next != NULL) {
675 xmlRelaxNGFreeGrammar(grammar->next);
676 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000677 if (grammar->refs != NULL) {
678 xmlHashFree(grammar->refs, NULL);
679 }
680 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000681 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000682 }
683
684 xmlFree(grammar);
685}
686
687/**
688 * xmlRelaxNGNewDefine:
689 * @ctxt: a Relax-NG validation context
690 * @node: the node in the input document.
691 *
692 * Allocate a new RelaxNG define.
693 *
694 * Returns the newly allocated structure or NULL in case or error
695 */
696static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000697xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000698{
699 xmlRelaxNGDefinePtr ret;
700
Daniel Veillard419a7682003-02-03 23:22:49 +0000701 if (ctxt->defMax == 0) {
702 ctxt->defMax = 16;
703 ctxt->defNr = 0;
704 ctxt->defTab = (xmlRelaxNGDefinePtr *)
705 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
706 if (ctxt->defTab == NULL) {
707 if ((ctxt != NULL) && (ctxt->error != NULL))
708 ctxt->error(ctxt->userData, "Out of memory\n");
709 ctxt->nbErrors++;
710 return (NULL);
711 }
712 } else if (ctxt->defMax <= ctxt->defNr) {
713 xmlRelaxNGDefinePtr *tmp;
714 ctxt->defMax *= 2;
715 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
716 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
717 if (tmp == NULL) {
718 if ((ctxt != NULL) && (ctxt->error != NULL))
719 ctxt->error(ctxt->userData, "Out of memory\n");
720 ctxt->nbErrors++;
721 return (NULL);
722 }
723 ctxt->defTab = tmp;
724 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000725 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
726 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000727 if ((ctxt != NULL) && (ctxt->error != NULL))
728 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000729 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000730 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000731 }
732 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000733 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000734 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000735 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000736 return (ret);
737}
738
739/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000740 * xmlRelaxNGFreePartition:
741 * @partitions: a partition set structure
742 *
743 * Deallocate RelaxNG partition set structures.
744 */
745static void
746xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
747 xmlRelaxNGInterleaveGroupPtr group;
748 int j;
749
750 if (partitions != NULL) {
751 if (partitions->groups != NULL) {
752 for (j = 0;j < partitions->nbgroups;j++) {
753 group = partitions->groups[j];
754 if (group != NULL) {
755 if (group->defs != NULL)
756 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000757 if (group->attrs != NULL)
758 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000759 xmlFree(group);
760 }
761 }
762 xmlFree(partitions->groups);
763 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000764 if (partitions->triage != NULL) {
765 xmlHashFree(partitions->triage, NULL);
766 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000767 xmlFree(partitions);
768 }
769}
770/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000771 * xmlRelaxNGFreeDefine:
772 * @define: a define structure
773 *
774 * Deallocate a RelaxNG define structure.
775 */
776static void
777xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
778{
779 if (define == NULL)
780 return;
781
Daniel Veillard419a7682003-02-03 23:22:49 +0000782 if ((define->data != NULL) &&
783 (define->type == XML_RELAXNG_INTERLEAVE))
784 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000785 if ((define->data != NULL) &&
786 (define->type == XML_RELAXNG_CHOICE))
787 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000788 if (define->name != NULL)
789 xmlFree(define->name);
790 if (define->ns != NULL)
791 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000792 if (define->value != NULL)
793 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000794 xmlFree(define);
795}
796
797/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000798 * xmlRelaxNGNewStates:
799 * @ctxt: a Relax-NG validation context
800 * @size: the default size for the container
801 *
802 * Allocate a new RelaxNG validation state container
803 * TODO: keep a pool in the ctxt
804 *
805 * Returns the newly allocated structure or NULL in case or error
806 */
807static xmlRelaxNGStatesPtr
808xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
809{
810 xmlRelaxNGStatesPtr ret;
811
Daniel Veillard798024a2003-03-19 10:36:09 +0000812 if ((ctxt != NULL) &&
813 (ctxt->freeState != NULL) &&
814 (ctxt->freeStatesNr > 0)) {
815 ctxt->freeStatesNr--;
816 ret = ctxt->freeStates[ctxt->freeStatesNr];
817 ret->nbState = 0;
818 return(ret);
819 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000820 if (size < 16) size = 16;
821
822 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
823 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
824 if (ret == NULL) {
825 if ((ctxt != NULL) && (ctxt->error != NULL))
826 ctxt->error(ctxt->userData, "Out of memory\n");
827 return (NULL);
828 }
829 ret->nbState = 0;
830 ret->maxState = size;
831 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
832 (size) * sizeof(xmlRelaxNGValidStatePtr));
833 if (ret->tabState == NULL) {
834 if ((ctxt != NULL) && (ctxt->error != NULL))
835 ctxt->error(ctxt->userData, "Out of memory\n");
836 xmlFree(ret->tabState);
837 return (NULL);
838 }
839 return(ret);
840}
841
842/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000843 * xmlRelaxNGAddStateUniq:
844 * @ctxt: a Relax-NG validation context
845 * @states: the states container
846 * @state: the validation state
847 *
848 * Add a RelaxNG validation state to the container without checking
849 * for unicity.
850 *
851 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
852 */
853static int
854xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
855 xmlRelaxNGStatesPtr states,
856 xmlRelaxNGValidStatePtr state)
857{
858 if (state == NULL) {
859 return(-1);
860 }
861 if (states->nbState >= states->maxState) {
862 xmlRelaxNGValidStatePtr *tmp;
863 int size;
864
865 size = states->maxState * 2;
866 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
867 (size) * sizeof(xmlRelaxNGValidStatePtr));
868 if (tmp == NULL) {
869 if ((ctxt != NULL) && (ctxt->error != NULL))
870 ctxt->error(ctxt->userData, "Out of memory\n");
871 return(-1);
872 }
873 states->tabState = tmp;
874 states->maxState = size;
875 }
876 states->tabState[states->nbState++] = state;
877 return(1);
878}
879
880/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000881 * xmlRelaxNGAddState:
882 * @ctxt: a Relax-NG validation context
883 * @states: the states container
884 * @state: the validation state
885 *
886 * Add a RelaxNG validation state to the container
887 *
888 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
889 */
890static int
891xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
892 xmlRelaxNGValidStatePtr state)
893{
894 int i;
895
896 if (state == NULL) {
897 return(-1);
898 }
899 if (states->nbState >= states->maxState) {
900 xmlRelaxNGValidStatePtr *tmp;
901 int size;
902
903 size = states->maxState * 2;
904 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
905 (size) * sizeof(xmlRelaxNGValidStatePtr));
906 if (tmp == NULL) {
907 if ((ctxt != NULL) && (ctxt->error != NULL))
908 ctxt->error(ctxt->userData, "Out of memory\n");
909 return(-1);
910 }
911 states->tabState = tmp;
912 states->maxState = size;
913 }
914 for (i = 0;i < states->nbState;i++) {
915 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000916 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000917 return(0);
918 }
919 }
920 states->tabState[states->nbState++] = state;
921 return(1);
922}
923
924/**
925 * xmlRelaxNGFreeStates:
926 * @ctxt: a Relax-NG validation context
927 * @states: teh container
928 *
929 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000930 */
931static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000932xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000933 xmlRelaxNGStatesPtr states)
934{
Daniel Veillard798024a2003-03-19 10:36:09 +0000935 if (states == NULL)
936 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000937 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
938 ctxt->freeStatesMax = 40;
939 ctxt->freeStatesNr = 0;
940 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
941 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
942 if (ctxt->freeStates == NULL) {
943 if ((ctxt != NULL) && (ctxt->error != NULL))
944 ctxt->error(ctxt->userData, "Out of memory\n");
945 }
946 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
947 xmlRelaxNGStatesPtr *tmp;
948
949 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
950 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
951 if (tmp == NULL) {
952 if ((ctxt != NULL) && (ctxt->error != NULL))
953 ctxt->error(ctxt->userData, "Out of memory\n");
954 xmlFree(states->tabState);
955 xmlFree(states);
956 return;
957 }
958 ctxt->freeStates = tmp;
959 ctxt->freeStatesMax *= 2;
960 }
961 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000962 xmlFree(states->tabState);
963 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000964 } else {
965 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000966 }
967}
968
969/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000970 * xmlRelaxNGNewValidState:
971 * @ctxt: a Relax-NG validation context
972 * @node: the current node or NULL for the document
973 *
974 * Allocate a new RelaxNG validation state
975 *
976 * Returns the newly allocated structure or NULL in case or error
977 */
978static xmlRelaxNGValidStatePtr
979xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
980{
981 xmlRelaxNGValidStatePtr ret;
982 xmlAttrPtr attr;
983 xmlAttrPtr attrs[MAX_ATTR];
984 int nbAttrs = 0;
985 xmlNodePtr root = NULL;
986
987 if (node == NULL) {
988 root = xmlDocGetRootElement(ctxt->doc);
989 if (root == NULL)
990 return(NULL);
991 } else {
992 attr = node->properties;
993 while (attr != NULL) {
994 if (nbAttrs < MAX_ATTR)
995 attrs[nbAttrs++] = attr;
996 else
997 nbAttrs++;
998 attr = attr->next;
999 }
1000 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001001 if ((ctxt->freeState != NULL) &&
1002 (ctxt->freeState->nbState > 0)) {
1003 ctxt->freeState->nbState--;
1004 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1005 } else {
1006 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1007 if (ret == NULL) {
1008 if ((ctxt != NULL) && (ctxt->error != NULL))
1009 ctxt->error(ctxt->userData, "Out of memory\n");
1010 return (NULL);
1011 }
1012 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001013 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001014 ret->value = NULL;
1015 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001016 if (node == NULL) {
1017 ret->node = (xmlNodePtr) ctxt->doc;
1018 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001019 } else {
1020 ret->node = node;
1021 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001022 }
1023 ret->nbAttrs = 0;
1024 if (nbAttrs > 0) {
1025 if (ret->attrs == NULL) {
1026 if (nbAttrs < 4) ret->maxAttrs = 4;
1027 else ret->maxAttrs = nbAttrs;
1028 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1029 sizeof(xmlAttrPtr));
1030 if (ret->attrs == NULL) {
1031 if ((ctxt != NULL) && (ctxt->error != NULL))
1032 ctxt->error(ctxt->userData, "Out of memory\n");
1033 return (ret);
1034 }
1035 } else if (ret->maxAttrs < nbAttrs) {
1036 xmlAttrPtr *tmp;
1037
1038 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1039 sizeof(xmlAttrPtr));
1040 if (tmp == NULL) {
1041 if ((ctxt != NULL) && (ctxt->error != NULL))
1042 ctxt->error(ctxt->userData, "Out of memory\n");
1043 return (ret);
1044 }
1045 ret->attrs = tmp;
1046 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001047 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001048 if (nbAttrs < MAX_ATTR) {
1049 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1050 } else {
1051 attr = node->properties;
1052 nbAttrs = 0;
1053 while (attr != NULL) {
1054 ret->attrs[nbAttrs++] = attr;
1055 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001056 }
1057 }
1058 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001059 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001060 return (ret);
1061}
1062
1063/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001064 * xmlRelaxNGCopyValidState:
1065 * @ctxt: a Relax-NG validation context
1066 * @state: a validation state
1067 *
1068 * Copy the validation state
1069 *
1070 * Returns the newly allocated structure or NULL in case or error
1071 */
1072static xmlRelaxNGValidStatePtr
1073xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1074 xmlRelaxNGValidStatePtr state)
1075{
1076 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001077 unsigned int maxAttrs;
1078 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001079
1080 if (state == NULL)
1081 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001082 if ((ctxt->freeState != NULL) &&
1083 (ctxt->freeState->nbState > 0)) {
1084 ctxt->freeState->nbState--;
1085 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1086 } else {
1087 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1088 if (ret == NULL) {
1089 if ((ctxt != NULL) && (ctxt->error != NULL))
1090 ctxt->error(ctxt->userData, "Out of memory\n");
1091 return (NULL);
1092 }
1093 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001094 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001095 attrs = ret->attrs;
1096 maxAttrs = ret->maxAttrs;
1097 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1098 ret->attrs = attrs;
1099 ret->maxAttrs = maxAttrs;
1100 if (state->nbAttrs > 0) {
1101 if (ret->attrs == NULL) {
1102 ret->maxAttrs = state->maxAttrs;
1103 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1104 sizeof(xmlAttrPtr));
1105 if (ret->attrs == NULL) {
1106 if ((ctxt != NULL) && (ctxt->error != NULL))
1107 ctxt->error(ctxt->userData, "Out of memory\n");
1108 ret->nbAttrs = 0;
1109 return (ret);
1110 }
1111 } else if (ret->maxAttrs < state->nbAttrs) {
1112 xmlAttrPtr *tmp;
1113
1114 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1115 sizeof(xmlAttrPtr));
1116 if (tmp == NULL) {
1117 if ((ctxt != NULL) && (ctxt->error != NULL))
1118 ctxt->error(ctxt->userData, "Out of memory\n");
1119 ret->nbAttrs = 0;
1120 return (ret);
1121 }
1122 ret->maxAttrs = state->maxAttrs;
1123 }
1124 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1125 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001126 return(ret);
1127}
1128
1129/**
1130 * xmlRelaxNGEqualValidState:
1131 * @ctxt: a Relax-NG validation context
1132 * @state1: a validation state
1133 * @state2: a validation state
1134 *
1135 * Compare the validation states for equality
1136 *
1137 * Returns 1 if equald, 0 otherwise
1138 */
1139static int
1140xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1141 xmlRelaxNGValidStatePtr state1,
1142 xmlRelaxNGValidStatePtr state2)
1143{
1144 int i;
1145
1146 if ((state1 == NULL) || (state2 == NULL))
1147 return(0);
1148 if (state1 == state2)
1149 return(1);
1150 if (state1->node != state2->node)
1151 return(0);
1152 if (state1->seq != state2->seq)
1153 return(0);
1154 if (state1->nbAttrLeft != state2->nbAttrLeft)
1155 return(0);
1156 if (state1->nbAttrs != state2->nbAttrs)
1157 return(0);
1158 if (state1->endvalue != state2->endvalue)
1159 return(0);
1160 if ((state1->value != state2->value) &&
1161 (!xmlStrEqual(state1->value, state2->value)))
1162 return(0);
1163 for (i = 0;i < state1->nbAttrs;i++) {
1164 if (state1->attrs[i] != state2->attrs[i])
1165 return(0);
1166 }
1167 return(1);
1168}
1169
1170/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001171 * xmlRelaxNGFreeValidState:
1172 * @state: a validation state structure
1173 *
1174 * Deallocate a RelaxNG validation state structure.
1175 */
1176static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001177xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1178 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001179{
1180 if (state == NULL)
1181 return;
1182
Daniel Veillard798024a2003-03-19 10:36:09 +00001183 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1184 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1185 }
1186 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1187 if (state->attrs != NULL)
1188 xmlFree(state->attrs);
1189 xmlFree(state);
1190 } else {
1191 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1192 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001193}
1194
1195/************************************************************************
1196 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001197 * Document functions *
1198 * *
1199 ************************************************************************/
1200static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1201 xmlDocPtr doc);
1202
1203/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001204 * xmlRelaxNGIncludePush:
1205 * @ctxt: the parser context
1206 * @value: the element doc
1207 *
1208 * Pushes a new include on top of the include stack
1209 *
1210 * Returns 0 in case of error, the index in the stack otherwise
1211 */
1212static int
1213xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1214 xmlRelaxNGIncludePtr value)
1215{
1216 if (ctxt->incTab == NULL) {
1217 ctxt->incMax = 4;
1218 ctxt->incNr = 0;
1219 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1220 ctxt->incMax * sizeof(ctxt->incTab[0]));
1221 if (ctxt->incTab == NULL) {
1222 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1223 return (0);
1224 }
1225 }
1226 if (ctxt->incNr >= ctxt->incMax) {
1227 ctxt->incMax *= 2;
1228 ctxt->incTab =
1229 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1230 ctxt->incMax *
1231 sizeof(ctxt->incTab[0]));
1232 if (ctxt->incTab == NULL) {
1233 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1234 return (0);
1235 }
1236 }
1237 ctxt->incTab[ctxt->incNr] = value;
1238 ctxt->inc = value;
1239 return (ctxt->incNr++);
1240}
1241
1242/**
1243 * xmlRelaxNGIncludePop:
1244 * @ctxt: the parser context
1245 *
1246 * Pops the top include from the include stack
1247 *
1248 * Returns the include just removed
1249 */
1250static xmlRelaxNGIncludePtr
1251xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1252{
1253 xmlRelaxNGIncludePtr ret;
1254
1255 if (ctxt->incNr <= 0)
1256 return (0);
1257 ctxt->incNr--;
1258 if (ctxt->incNr > 0)
1259 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1260 else
1261 ctxt->inc = NULL;
1262 ret = ctxt->incTab[ctxt->incNr];
1263 ctxt->incTab[ctxt->incNr] = 0;
1264 return (ret);
1265}
1266
1267/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001268 * xmlRelaxNGRemoveRedefine:
1269 * @ctxt: the parser context
1270 * @URL: the normalized URL
1271 * @target: the included target
1272 * @name: the define name to eliminate
1273 *
1274 * Applies the elimination algorithm of 4.7
1275 *
1276 * Returns 0 in case of error, 1 in case of success.
1277 */
1278static int
1279xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1280 const xmlChar *URL ATTRIBUTE_UNUSED,
1281 xmlNodePtr target, const xmlChar *name) {
1282 int found = 0;
1283 xmlNodePtr tmp, tmp2;
1284 xmlChar *name2;
1285
1286#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001287 if (name == NULL)
1288 xmlGenericError(xmlGenericErrorContext,
1289 "Elimination of <include> start from %s\n", URL);
1290 else
1291 xmlGenericError(xmlGenericErrorContext,
1292 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001293#endif
1294 tmp = target;
1295 while (tmp != NULL) {
1296 tmp2 = tmp->next;
1297 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1298 found = 1;
1299 xmlUnlinkNode(tmp);
1300 xmlFreeNode(tmp);
1301 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1302 name2 = xmlGetProp(tmp, BAD_CAST "name");
1303 xmlRelaxNGNormExtSpace(name2);
1304 if (name2 != NULL) {
1305 if (xmlStrEqual(name, name2)) {
1306 found = 1;
1307 xmlUnlinkNode(tmp);
1308 xmlFreeNode(tmp);
1309 }
1310 xmlFree(name2);
1311 }
1312 } else if (IS_RELAXNG(tmp, "include")) {
1313 xmlChar *href = NULL;
1314 xmlRelaxNGDocumentPtr inc = tmp->_private;
1315
1316 if ((inc != NULL) && (inc->doc != NULL) &&
1317 (inc->doc->children != NULL)) {
1318
1319 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1320#ifdef DEBUG_INCLUDE
1321 href = xmlGetProp(tmp, BAD_CAST "href");
1322#endif
1323 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1324 inc->doc->children->children, name) == 1) {
1325 found = 1;
1326 }
1327 if (href != NULL)
1328 xmlFree(href);
1329 }
1330 }
1331 }
1332 tmp = tmp2;
1333 }
1334 return(found);
1335}
1336
1337/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001338 * xmlRelaxNGLoadInclude:
1339 * @ctxt: the parser context
1340 * @URL: the normalized URL
1341 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001342 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001343 *
1344 * First lookup if the document is already loaded into the parser context,
1345 * check against recursion. If not found the resource is loaded and
1346 * the content is preprocessed before being returned back to the caller.
1347 *
1348 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1349 */
1350static xmlRelaxNGIncludePtr
1351xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001352 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001353 xmlRelaxNGIncludePtr ret = NULL;
1354 xmlDocPtr doc;
1355 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001356 xmlNodePtr root, cur;
1357
1358#ifdef DEBUG_INCLUDE
1359 xmlGenericError(xmlGenericErrorContext,
1360 "xmlRelaxNGLoadInclude(%s)\n", URL);
1361#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001362
1363 /*
1364 * check against recursion in the stack
1365 */
1366 for (i = 0;i < ctxt->incNr;i++) {
1367 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1368 if (ctxt->error != NULL)
1369 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001370 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001371 URL);
1372 ctxt->nbErrors++;
1373 return(NULL);
1374 }
1375 }
1376
1377 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001378 * load the document
1379 */
1380 doc = xmlParseFile((const char *) URL);
1381 if (doc == NULL) {
1382 if (ctxt->error != NULL)
1383 ctxt->error(ctxt->userData,
1384 "xmlRelaxNG: could not load %s\n", URL);
1385 ctxt->nbErrors++;
1386 return (NULL);
1387 }
1388
Daniel Veillard5add8682003-03-10 13:13:58 +00001389#ifdef DEBUG_INCLUDE
1390 xmlGenericError(xmlGenericErrorContext,
1391 "Parsed %s Okay\n", URL);
1392#endif
1393
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001394 /*
1395 * Allocate the document structures and register it first.
1396 */
1397 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1398 if (ret == NULL) {
1399 if (ctxt->error != NULL)
1400 ctxt->error(ctxt->userData,
1401 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1402 ctxt->nbErrors++;
1403 xmlFreeDoc(doc);
1404 return (NULL);
1405 }
1406 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1407 ret->doc = doc;
1408 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001409 ret->next = ctxt->includes;
1410 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001411
1412 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001413 * transmit the ns if needed
1414 */
1415 if (ns != NULL) {
1416 root = xmlDocGetRootElement(doc);
1417 if (root != NULL) {
1418 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1419 xmlSetProp(root, BAD_CAST"ns", ns);
1420 }
1421 }
1422 }
1423
1424 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001425 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001426 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 xmlRelaxNGIncludePush(ctxt, ret);
1428
1429 /*
1430 * Some preprocessing of the document content, this include recursing
1431 * in the include stack.
1432 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001433#ifdef DEBUG_INCLUDE
1434 xmlGenericError(xmlGenericErrorContext,
1435 "cleanup of %s\n", URL);
1436#endif
1437
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1439 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001440 ctxt->inc = NULL;
1441 return(NULL);
1442 }
1443
1444 /*
1445 * Pop up the include from the stack
1446 */
1447 xmlRelaxNGIncludePop(ctxt);
1448
Daniel Veillard5add8682003-03-10 13:13:58 +00001449#ifdef DEBUG_INCLUDE
1450 xmlGenericError(xmlGenericErrorContext,
1451 "Checking of %s\n", URL);
1452#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001453 /*
1454 * Check that the top element is a grammar
1455 */
1456 root = xmlDocGetRootElement(doc);
1457 if (root == NULL) {
1458 if (ctxt->error != NULL)
1459 ctxt->error(ctxt->userData,
1460 "xmlRelaxNG: included document is empty %s\n", URL);
1461 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001462 return (NULL);
1463 }
1464 if (!IS_RELAXNG(root, "grammar")) {
1465 if (ctxt->error != NULL)
1466 ctxt->error(ctxt->userData,
1467 "xmlRelaxNG: included document %s root is not a grammar\n",
1468 URL);
1469 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001470 return (NULL);
1471 }
1472
1473 /*
1474 * Elimination of redefined rules in the include.
1475 */
1476 cur = node->children;
1477 while (cur != NULL) {
1478 if (IS_RELAXNG(cur, "start")) {
1479 int found = 0;
1480
Daniel Veillard5add8682003-03-10 13:13:58 +00001481 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001482 if (!found) {
1483 if (ctxt->error != NULL)
1484 ctxt->error(ctxt->userData,
1485 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1486 URL);
1487 ctxt->nbErrors++;
1488 }
1489 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001490 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001491
1492 name = xmlGetProp(cur, BAD_CAST "name");
1493 if (name == NULL) {
1494 if (ctxt->error != NULL)
1495 ctxt->error(ctxt->userData,
1496 "xmlRelaxNG: include %s has define without name\n",
1497 URL);
1498 ctxt->nbErrors++;
1499 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001500 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001501
Daniel Veillardd2298792003-02-14 16:54:11 +00001502 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001503 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1504 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001505 if (!found) {
1506 if (ctxt->error != NULL)
1507 ctxt->error(ctxt->userData,
1508 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1509 URL, name);
1510 ctxt->nbErrors++;
1511 }
1512 xmlFree(name);
1513 }
1514 }
1515 cur = cur->next;
1516 }
1517
1518
1519 return(ret);
1520}
1521
1522/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001523 * xmlRelaxNGValidErrorPush:
1524 * @ctxt: the validation context
1525 * @err: the error code
1526 * @arg1: the first string argument
1527 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001528 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001529 *
1530 * Pushes a new error on top of the error stack
1531 *
1532 * Returns 0 in case of error, the index in the stack otherwise
1533 */
1534static int
1535xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001536 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001537{
1538 xmlRelaxNGValidErrorPtr cur;
1539 if (ctxt->errTab == NULL) {
1540 ctxt->errMax = 8;
1541 ctxt->errNr = 0;
1542 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1543 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1544 if (ctxt->errTab == NULL) {
1545 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1546 return (0);
1547 }
1548 }
1549 if (ctxt->errNr >= ctxt->errMax) {
1550 ctxt->errMax *= 2;
1551 ctxt->errTab =
1552 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1553 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1554 if (ctxt->errTab == NULL) {
1555 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1556 return (0);
1557 }
1558 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001559 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001560 (ctxt->err->node == ctxt->state->node) &&
1561 (ctxt->err->err == err))
1562 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001563 cur = &ctxt->errTab[ctxt->errNr];
1564 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001565 if (dup) {
1566 cur->arg1 = xmlStrdup(arg1);
1567 cur->arg2 = xmlStrdup(arg2);
1568 cur->flags = ERROR_IS_DUP;
1569 } else {
1570 cur->arg1 = arg1;
1571 cur->arg2 = arg2;
1572 cur->flags = 0;
1573 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001574 if (ctxt->state != NULL) {
1575 cur->node = ctxt->state->node;
1576 cur->seq = ctxt->state->seq;
1577 } else {
1578 cur->node = NULL;
1579 cur->seq = NULL;
1580 }
1581 ctxt->err = cur;
1582 return (ctxt->errNr++);
1583}
1584
1585/**
1586 * xmlRelaxNGValidErrorPop:
1587 * @ctxt: the validation context
1588 *
1589 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001590 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001591static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001592xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1593{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001594 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001595
1596 if (ctxt->errNr <= 0)
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001597 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001598 ctxt->errNr--;
1599 if (ctxt->errNr > 0)
1600 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1601 else
1602 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001603 cur = &ctxt->errTab[ctxt->errNr];
1604 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001605 if (cur->arg1 != NULL)
1606 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001607 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001608 if (cur->arg2 != NULL)
1609 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001610 cur->arg2 = NULL;
1611 cur->flags = 0;
1612 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001613}
1614
Daniel Veillard42f12e92003-03-07 18:32:59 +00001615/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001616 * xmlRelaxNGDocumentPush:
1617 * @ctxt: the parser context
1618 * @value: the element doc
1619 *
1620 * Pushes a new doc on top of the doc stack
1621 *
1622 * Returns 0 in case of error, the index in the stack otherwise
1623 */
1624static int
1625xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1626 xmlRelaxNGDocumentPtr value)
1627{
1628 if (ctxt->docTab == NULL) {
1629 ctxt->docMax = 4;
1630 ctxt->docNr = 0;
1631 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1632 ctxt->docMax * sizeof(ctxt->docTab[0]));
1633 if (ctxt->docTab == NULL) {
1634 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1635 return (0);
1636 }
1637 }
1638 if (ctxt->docNr >= ctxt->docMax) {
1639 ctxt->docMax *= 2;
1640 ctxt->docTab =
1641 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1642 ctxt->docMax *
1643 sizeof(ctxt->docTab[0]));
1644 if (ctxt->docTab == NULL) {
1645 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1646 return (0);
1647 }
1648 }
1649 ctxt->docTab[ctxt->docNr] = value;
1650 ctxt->doc = value;
1651 return (ctxt->docNr++);
1652}
1653
1654/**
1655 * xmlRelaxNGDocumentPop:
1656 * @ctxt: the parser context
1657 *
1658 * Pops the top doc from the doc stack
1659 *
1660 * Returns the doc just removed
1661 */
1662static xmlRelaxNGDocumentPtr
1663xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1664{
1665 xmlRelaxNGDocumentPtr ret;
1666
1667 if (ctxt->docNr <= 0)
1668 return (0);
1669 ctxt->docNr--;
1670 if (ctxt->docNr > 0)
1671 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1672 else
1673 ctxt->doc = NULL;
1674 ret = ctxt->docTab[ctxt->docNr];
1675 ctxt->docTab[ctxt->docNr] = 0;
1676 return (ret);
1677}
1678
1679/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001680 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001681 * @ctxt: the parser context
1682 * @URL: the normalized URL
1683 * @ns: the inherited ns if any
1684 *
1685 * First lookup if the document is already loaded into the parser context,
1686 * check against recursion. If not found the resource is loaded and
1687 * the content is preprocessed before being returned back to the caller.
1688 *
1689 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1690 */
1691static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001692xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001693 const xmlChar *ns) {
1694 xmlRelaxNGDocumentPtr ret = NULL;
1695 xmlDocPtr doc;
1696 xmlNodePtr root;
1697 int i;
1698
1699 /*
1700 * check against recursion in the stack
1701 */
1702 for (i = 0;i < ctxt->docNr;i++) {
1703 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1704 if (ctxt->error != NULL)
1705 ctxt->error(ctxt->userData,
1706 "Detected an externalRef recursion for %s\n",
1707 URL);
1708 ctxt->nbErrors++;
1709 return(NULL);
1710 }
1711 }
1712
1713 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001714 * load the document
1715 */
1716 doc = xmlParseFile((const char *) URL);
1717 if (doc == NULL) {
1718 if (ctxt->error != NULL)
1719 ctxt->error(ctxt->userData,
1720 "xmlRelaxNG: could not load %s\n", URL);
1721 ctxt->nbErrors++;
1722 return (NULL);
1723 }
1724
1725 /*
1726 * Allocate the document structures and register it first.
1727 */
1728 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1729 if (ret == NULL) {
1730 if (ctxt->error != NULL)
1731 ctxt->error(ctxt->userData,
1732 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1733 ctxt->nbErrors++;
1734 xmlFreeDoc(doc);
1735 return (NULL);
1736 }
1737 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1738 ret->doc = doc;
1739 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001740 ret->next = ctxt->documents;
1741 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001742
1743 /*
1744 * transmit the ns if needed
1745 */
1746 if (ns != NULL) {
1747 root = xmlDocGetRootElement(doc);
1748 if (root != NULL) {
1749 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1750 xmlSetProp(root, BAD_CAST"ns", ns);
1751 }
1752 }
1753 }
1754
1755 /*
1756 * push it on the stack and register it in the hash table
1757 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001758 xmlRelaxNGDocumentPush(ctxt, ret);
1759
1760 /*
1761 * Some preprocessing of the document content
1762 */
1763 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1764 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001765 ctxt->doc = NULL;
1766 return(NULL);
1767 }
1768
1769 xmlRelaxNGDocumentPop(ctxt);
1770
1771 return(ret);
1772}
1773
1774/************************************************************************
1775 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001776 * Error functions *
1777 * *
1778 ************************************************************************/
1779
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001780#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1781#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1782#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1783#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1784#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001785
Daniel Veillardfd573f12003-03-16 17:52:32 +00001786#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001787static const char *
1788xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1789 if (def == NULL)
1790 return("none");
1791 switch(def->type) {
1792 case XML_RELAXNG_EMPTY: return("empty");
1793 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1794 case XML_RELAXNG_EXCEPT: return("except");
1795 case XML_RELAXNG_TEXT: return("text");
1796 case XML_RELAXNG_ELEMENT: return("element");
1797 case XML_RELAXNG_DATATYPE: return("datatype");
1798 case XML_RELAXNG_VALUE: return("value");
1799 case XML_RELAXNG_LIST: return("list");
1800 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1801 case XML_RELAXNG_DEF: return("def");
1802 case XML_RELAXNG_REF: return("ref");
1803 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1804 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001805 case XML_RELAXNG_OPTIONAL: return("optional");
1806 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001807 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1808 case XML_RELAXNG_CHOICE: return("choice");
1809 case XML_RELAXNG_GROUP: return("group");
1810 case XML_RELAXNG_INTERLEAVE: return("interleave");
1811 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001812 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001813 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001814 }
1815 return("unknown");
1816}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001817#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001818
Daniel Veillard6eadf632003-01-23 18:29:16 +00001819/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001820 * xmlRelaxNGGetErrorString:
1821 * @err: the error code
1822 * @arg1: the first string argument
1823 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001824 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001825 * computes a formatted error string for the given error code and args
1826 *
1827 * Returns the error string, it must be deallocated by the caller
1828 */
1829static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001830xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1831 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001832 char msg[1000];
1833
1834 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001835 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001836 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001837 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001838
1839 msg[0] = 0;
1840 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001841 case XML_RELAXNG_OK:
1842 return(NULL);
1843 case XML_RELAXNG_ERR_MEMORY:
1844 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001845 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001846 snprintf(msg, 1000, "failed to validate type %s", arg1);
1847 break;
1848 case XML_RELAXNG_ERR_TYPEVAL:
1849 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1850 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001851 case XML_RELAXNG_ERR_DUPID:
1852 snprintf(msg, 1000, "ID %s redefined", arg1);
1853 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001854 case XML_RELAXNG_ERR_TYPECMP:
1855 snprintf(msg, 1000, "failed to compare type %s", arg1);
1856 break;
1857 case XML_RELAXNG_ERR_NOSTATE:
1858 return(xmlCharStrdup("Internal error: no state"));
1859 case XML_RELAXNG_ERR_NODEFINE:
1860 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001861 case XML_RELAXNG_ERR_INTERNAL:
1862 snprintf(msg, 1000, "Internal error: %s", arg1);
1863 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001864 case XML_RELAXNG_ERR_LISTEXTRA:
1865 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1866 break;
1867 case XML_RELAXNG_ERR_INTERNODATA:
1868 return(xmlCharStrdup("Internal: interleave block has no data"));
1869 case XML_RELAXNG_ERR_INTERSEQ:
1870 return(xmlCharStrdup("Invalid sequence in interleave"));
1871 case XML_RELAXNG_ERR_INTEREXTRA:
1872 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1873 break;
1874 case XML_RELAXNG_ERR_ELEMNAME:
1875 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1876 break;
1877 case XML_RELAXNG_ERR_ELEMNONS:
1878 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1879 break;
1880 case XML_RELAXNG_ERR_ELEMWRONGNS:
1881 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1882 arg1, arg2);
1883 break;
1884 case XML_RELAXNG_ERR_ELEMEXTRANS:
1885 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1886 break;
1887 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1888 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1889 break;
1890 case XML_RELAXNG_ERR_NOELEM:
1891 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1892 break;
1893 case XML_RELAXNG_ERR_NOTELEM:
1894 return(xmlCharStrdup("Expecting an element got text"));
1895 case XML_RELAXNG_ERR_ATTRVALID:
1896 snprintf(msg, 1000, "Element %s failed to validate attributes",
1897 arg1);
1898 break;
1899 case XML_RELAXNG_ERR_CONTENTVALID:
1900 snprintf(msg, 1000, "Element %s failed to validate content",
1901 arg1);
1902 break;
1903 case XML_RELAXNG_ERR_EXTRACONTENT:
1904 snprintf(msg, 1000, "Element %s has extra content: %s",
1905 arg1, arg2);
1906 break;
1907 case XML_RELAXNG_ERR_INVALIDATTR:
1908 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1909 arg1, arg2);
1910 break;
1911 case XML_RELAXNG_ERR_DATAELEM:
1912 snprintf(msg, 1000, "Datatype element %s has child elements",
1913 arg1);
1914 break;
1915 case XML_RELAXNG_ERR_VALELEM:
1916 snprintf(msg, 1000, "Value element %s has child elements",
1917 arg1);
1918 break;
1919 case XML_RELAXNG_ERR_LISTELEM:
1920 snprintf(msg, 1000, "List element %s has child elements",
1921 arg1);
1922 break;
1923 case XML_RELAXNG_ERR_DATATYPE:
1924 snprintf(msg, 1000, "Error validating datatype %s",
1925 arg1);
1926 break;
1927 case XML_RELAXNG_ERR_VALUE:
1928 snprintf(msg, 1000, "Error validating value %s",
1929 arg1);
1930 break;
1931 case XML_RELAXNG_ERR_LIST:
1932 return(xmlCharStrdup("Error validating list"));
1933 case XML_RELAXNG_ERR_NOGRAMMAR:
1934 return(xmlCharStrdup("No top grammar defined"));
1935 case XML_RELAXNG_ERR_EXTRADATA:
1936 return(xmlCharStrdup("Extra data in the document"));
1937 default:
1938 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001939 }
1940 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001941 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001942 }
1943 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001944 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001945}
1946
1947/**
1948 * xmlRelaxNGValidErrorContext:
1949 * @ctxt: the validation context
1950 * @node: the node
1951 * @child: the node child generating the problem.
1952 *
1953 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001954 */
1955static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001956xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1957 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001958{
1959 int line = 0;
1960 const xmlChar *file = NULL;
1961 const xmlChar *name = NULL;
1962 const char *type = "error";
1963
1964 if ((ctxt == NULL) || (ctxt->error == NULL))
1965 return;
1966
1967 if (child != NULL)
1968 node = child;
1969
1970 if (node != NULL) {
1971 if ((node->type == XML_DOCUMENT_NODE) ||
1972 (node->type == XML_HTML_DOCUMENT_NODE)) {
1973 xmlDocPtr doc = (xmlDocPtr) node;
1974
1975 file = doc->URL;
1976 } else {
1977 /*
1978 * Try to find contextual informations to report
1979 */
1980 if (node->type == XML_ELEMENT_NODE) {
1981 line = (int) node->content;
1982 } else if ((node->prev != NULL) &&
1983 (node->prev->type == XML_ELEMENT_NODE)) {
1984 line = (int) node->prev->content;
1985 } else if ((node->parent != NULL) &&
1986 (node->parent->type == XML_ELEMENT_NODE)) {
1987 line = (int) node->parent->content;
1988 }
1989 if ((node->doc != NULL) && (node->doc->URL != NULL))
1990 file = node->doc->URL;
1991 if (node->name != NULL)
1992 name = node->name;
1993 }
1994 }
1995
Daniel Veillard42f12e92003-03-07 18:32:59 +00001996 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001997
1998 if ((file != NULL) && (line != 0) && (name != NULL))
1999 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2000 type, file, line, name);
2001 else if ((file != NULL) && (name != NULL))
2002 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2003 type, file, name);
2004 else if ((file != NULL) && (line != 0))
2005 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2006 else if (file != NULL)
2007 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2008 else if (name != NULL)
2009 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2010 else
2011 ctxt->error(ctxt->userData, "%s\n", type);
2012}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002013
2014/**
2015 * xmlRelaxNGShowValidError:
2016 * @ctxt: the validation context
2017 * @err: the error number
2018 * @node: the node
2019 * @child: the node child generating the problem.
2020 * @arg1: the first argument
2021 * @arg2: the second argument
2022 *
2023 * Show a validation error.
2024 */
2025static void
2026xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2027 xmlNodePtr node, xmlNodePtr child,
2028 const xmlChar *arg1, const xmlChar *arg2)
2029{
2030 xmlChar *msg;
2031
2032 if (ctxt->error == NULL)
2033 return;
2034
2035 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2036 if (msg == NULL)
2037 return;
2038
2039 xmlRelaxNGValidErrorContext(ctxt, node, child);
2040 ctxt->error(ctxt->userData, "%s\n", msg);
2041 xmlFree(msg);
2042}
2043
2044/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002045 * xmlRelaxNGPopErrors:
2046 * @ctxt: the validation context
2047 * @level: the error level in the stack
2048 *
2049 * pop and discard all errors until the given level is reached
2050 */
2051static void
2052xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2053 int i;
2054 xmlRelaxNGValidErrorPtr err;
2055
2056 for (i = level;i < ctxt->errNr;i++) {
2057 err = &ctxt->errTab[i];
2058 if (err->flags & ERROR_IS_DUP) {
2059 if (err->arg1 != NULL)
2060 xmlFree((xmlChar *)err->arg1);
2061 err->arg1 = NULL;
2062 if (err->arg2 != NULL)
2063 xmlFree((xmlChar *)err->arg2);
2064 err->arg2 = NULL;
2065 err->flags = 0;
2066 }
2067 }
2068 ctxt->errNr = level;
2069}
2070/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002071 * xmlRelaxNGDumpValidError:
2072 * @ctxt: the validation context
2073 *
2074 * Show all validation error over a given index.
2075 */
2076static void
2077xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
2078 int i;
2079 xmlRelaxNGValidErrorPtr err;
2080
2081 for (i = 0;i < ctxt->errNr;i++) {
2082 err = &ctxt->errTab[i];
2083 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2084 err->arg1, err->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002085 if (err->flags & ERROR_IS_DUP) {
2086 if (err->arg1 != NULL)
2087 xmlFree((xmlChar *)err->arg1);
2088 err->arg1 = NULL;
2089 if (err->arg2 != NULL)
2090 xmlFree((xmlChar *)err->arg2);
2091 err->arg2 = NULL;
2092 err->flags = 0;
2093 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002094 }
2095 ctxt->errNr = 0;
2096}
2097/**
2098 * xmlRelaxNGAddValidError:
2099 * @ctxt: the validation context
2100 * @err: the error number
2101 * @arg1: the first argument
2102 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002103 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002104 *
2105 * Register a validation error, either generating it if it's sure
2106 * or stacking it for later handling if unsure.
2107 */
2108static void
2109xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002110 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002111{
2112 if ((ctxt == NULL) || (ctxt->error == NULL))
2113 return;
2114
2115 /*
2116 * generate the error directly
2117 */
2118 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2119 xmlNodePtr node, seq;
2120 /*
2121 * Flush first any stacked error which might be the
2122 * real cause of the problem.
2123 */
2124 if (ctxt->errNr != 0)
2125 xmlRelaxNGDumpValidError(ctxt);
2126 if (ctxt->state != NULL) {
2127 node = ctxt->state->node;
2128 seq = ctxt->state->seq;
2129 } else {
2130 node = seq = NULL;
2131 }
2132 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2133 }
2134 /*
2135 * Stack the error for later processing if needed
2136 */
2137 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002138 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002139 }
2140}
2141
Daniel Veillard6eadf632003-01-23 18:29:16 +00002142
2143/************************************************************************
2144 * *
2145 * Type library hooks *
2146 * *
2147 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002148static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2149 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002150
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002151/**
2152 * xmlRelaxNGSchemaTypeHave:
2153 * @data: data needed for the library
2154 * @type: the type name
2155 *
2156 * Check if the given type is provided by
2157 * the W3C XMLSchema Datatype library.
2158 *
2159 * Returns 1 if yes, 0 if no and -1 in case of error.
2160 */
2161static int
2162xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002163 const xmlChar *type) {
2164 xmlSchemaTypePtr typ;
2165
2166 if (type == NULL)
2167 return(-1);
2168 typ = xmlSchemaGetPredefinedType(type,
2169 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2170 if (typ == NULL)
2171 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002172 return(1);
2173}
2174
2175/**
2176 * xmlRelaxNGSchemaTypeCheck:
2177 * @data: data needed for the library
2178 * @type: the type name
2179 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002180 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002181 *
2182 * Check if the given type and value are validated by
2183 * the W3C XMLSchema Datatype library.
2184 *
2185 * Returns 1 if yes, 0 if no and -1 in case of error.
2186 */
2187static int
2188xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002189 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002190 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002191 void **result,
2192 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002193 xmlSchemaTypePtr typ;
2194 int ret;
2195
2196 /*
2197 * TODO: the type should be cached ab provided back, interface subject
2198 * to changes.
2199 * TODO: handle facets, may require an additional interface and keep
2200 * the value returned from the validation.
2201 */
2202 if ((type == NULL) || (value == NULL))
2203 return(-1);
2204 typ = xmlSchemaGetPredefinedType(type,
2205 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2206 if (typ == NULL)
2207 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002208 ret = xmlSchemaValPredefTypeNode(typ, value,
2209 (xmlSchemaValPtr *) result, node);
2210 if (ret == 2) /* special ID error code */
2211 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002212 if (ret == 0)
2213 return(1);
2214 if (ret > 0)
2215 return(0);
2216 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002217}
2218
2219/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002220 * xmlRelaxNGSchemaFacetCheck:
2221 * @data: data needed for the library
2222 * @type: the type name
2223 * @facet: the facet name
2224 * @val: the facet value
2225 * @strval: the string value
2226 * @value: the value to check
2227 *
2228 * Function provided by a type library to check a value facet
2229 *
2230 * Returns 1 if yes, 0 if no and -1 in case of error.
2231 */
2232static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002233xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002234 const xmlChar *facetname, const xmlChar *val,
2235 const xmlChar *strval, void *value) {
2236 xmlSchemaFacetPtr facet;
2237 xmlSchemaTypePtr typ;
2238 int ret;
2239
2240 if ((type == NULL) || (strval == NULL))
2241 return(-1);
2242 typ = xmlSchemaGetPredefinedType(type,
2243 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2244 if (typ == NULL)
2245 return(-1);
2246
2247 facet = xmlSchemaNewFacet();
2248 if (facet == NULL)
2249 return(-1);
2250
2251 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2252 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2253 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2254 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2255 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2256 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2257 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2258 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2259 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2260 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2261 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2262 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2263 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2264 facet->type = XML_SCHEMA_FACET_PATTERN;
2265 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2266 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2267 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2268 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2269 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2270 facet->type = XML_SCHEMA_FACET_LENGTH;
2271 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2272 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2273 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2274 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2275 } else {
2276 xmlSchemaFreeFacet(facet);
2277 return(-1);
2278 }
2279 facet->value = xmlStrdup(val);
2280 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2281 if (ret != 0) {
2282 xmlSchemaFreeFacet(facet);
2283 return(-1);
2284 }
2285 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2286 xmlSchemaFreeFacet(facet);
2287 if (ret != 0)
2288 return(-1);
2289 return(0);
2290}
2291
2292/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002293 * xmlRelaxNGSchemaTypeCompare:
2294 * @data: data needed for the library
2295 * @type: the type name
2296 * @value1: the first value
2297 * @value2: the second value
2298 *
2299 * Compare two values accordingly a type from the W3C XMLSchema
2300 * Datatype library.
2301 *
2302 * Returns 1 if yes, 0 if no and -1 in case of error.
2303 */
2304static int
2305xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2306 const xmlChar *type ATTRIBUTE_UNUSED,
2307 const xmlChar *value1 ATTRIBUTE_UNUSED,
2308 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2309 TODO
2310 return(1);
2311}
2312
2313/**
2314 * xmlRelaxNGDefaultTypeHave:
2315 * @data: data needed for the library
2316 * @type: the type name
2317 *
2318 * Check if the given type is provided by
2319 * the default datatype library.
2320 *
2321 * Returns 1 if yes, 0 if no and -1 in case of error.
2322 */
2323static int
2324xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2325 if (type == NULL)
2326 return(-1);
2327 if (xmlStrEqual(type, BAD_CAST "string"))
2328 return(1);
2329 if (xmlStrEqual(type, BAD_CAST "token"))
2330 return(1);
2331 return(0);
2332}
2333
2334/**
2335 * xmlRelaxNGDefaultTypeCheck:
2336 * @data: data needed for the library
2337 * @type: the type name
2338 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002339 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002340 *
2341 * Check if the given type and value are validated by
2342 * the default datatype library.
2343 *
2344 * Returns 1 if yes, 0 if no and -1 in case of error.
2345 */
2346static int
2347xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2348 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002349 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002350 void **result ATTRIBUTE_UNUSED,
2351 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002352 if (value == NULL)
2353 return(-1);
2354 if (xmlStrEqual(type, BAD_CAST "string"))
2355 return(1);
2356 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002357 return(1);
2358 }
2359
2360 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002361}
2362
2363/**
2364 * xmlRelaxNGDefaultTypeCompare:
2365 * @data: data needed for the library
2366 * @type: the type name
2367 * @value1: the first value
2368 * @value2: the second value
2369 *
2370 * Compare two values accordingly a type from the default
2371 * datatype library.
2372 *
2373 * Returns 1 if yes, 0 if no and -1 in case of error.
2374 */
2375static int
2376xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2377 const xmlChar *type ATTRIBUTE_UNUSED,
2378 const xmlChar *value1 ATTRIBUTE_UNUSED,
2379 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002380 int ret = -1;
2381
2382 if (xmlStrEqual(type, BAD_CAST "string")) {
2383 ret = xmlStrEqual(value1, value2);
2384 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2385 if (!xmlStrEqual(value1, value2)) {
2386 xmlChar *nval, *nvalue;
2387
2388 /*
2389 * TODO: trivial optimizations are possible by
2390 * computing at compile-time
2391 */
2392 nval = xmlRelaxNGNormalize(NULL, value1);
2393 nvalue = xmlRelaxNGNormalize(NULL, value2);
2394
Daniel Veillardd4310742003-02-18 21:12:46 +00002395 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002396 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002397 else if (xmlStrEqual(nval, nvalue))
2398 ret = 1;
2399 else
2400 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002401 if (nval != NULL)
2402 xmlFree(nval);
2403 if (nvalue != NULL)
2404 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002405 } else
2406 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002407 }
2408 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002409}
2410
2411static int xmlRelaxNGTypeInitialized = 0;
2412static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2413
2414/**
2415 * xmlRelaxNGFreeTypeLibrary:
2416 * @lib: the type library structure
2417 * @namespace: the URI bound to the library
2418 *
2419 * Free the structure associated to the type library
2420 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002421static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002422xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2423 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2424 if (lib == NULL)
2425 return;
2426 if (lib->namespace != NULL)
2427 xmlFree((xmlChar *)lib->namespace);
2428 xmlFree(lib);
2429}
2430
2431/**
2432 * xmlRelaxNGRegisterTypeLibrary:
2433 * @namespace: the URI bound to the library
2434 * @data: data associated to the library
2435 * @have: the provide function
2436 * @check: the checking function
2437 * @comp: the comparison function
2438 *
2439 * Register a new type library
2440 *
2441 * Returns 0 in case of success and -1 in case of error.
2442 */
2443static int
2444xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2445 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002446 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2447 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002448 xmlRelaxNGTypeLibraryPtr lib;
2449 int ret;
2450
2451 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2452 (check == NULL) || (comp == NULL))
2453 return(-1);
2454 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2455 xmlGenericError(xmlGenericErrorContext,
2456 "Relax-NG types library '%s' already registered\n",
2457 namespace);
2458 return(-1);
2459 }
2460 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2461 if (lib == NULL) {
2462 xmlGenericError(xmlGenericErrorContext,
2463 "Relax-NG types library '%s' malloc() failed\n",
2464 namespace);
2465 return (-1);
2466 }
2467 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2468 lib->namespace = xmlStrdup(namespace);
2469 lib->data = data;
2470 lib->have = have;
2471 lib->comp = comp;
2472 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002473 lib->facet = facet;
2474 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002475 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2476 if (ret < 0) {
2477 xmlGenericError(xmlGenericErrorContext,
2478 "Relax-NG types library failed to register '%s'\n",
2479 namespace);
2480 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2481 return(-1);
2482 }
2483 return(0);
2484}
2485
2486/**
2487 * xmlRelaxNGInitTypes:
2488 *
2489 * Initilize the default type libraries.
2490 *
2491 * Returns 0 in case of success and -1 in case of error.
2492 */
2493static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002494xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002495 if (xmlRelaxNGTypeInitialized != 0)
2496 return(0);
2497 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2498 if (xmlRelaxNGRegisteredTypes == NULL) {
2499 xmlGenericError(xmlGenericErrorContext,
2500 "Failed to allocate sh table for Relax-NG types\n");
2501 return(-1);
2502 }
2503 xmlRelaxNGRegisterTypeLibrary(
2504 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2505 NULL,
2506 xmlRelaxNGSchemaTypeHave,
2507 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002508 xmlRelaxNGSchemaTypeCompare,
2509 xmlRelaxNGSchemaFacetCheck,
2510 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002511 xmlRelaxNGRegisterTypeLibrary(
2512 xmlRelaxNGNs,
2513 NULL,
2514 xmlRelaxNGDefaultTypeHave,
2515 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002516 xmlRelaxNGDefaultTypeCompare,
2517 NULL,
2518 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002519 xmlRelaxNGTypeInitialized = 1;
2520 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002521}
2522
2523/**
2524 * xmlRelaxNGCleanupTypes:
2525 *
2526 * Cleanup the default Schemas type library associated to RelaxNG
2527 */
2528void
2529xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002530 if (xmlRelaxNGTypeInitialized == 0)
2531 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002532 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002533 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2534 xmlRelaxNGFreeTypeLibrary);
2535 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002536}
2537
2538/************************************************************************
2539 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002540 * Compiling element content into regexp *
2541 * *
2542 * Sometime the element content can be compiled into a pure regexp, *
2543 * This allows a faster execution and streamability at that level *
2544 * *
2545 ************************************************************************/
2546
2547/**
2548 * xmlRelaxNGIsCompileable:
2549 * @define: the definition to check
2550 *
2551 * Check if a definition is nullable.
2552 *
2553 * Returns 1 if yes, 0 if no and -1 in case of error
2554 */
2555static int
2556xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2557 if (def == NULL) {
2558 return(-1);
2559 }
2560 switch(def->type) {
2561 case XML_RELAXNG_REF:
2562 case XML_RELAXNG_EXTERNALREF:
2563 case XML_RELAXNG_PARENTREF:
2564 case XML_RELAXNG_NOOP:
2565 case XML_RELAXNG_START:
2566 return(xmlRelaxNGIsCompileable(def->content));
2567 case XML_RELAXNG_TEXT:
2568 case XML_RELAXNG_DATATYPE:
2569 case XML_RELAXNG_LIST:
2570 case XML_RELAXNG_PARAM:
2571 case XML_RELAXNG_VALUE:
2572
2573 case XML_RELAXNG_EMPTY:
2574 case XML_RELAXNG_ELEMENT:
2575 return(1);
2576 case XML_RELAXNG_OPTIONAL:
2577 case XML_RELAXNG_ZEROORMORE:
2578 case XML_RELAXNG_ONEORMORE:
2579 case XML_RELAXNG_CHOICE:
2580 case XML_RELAXNG_GROUP:
2581 case XML_RELAXNG_DEF: {
2582 xmlRelaxNGDefinePtr list;
2583 int ret;
2584
2585 list = def->content;
2586 while (list != NULL) {
2587 ret = xmlRelaxNGIsCompileable(list);
2588 if (ret != 1)
2589 return(ret);
2590 list = list->next;
2591 }
2592 return(1);
2593 }
2594 case XML_RELAXNG_EXCEPT:
2595 case XML_RELAXNG_ATTRIBUTE:
2596 case XML_RELAXNG_INTERLEAVE:
2597 return(0);
2598 case XML_RELAXNG_NOT_ALLOWED:
2599 return(-1);
2600 }
2601 return(-1);
2602}
2603
2604/************************************************************************
2605 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002606 * Parsing functions *
2607 * *
2608 ************************************************************************/
2609
2610static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2611 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2612static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2613 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2614static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002615 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002616static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2617 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002618static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2619 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002620static int xmlRelaxNGParseGrammarContent(
2621 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002622static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2623 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2624 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002625static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2626 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002627static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2628 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002629
2630
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002631#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002632
2633/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002634 * xmlRelaxNGIsNullable:
2635 * @define: the definition to verify
2636 *
2637 * Check if a definition is nullable.
2638 *
2639 * Returns 1 if yes, 0 if no and -1 in case of error
2640 */
2641static int
2642xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2643 int ret;
2644 if (define == NULL)
2645 return(-1);
2646
Daniel Veillarde063f482003-03-21 16:53:17 +00002647 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002648 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002649 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002650 return(0);
2651 switch (define->type) {
2652 case XML_RELAXNG_EMPTY:
2653 case XML_RELAXNG_TEXT:
2654 ret = 1; break;
2655 case XML_RELAXNG_NOOP:
2656 case XML_RELAXNG_DEF:
2657 case XML_RELAXNG_REF:
2658 case XML_RELAXNG_EXTERNALREF:
2659 case XML_RELAXNG_PARENTREF:
2660 case XML_RELAXNG_ONEORMORE:
2661 ret = xmlRelaxNGIsNullable(define->content);
2662 break;
2663 case XML_RELAXNG_EXCEPT:
2664 case XML_RELAXNG_NOT_ALLOWED:
2665 case XML_RELAXNG_ELEMENT:
2666 case XML_RELAXNG_DATATYPE:
2667 case XML_RELAXNG_PARAM:
2668 case XML_RELAXNG_VALUE:
2669 case XML_RELAXNG_LIST:
2670 case XML_RELAXNG_ATTRIBUTE:
2671 ret = 0; break;
2672 case XML_RELAXNG_CHOICE: {
2673 xmlRelaxNGDefinePtr list = define->content;
2674
2675 while (list != NULL) {
2676 ret = xmlRelaxNGIsNullable(list);
2677 if (ret != 0)
2678 goto done;
2679 list = list->next;
2680 }
2681 ret = 0; break;
2682 }
2683 case XML_RELAXNG_START:
2684 case XML_RELAXNG_INTERLEAVE:
2685 case XML_RELAXNG_GROUP: {
2686 xmlRelaxNGDefinePtr list = define->content;
2687
2688 while (list != NULL) {
2689 ret = xmlRelaxNGIsNullable(list);
2690 if (ret != 1)
2691 goto done;
2692 list = list->next;
2693 }
2694 return(1);
2695 }
2696 default:
2697 return(-1);
2698 }
2699done:
2700 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002701 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002702 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002703 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002704 return(ret);
2705}
2706
2707/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002708 * xmlRelaxNGIsBlank:
2709 * @str: a string
2710 *
2711 * Check if a string is ignorable c.f. 4.2. Whitespace
2712 *
2713 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2714 */
2715static int
2716xmlRelaxNGIsBlank(xmlChar *str) {
2717 if (str == NULL)
2718 return(1);
2719 while (*str != 0) {
2720 if (!(IS_BLANK(*str))) return(0);
2721 str++;
2722 }
2723 return(1);
2724}
2725
Daniel Veillard6eadf632003-01-23 18:29:16 +00002726/**
2727 * xmlRelaxNGGetDataTypeLibrary:
2728 * @ctxt: a Relax-NG parser context
2729 * @node: the current data or value element
2730 *
2731 * Applies algorithm from 4.3. datatypeLibrary attribute
2732 *
2733 * Returns the datatypeLibary value or NULL if not found
2734 */
2735static xmlChar *
2736xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2737 xmlNodePtr node) {
2738 xmlChar *ret, *escape;
2739
Daniel Veillard6eadf632003-01-23 18:29:16 +00002740 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2741 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2742 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002743 if (ret[0] == 0) {
2744 xmlFree(ret);
2745 return(NULL);
2746 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002747 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002748 if (escape == NULL) {
2749 return(ret);
2750 }
2751 xmlFree(ret);
2752 return(escape);
2753 }
2754 }
2755 node = node->parent;
2756 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002757 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2758 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002759 if (ret[0] == 0) {
2760 xmlFree(ret);
2761 return(NULL);
2762 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002763 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2764 if (escape == NULL) {
2765 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002766 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002767 xmlFree(ret);
2768 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002769 }
2770 node = node->parent;
2771 }
2772 return(NULL);
2773}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002774
2775/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002776 * xmlRelaxNGParseValue:
2777 * @ctxt: a Relax-NG parser context
2778 * @node: the data node.
2779 *
2780 * parse the content of a RelaxNG value node.
2781 *
2782 * Returns the definition pointer or NULL in case of error
2783 */
2784static xmlRelaxNGDefinePtr
2785xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2786 xmlRelaxNGDefinePtr def = NULL;
2787 xmlRelaxNGTypeLibraryPtr lib;
2788 xmlChar *type;
2789 xmlChar *library;
2790 int tmp;
2791
Daniel Veillardfd573f12003-03-16 17:52:32 +00002792 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002793 if (def == NULL)
2794 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002795 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002796
2797 type = xmlGetProp(node, BAD_CAST "type");
2798 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002799 xmlRelaxNGNormExtSpace(type);
2800 if (xmlValidateNCName(type, 0)) {
2801 if (ctxt->error != NULL)
2802 ctxt->error(ctxt->userData,
2803 "value type '%s' is not an NCName\n",
2804 type);
2805 ctxt->nbErrors++;
2806 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002807 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2808 if (library == NULL)
2809 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2810
2811 def->name = type;
2812 def->ns = library;
2813
2814 lib = (xmlRelaxNGTypeLibraryPtr)
2815 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2816 if (lib == NULL) {
2817 if (ctxt->error != NULL)
2818 ctxt->error(ctxt->userData,
2819 "Use of unregistered type library '%s'\n",
2820 library);
2821 ctxt->nbErrors++;
2822 def->data = NULL;
2823 } else {
2824 def->data = lib;
2825 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002826 if (ctxt->error != NULL)
2827 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002828 "Internal error with type library '%s': no 'have'\n",
2829 library);
2830 ctxt->nbErrors++;
2831 } else {
2832 tmp = lib->have(lib->data, def->name);
2833 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002834 if (ctxt->error != NULL)
2835 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002836 "Error type '%s' is not exported by type library '%s'\n",
2837 def->name, library);
2838 ctxt->nbErrors++;
2839 }
2840 }
2841 }
2842 }
2843 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002844 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002845 } else if (((node->children->type != XML_TEXT_NODE) &&
2846 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002847 (node->children->next != NULL)) {
2848 if (ctxt->error != NULL)
2849 ctxt->error(ctxt->userData,
2850 "Expecting a single text value for <value>content\n");
2851 ctxt->nbErrors++;
2852 } else {
2853 def->value = xmlNodeGetContent(node);
2854 if (def->value == NULL) {
2855 if (ctxt->error != NULL)
2856 ctxt->error(ctxt->userData,
2857 "Element <value> has no content\n");
2858 ctxt->nbErrors++;
2859 }
2860 }
2861 /* TODO check ahead of time that the value is okay per the type */
2862 return(def);
2863}
2864
2865/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002866 * xmlRelaxNGParseData:
2867 * @ctxt: a Relax-NG parser context
2868 * @node: the data node.
2869 *
2870 * parse the content of a RelaxNG data node.
2871 *
2872 * Returns the definition pointer or NULL in case of error
2873 */
2874static xmlRelaxNGDefinePtr
2875xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002876 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002877 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002878 xmlRelaxNGTypeLibraryPtr lib;
2879 xmlChar *type;
2880 xmlChar *library;
2881 xmlNodePtr content;
2882 int tmp;
2883
2884 type = xmlGetProp(node, BAD_CAST "type");
2885 if (type == NULL) {
2886 if (ctxt->error != NULL)
2887 ctxt->error(ctxt->userData,
2888 "data has no type\n");
2889 ctxt->nbErrors++;
2890 return(NULL);
2891 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002892 xmlRelaxNGNormExtSpace(type);
2893 if (xmlValidateNCName(type, 0)) {
2894 if (ctxt->error != NULL)
2895 ctxt->error(ctxt->userData,
2896 "data type '%s' is not an NCName\n",
2897 type);
2898 ctxt->nbErrors++;
2899 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002900 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2901 if (library == NULL)
2902 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2903
Daniel Veillardfd573f12003-03-16 17:52:32 +00002904 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002905 if (def == NULL) {
2906 xmlFree(type);
2907 return(NULL);
2908 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002909 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002910 def->name = type;
2911 def->ns = library;
2912
2913 lib = (xmlRelaxNGTypeLibraryPtr)
2914 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2915 if (lib == NULL) {
2916 if (ctxt->error != NULL)
2917 ctxt->error(ctxt->userData,
2918 "Use of unregistered type library '%s'\n",
2919 library);
2920 ctxt->nbErrors++;
2921 def->data = NULL;
2922 } else {
2923 def->data = lib;
2924 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002925 if (ctxt->error != NULL)
2926 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002927 "Internal error with type library '%s': no 'have'\n",
2928 library);
2929 ctxt->nbErrors++;
2930 } else {
2931 tmp = lib->have(lib->data, def->name);
2932 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002933 if (ctxt->error != NULL)
2934 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002935 "Error type '%s' is not exported by type library '%s'\n",
2936 def->name, library);
2937 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002938 } else if ((xmlStrEqual(library, BAD_CAST
2939 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2940 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2941 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2942 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002943 }
2944 }
2945 }
2946 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002947
2948 /*
2949 * Handle optional params
2950 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002951 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002952 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2953 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002954 if (xmlStrEqual(library,
2955 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2956 if (ctxt->error != NULL)
2957 ctxt->error(ctxt->userData,
2958 "Type library '%s' does not allow type parameters\n",
2959 library);
2960 ctxt->nbErrors++;
2961 content = content->next;
2962 while ((content != NULL) &&
2963 (xmlStrEqual(content->name, BAD_CAST "param")))
2964 content = content->next;
2965 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002966 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002967 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002968 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002969 param->name = xmlGetProp(content, BAD_CAST "name");
2970 if (param->name == NULL) {
2971 if (ctxt->error != NULL)
2972 ctxt->error(ctxt->userData,
2973 "param has no name\n");
2974 ctxt->nbErrors++;
2975 }
2976 param->value = xmlNodeGetContent(content);
2977 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002978 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002979 } else {
2980 lastparam->next = param;
2981 lastparam = param;
2982 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002983 if (lib != NULL) {
2984 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002985 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002986 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002987 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002988 }
Daniel Veillard416589a2003-02-17 17:25:42 +00002989 /*
2990 * Handle optional except
2991 */
2992 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2993 xmlNodePtr child;
2994 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2995
Daniel Veillardfd573f12003-03-16 17:52:32 +00002996 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00002997 if (except == NULL) {
2998 return(def);
2999 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003000 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003001 child = content->children;
3002 if (last == NULL) {
3003 def->content = except;
3004 } else {
3005 last->next = except;
3006 }
3007 if (child == NULL) {
3008 if (ctxt->error != NULL)
3009 ctxt->error(ctxt->userData,
3010 "except has no content\n");
3011 ctxt->nbErrors++;
3012 }
3013 while (child != NULL) {
3014 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3015 if (tmp2 != NULL) {
3016 if (last2 == NULL) {
3017 except->content = last2 = tmp2;
3018 } else {
3019 last2->next = tmp2;
3020 last2 = tmp2;
3021 }
3022 }
3023 child = child->next;
3024 }
3025 content = content->next;
3026 }
3027 /*
3028 * Check there is no unhandled data
3029 */
3030 if (content != NULL) {
3031 if (ctxt->error != NULL)
3032 ctxt->error(ctxt->userData,
3033 "Element data has unexpected content %s\n", content->name);
3034 ctxt->nbErrors++;
3035 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003036
3037 return(def);
3038}
3039
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003040static const xmlChar *invalidName = BAD_CAST "\1";
3041
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003042/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003043 * xmlRelaxNGCompareNameClasses:
3044 * @defs1: the first element/attribute defs
3045 * @defs2: the second element/attribute defs
3046 * @name: the restriction on the name
3047 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003048 *
3049 * Compare the 2 lists of element definitions. The comparison is
3050 * that if both lists do not accept the same QNames, it returns 1
3051 * If the 2 lists can accept the same QName the comparison returns 0
3052 *
3053 * Returns 1 disttinct, 0 if equal
3054 */
3055static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003056xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3057 xmlRelaxNGDefinePtr def2) {
3058 int ret = 1;
3059 xmlNode node;
3060 xmlNs ns;
3061 xmlRelaxNGValidCtxt ctxt;
3062 ctxt.flags = FLAGS_IGNORABLE;
3063
Daniel Veillard42f12e92003-03-07 18:32:59 +00003064 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3065
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003066 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3067 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3068 if (def2->type == XML_RELAXNG_TEXT)
3069 return(1);
3070 if (def1->name != NULL) {
3071 node.name = def1->name;
3072 } else {
3073 node.name = invalidName;
3074 }
3075 node.ns = &ns;
3076 if (def1->ns != NULL) {
3077 if (def1->ns[0] == 0) {
3078 node.ns = NULL;
3079 } else {
3080 ns.href = def1->ns;
3081 }
3082 } else {
3083 ns.href = invalidName;
3084 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003085 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003086 if (def1->nameClass != NULL) {
3087 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3088 } else {
3089 ret = 0;
3090 }
3091 } else {
3092 ret = 1;
3093 }
3094 } else if (def1->type == XML_RELAXNG_TEXT) {
3095 if (def2->type == XML_RELAXNG_TEXT)
3096 return(0);
3097 return(1);
3098 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003099 TODO
3100 ret = 0;
3101 } else {
3102 TODO
3103 ret = 0;
3104 }
3105 if (ret == 0)
3106 return(ret);
3107 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3108 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3109 if (def2->name != NULL) {
3110 node.name = def2->name;
3111 } else {
3112 node.name = invalidName;
3113 }
3114 node.ns = &ns;
3115 if (def2->ns != NULL) {
3116 if (def2->ns[0] == 0) {
3117 node.ns = NULL;
3118 } else {
3119 ns.href = def2->ns;
3120 }
3121 } else {
3122 ns.href = invalidName;
3123 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003124 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003125 if (def2->nameClass != NULL) {
3126 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3127 } else {
3128 ret = 0;
3129 }
3130 } else {
3131 ret = 1;
3132 }
3133 } else {
3134 TODO
3135 ret = 0;
3136 }
3137
3138 return(ret);
3139}
3140
3141/**
3142 * xmlRelaxNGCompareElemDefLists:
3143 * @ctxt: a Relax-NG parser context
3144 * @defs1: the first list of element/attribute defs
3145 * @defs2: the second list of element/attribute defs
3146 *
3147 * Compare the 2 lists of element or attribute definitions. The comparison
3148 * is that if both lists do not accept the same QNames, it returns 1
3149 * If the 2 lists can accept the same QName the comparison returns 0
3150 *
3151 * Returns 1 disttinct, 0 if equal
3152 */
3153static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003154xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3155 xmlRelaxNGDefinePtr *def1,
3156 xmlRelaxNGDefinePtr *def2) {
3157 xmlRelaxNGDefinePtr *basedef2 = def2;
3158
Daniel Veillard154877e2003-01-30 12:17:05 +00003159 if ((def1 == NULL) || (def2 == NULL))
3160 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003161 if ((*def1 == NULL) || (*def2 == NULL))
3162 return(1);
3163 while (*def1 != NULL) {
3164 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003165 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3166 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003167 def2++;
3168 }
3169 def2 = basedef2;
3170 def1++;
3171 }
3172 return(1);
3173}
3174
3175/**
3176 * xmlRelaxNGGetElements:
3177 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003178 * @def: the definition definition
3179 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003180 *
3181 * Compute the list of top elements a definition can generate
3182 *
3183 * Returns a list of elements or NULL if none was found.
3184 */
3185static xmlRelaxNGDefinePtr *
3186xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003187 xmlRelaxNGDefinePtr def,
3188 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003189 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003190 int len = 0;
3191 int max = 0;
3192
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003193 /*
3194 * Don't run that check in case of error. Infinite recursion
3195 * becomes possible.
3196 */
3197 if (ctxt->nbErrors != 0)
3198 return(NULL);
3199
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003200 parent = NULL;
3201 cur = def;
3202 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003203 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3204 (cur->type == XML_RELAXNG_TEXT))) ||
3205 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003206 if (ret == NULL) {
3207 max = 10;
3208 ret = (xmlRelaxNGDefinePtr *)
3209 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3210 if (ret == NULL) {
3211 if (ctxt->error != NULL)
3212 ctxt->error(ctxt->userData,
3213 "Out of memory in element search\n");
3214 ctxt->nbErrors++;
3215 return(NULL);
3216 }
3217 } else if (max <= len) {
3218 max *= 2;
3219 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3220 if (ret == NULL) {
3221 if (ctxt->error != NULL)
3222 ctxt->error(ctxt->userData,
3223 "Out of memory in element search\n");
3224 ctxt->nbErrors++;
3225 return(NULL);
3226 }
3227 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003228 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003229 ret[len] = NULL;
3230 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3231 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3232 (cur->type == XML_RELAXNG_GROUP) ||
3233 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003234 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3235 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003236 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003237 (cur->type == XML_RELAXNG_REF) ||
3238 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003239 /*
3240 * Don't go within elements or attributes or string values.
3241 * Just gather the element top list
3242 */
3243 if (cur->content != NULL) {
3244 parent = cur;
3245 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003246 tmp = cur;
3247 while (tmp != NULL) {
3248 tmp->parent = parent;
3249 tmp = tmp->next;
3250 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003251 continue;
3252 }
3253 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003254 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003255 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003256 if (cur->next != NULL) {
3257 cur = cur->next;
3258 continue;
3259 }
3260 do {
3261 cur = cur->parent;
3262 if (cur == NULL) break;
3263 if (cur == def) return(ret);
3264 if (cur->next != NULL) {
3265 cur = cur->next;
3266 break;
3267 }
3268 } while (cur != NULL);
3269 }
3270 return(ret);
3271}
3272
3273/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003274 * xmlRelaxNGCheckChoiceDeterminism:
3275 * @ctxt: a Relax-NG parser context
3276 * @def: the choice definition
3277 *
3278 * Also used to find indeterministic pattern in choice
3279 */
3280static void
3281xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3282 xmlRelaxNGDefinePtr def) {
3283 xmlRelaxNGDefinePtr **list;
3284 xmlRelaxNGDefinePtr cur;
3285 int nbchild = 0, i, j, ret;
3286 int is_nullable = 0;
3287 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003288 xmlHashTablePtr triage = NULL;
3289 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003290
3291 if ((def == NULL) ||
3292 (def->type != XML_RELAXNG_CHOICE))
3293 return;
3294
Daniel Veillarde063f482003-03-21 16:53:17 +00003295 if (def->dflags & IS_PROCESSED)
3296 return;
3297
Daniel Veillardfd573f12003-03-16 17:52:32 +00003298 /*
3299 * Don't run that check in case of error. Infinite recursion
3300 * becomes possible.
3301 */
3302 if (ctxt->nbErrors != 0)
3303 return;
3304
3305 is_nullable = xmlRelaxNGIsNullable(def);
3306
3307 cur = def->content;
3308 while (cur != NULL) {
3309 nbchild++;
3310 cur = cur->next;
3311 }
3312
3313 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3314 sizeof(xmlRelaxNGDefinePtr *));
3315 if (list == NULL) {
3316 if (ctxt->error != NULL)
3317 ctxt->error(ctxt->userData,
3318 "Out of memory in choice computation\n");
3319 ctxt->nbErrors++;
3320 return;
3321 }
3322 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003323 /*
3324 * a bit strong but safe
3325 */
3326 if (is_nullable == 0) {
3327 triage = xmlHashCreate(10);
3328 } else {
3329 is_triable = 0;
3330 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003331 cur = def->content;
3332 while (cur != NULL) {
3333 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003334 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3335 is_triable = 0;
3336 } else if (is_triable == 1) {
3337 xmlRelaxNGDefinePtr *tmp;
3338 int res;
3339
3340 tmp = list[i];
3341 while ((*tmp != NULL) && (is_triable == 1)) {
3342 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3343 res = xmlHashAddEntry2(triage,
3344 BAD_CAST "#text", NULL,
3345 (void *)cur);
3346 if (res != 0)
3347 is_triable = -1;
3348 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3349 ((*tmp)->name != NULL)) {
3350 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3351 res = xmlHashAddEntry2(triage,
3352 (*tmp)->name, NULL,
3353 (void *)cur);
3354 else
3355 res = xmlHashAddEntry2(triage,
3356 (*tmp)->name, (*tmp)->ns,
3357 (void *)cur);
3358 if (res != 0)
3359 is_triable = -1;
3360 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3361 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3362 res = xmlHashAddEntry2(triage,
3363 BAD_CAST "#any", NULL,
3364 (void *)cur);
3365 else
3366 res = xmlHashAddEntry2(triage,
3367 BAD_CAST "#any", (*tmp)->ns,
3368 (void *)cur);
3369 if (res != 0)
3370 is_triable = -1;
3371 } else {
3372 is_triable = -1;
3373 }
3374 tmp++;
3375 }
3376 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003377 i++;
3378 cur = cur->next;
3379 }
3380
3381 for (i = 0;i < nbchild;i++) {
3382 if (list[i] == NULL)
3383 continue;
3384 for (j = 0;j < i;j++) {
3385 if (list[j] == NULL)
3386 continue;
3387 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3388 if (ret == 0) {
3389 is_indeterminist = 1;
3390 }
3391 }
3392 }
3393 for (i = 0;i < nbchild;i++) {
3394 if (list[i] != NULL)
3395 xmlFree(list[i]);
3396 }
3397
3398 xmlFree(list);
3399 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003400 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003401 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003402 if (is_triable == 1) {
3403 def->dflags |= IS_TRIABLE;
3404 def->data = triage;
3405 } else if (triage != NULL) {
3406 xmlHashFree(triage, NULL);
3407 }
3408 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003409}
3410
3411/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003412 * xmlRelaxNGCheckGroupAttrs:
3413 * @ctxt: a Relax-NG parser context
3414 * @def: the group definition
3415 *
3416 * Detects violations of rule 7.3
3417 */
3418static void
3419xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3420 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003421 xmlRelaxNGDefinePtr **list;
3422 xmlRelaxNGDefinePtr cur;
3423 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003424
3425 if ((def == NULL) ||
3426 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003427 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003428 return;
3429
Daniel Veillarde063f482003-03-21 16:53:17 +00003430 if (def->dflags & IS_PROCESSED)
3431 return;
3432
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003433 /*
3434 * Don't run that check in case of error. Infinite recursion
3435 * becomes possible.
3436 */
3437 if (ctxt->nbErrors != 0)
3438 return;
3439
Daniel Veillardfd573f12003-03-16 17:52:32 +00003440 cur = def->attrs;
3441 while (cur != NULL) {
3442 nbchild++;
3443 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003444 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003445 cur = def->content;
3446 while (cur != NULL) {
3447 nbchild++;
3448 cur = cur->next;
3449 }
3450
3451 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3452 sizeof(xmlRelaxNGDefinePtr *));
3453 if (list == NULL) {
3454 if (ctxt->error != NULL)
3455 ctxt->error(ctxt->userData,
3456 "Out of memory in group computation\n");
3457 ctxt->nbErrors++;
3458 return;
3459 }
3460 i = 0;
3461 cur = def->attrs;
3462 while (cur != NULL) {
3463 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3464 i++;
3465 cur = cur->next;
3466 }
3467 cur = def->content;
3468 while (cur != NULL) {
3469 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3470 i++;
3471 cur = cur->next;
3472 }
3473
3474 for (i = 0;i < nbchild;i++) {
3475 if (list[i] == NULL)
3476 continue;
3477 for (j = 0;j < i;j++) {
3478 if (list[j] == NULL)
3479 continue;
3480 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3481 if (ret == 0) {
3482 if (ctxt->error != NULL)
3483 ctxt->error(ctxt->userData,
3484 "Attributes conflicts in group\n");
3485 ctxt->nbErrors++;
3486 }
3487 }
3488 }
3489 for (i = 0;i < nbchild;i++) {
3490 if (list[i] != NULL)
3491 xmlFree(list[i]);
3492 }
3493
3494 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003495 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003496}
3497
3498/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003499 * xmlRelaxNGComputeInterleaves:
3500 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003501 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003502 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003503 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003504 * A lot of work for preprocessing interleave definitions
3505 * is potentially needed to get a decent execution speed at runtime
3506 * - trying to get a total order on the element nodes generated
3507 * by the interleaves, order the list of interleave definitions
3508 * following that order.
3509 * - if <text/> is used to handle mixed content, it is better to
3510 * flag this in the define and simplify the runtime checking
3511 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003512 */
3513static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003514xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3515 xmlRelaxNGParserCtxtPtr ctxt,
3516 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003517 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003518
Daniel Veillardfd573f12003-03-16 17:52:32 +00003519 xmlRelaxNGPartitionPtr partitions = NULL;
3520 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3521 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003522 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003523 int nbgroups = 0;
3524 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003525 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003526 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003527
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003528 /*
3529 * Don't run that check in case of error. Infinite recursion
3530 * becomes possible.
3531 */
3532 if (ctxt->nbErrors != 0)
3533 return;
3534
Daniel Veillardfd573f12003-03-16 17:52:32 +00003535#ifdef DEBUG_INTERLEAVE
3536 xmlGenericError(xmlGenericErrorContext,
3537 "xmlRelaxNGComputeInterleaves(%s)\n",
3538 name);
3539#endif
3540 cur = def->content;
3541 while (cur != NULL) {
3542 nbchild++;
3543 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003544 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003545
3546#ifdef DEBUG_INTERLEAVE
3547 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3548#endif
3549 groups = (xmlRelaxNGInterleaveGroupPtr *)
3550 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3551 if (groups == NULL)
3552 goto error;
3553 cur = def->content;
3554 while (cur != NULL) {
3555 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3556 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3557 if (groups[nbgroups] == NULL)
3558 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003559 if (cur->type == XML_RELAXNG_TEXT)
3560 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003561 groups[nbgroups]->rule = cur;
3562 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3563 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3564 nbgroups++;
3565 cur = cur->next;
3566 }
3567#ifdef DEBUG_INTERLEAVE
3568 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3569#endif
3570
3571 /*
3572 * Let's check that all rules makes a partitions according to 7.4
3573 */
3574 partitions = (xmlRelaxNGPartitionPtr)
3575 xmlMalloc(sizeof(xmlRelaxNGPartition));
3576 if (partitions == NULL)
3577 goto error;
3578 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003579 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003580 for (i = 0;i < nbgroups;i++) {
3581 group = groups[i];
3582 for (j = i+1;j < nbgroups;j++) {
3583 if (groups[j] == NULL)
3584 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003585
Daniel Veillardfd573f12003-03-16 17:52:32 +00003586 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3587 groups[j]->defs);
3588 if (ret == 0) {
3589 if (ctxt->error != NULL)
3590 ctxt->error(ctxt->userData,
3591 "Element or text conflicts in interleave\n");
3592 ctxt->nbErrors++;
3593 }
3594 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3595 groups[j]->attrs);
3596 if (ret == 0) {
3597 if (ctxt->error != NULL)
3598 ctxt->error(ctxt->userData,
3599 "Attributes conflicts in interleave\n");
3600 ctxt->nbErrors++;
3601 }
3602 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003603 tmp = group->defs;
3604 if ((tmp != NULL) && (*tmp != NULL)) {
3605 while (*tmp != NULL) {
3606 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3607 res = xmlHashAddEntry2(partitions->triage,
3608 BAD_CAST "#text", NULL,
3609 (void *)(i + 1));
3610 if (res != 0)
3611 is_determinist = -1;
3612 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3613 ((*tmp)->name != NULL)) {
3614 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3615 res = xmlHashAddEntry2(partitions->triage,
3616 (*tmp)->name, NULL,
3617 (void *)(i + 1));
3618 else
3619 res = xmlHashAddEntry2(partitions->triage,
3620 (*tmp)->name, (*tmp)->ns,
3621 (void *)(i + 1));
3622 if (res != 0)
3623 is_determinist = -1;
3624 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3625 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3626 res = xmlHashAddEntry2(partitions->triage,
3627 BAD_CAST "#any", NULL,
3628 (void *)(i + 1));
3629 else
3630 res = xmlHashAddEntry2(partitions->triage,
3631 BAD_CAST "#any", (*tmp)->ns,
3632 (void *)(i + 1));
3633 if ((*tmp)->nameClass != NULL)
3634 is_determinist = 2;
3635 if (res != 0)
3636 is_determinist = -1;
3637 } else {
3638 is_determinist = -1;
3639 }
3640 tmp++;
3641 }
3642 } else {
3643 is_determinist = 0;
3644 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003645 }
3646 partitions->groups = groups;
3647
3648 /*
3649 * and save the partition list back in the def
3650 */
3651 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003652 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003653 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003654 if (is_determinist == 1)
3655 partitions->flags = IS_DETERMINIST;
3656 if (is_determinist == 2)
3657 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003658 return;
3659
3660error:
3661 if (ctxt->error != NULL)
3662 ctxt->error(ctxt->userData,
3663 "Out of memory in interleave computation\n");
3664 ctxt->nbErrors++;
3665 if (groups != NULL) {
3666 for (i = 0;i < nbgroups;i++)
3667 if (groups[i] != NULL) {
3668 if (groups[i]->defs != NULL)
3669 xmlFree(groups[i]->defs);
3670 xmlFree(groups[i]);
3671 }
3672 xmlFree(groups);
3673 }
3674 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003675}
3676
3677/**
3678 * xmlRelaxNGParseInterleave:
3679 * @ctxt: a Relax-NG parser context
3680 * @node: the data node.
3681 *
3682 * parse the content of a RelaxNG interleave node.
3683 *
3684 * Returns the definition pointer or NULL in case of error
3685 */
3686static xmlRelaxNGDefinePtr
3687xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3688 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003689 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003690 xmlNodePtr child;
3691
Daniel Veillardfd573f12003-03-16 17:52:32 +00003692 def = xmlRelaxNGNewDefine(ctxt, node);
3693 if (def == NULL) {
3694 return(NULL);
3695 }
3696 def->type = XML_RELAXNG_INTERLEAVE;
3697
3698 if (ctxt->interleaves == NULL)
3699 ctxt->interleaves = xmlHashCreate(10);
3700 if (ctxt->interleaves == NULL) {
3701 if (ctxt->error != NULL)
3702 ctxt->error(ctxt->userData,
3703 "Failed to create interleaves hash table\n");
3704 ctxt->nbErrors++;
3705 } else {
3706 char name[32];
3707
3708 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3709 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3710 if (ctxt->error != NULL)
3711 ctxt->error(ctxt->userData,
3712 "Failed to add %s to hash table\n", name);
3713 ctxt->nbErrors++;
3714 }
3715 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003716 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003717 if (child == NULL) {
3718 if (ctxt->error != NULL)
3719 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3720 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003721 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003722 while (child != NULL) {
3723 if (IS_RELAXNG(child, "element")) {
3724 cur = xmlRelaxNGParseElement(ctxt, child);
3725 } else {
3726 cur = xmlRelaxNGParsePattern(ctxt, child);
3727 }
3728 if (cur != NULL) {
3729 cur->parent = def;
3730 if (last == NULL) {
3731 def->content = last = cur;
3732 } else {
3733 last->next = cur;
3734 last = cur;
3735 }
3736 }
3737 child = child->next;
3738 }
3739
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003740 return(def);
3741}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003742
3743/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003744 * xmlRelaxNGParseInclude:
3745 * @ctxt: a Relax-NG parser context
3746 * @node: the include node
3747 *
3748 * Integrate the content of an include node in the current grammar
3749 *
3750 * Returns 0 in case of success or -1 in case of error
3751 */
3752static int
3753xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3754 xmlRelaxNGIncludePtr incl;
3755 xmlNodePtr root;
3756 int ret = 0, tmp;
3757
3758 incl = node->_private;
3759 if (incl == NULL) {
3760 if (ctxt->error != NULL)
3761 ctxt->error(ctxt->userData,
3762 "Include node has no data\n");
3763 ctxt->nbErrors++;
3764 return(-1);
3765 }
3766 root = xmlDocGetRootElement(incl->doc);
3767 if (root == NULL) {
3768 if (ctxt->error != NULL)
3769 ctxt->error(ctxt->userData,
3770 "Include document is empty\n");
3771 ctxt->nbErrors++;
3772 return(-1);
3773 }
3774 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3775 if (ctxt->error != NULL)
3776 ctxt->error(ctxt->userData,
3777 "Include document root is not a grammar\n");
3778 ctxt->nbErrors++;
3779 return(-1);
3780 }
3781
3782 /*
3783 * Merge the definition from both the include and the internal list
3784 */
3785 if (root->children != NULL) {
3786 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3787 if (tmp != 0)
3788 ret = -1;
3789 }
3790 if (node->children != NULL) {
3791 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3792 if (tmp != 0)
3793 ret = -1;
3794 }
3795 return(ret);
3796}
3797
3798/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003799 * xmlRelaxNGParseDefine:
3800 * @ctxt: a Relax-NG parser context
3801 * @node: the define node
3802 *
3803 * parse the content of a RelaxNG define element node.
3804 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003805 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003806 */
3807static int
3808xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3809 xmlChar *name;
3810 int ret = 0, tmp;
3811 xmlRelaxNGDefinePtr def;
3812 const xmlChar *olddefine;
3813
3814 name = xmlGetProp(node, BAD_CAST "name");
3815 if (name == NULL) {
3816 if (ctxt->error != NULL)
3817 ctxt->error(ctxt->userData,
3818 "define has no name\n");
3819 ctxt->nbErrors++;
3820 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003821 xmlRelaxNGNormExtSpace(name);
3822 if (xmlValidateNCName(name, 0)) {
3823 if (ctxt->error != NULL)
3824 ctxt->error(ctxt->userData,
3825 "define name '%s' is not an NCName\n",
3826 name);
3827 ctxt->nbErrors++;
3828 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003829 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003830 if (def == NULL) {
3831 xmlFree(name);
3832 return(-1);
3833 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003834 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003835 def->name = name;
3836 if (node->children == NULL) {
3837 if (ctxt->error != NULL)
3838 ctxt->error(ctxt->userData,
3839 "define has no children\n");
3840 ctxt->nbErrors++;
3841 } else {
3842 olddefine = ctxt->define;
3843 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003844 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003845 ctxt->define = olddefine;
3846 }
3847 if (ctxt->grammar->defs == NULL)
3848 ctxt->grammar->defs = xmlHashCreate(10);
3849 if (ctxt->grammar->defs == NULL) {
3850 if (ctxt->error != NULL)
3851 ctxt->error(ctxt->userData,
3852 "Could not create definition hash\n");
3853 ctxt->nbErrors++;
3854 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003855 } else {
3856 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3857 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003858 xmlRelaxNGDefinePtr prev;
3859
3860 prev = xmlHashLookup(ctxt->grammar->defs, name);
3861 if (prev == NULL) {
3862 if (ctxt->error != NULL)
3863 ctxt->error(ctxt->userData,
3864 "Internal error on define aggregation of %s\n",
3865 name);
3866 ctxt->nbErrors++;
3867 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003868 } else {
3869 while (prev->nextHash != NULL)
3870 prev = prev->nextHash;
3871 prev->nextHash = def;
3872 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003873 }
3874 }
3875 }
3876 return(ret);
3877}
3878
3879/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003880 * xmlRelaxNGProcessExternalRef:
3881 * @ctxt: the parser context
3882 * @node: the externlRef node
3883 *
3884 * Process and compile an externlRef node
3885 *
3886 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3887 */
3888static xmlRelaxNGDefinePtr
3889xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3890 xmlRelaxNGDocumentPtr docu;
3891 xmlNodePtr root, tmp;
3892 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003893 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003894 xmlRelaxNGDefinePtr def;
3895
3896 docu = node->_private;
3897 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003898 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003899 if (def == NULL)
3900 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003901 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003902
3903 if (docu->content == NULL) {
3904 /*
3905 * Then do the parsing for good
3906 */
3907 root = xmlDocGetRootElement(docu->doc);
3908 if (root == NULL) {
3909 if (ctxt->error != NULL)
3910 ctxt->error(ctxt->userData,
3911 "xmlRelaxNGParse: %s is empty\n",
3912 ctxt->URL);
3913 ctxt->nbErrors++;
3914 return (NULL);
3915 }
3916 /*
3917 * ns transmission rules
3918 */
3919 ns = xmlGetProp(root, BAD_CAST "ns");
3920 if (ns == NULL) {
3921 tmp = node;
3922 while ((tmp != NULL) &&
3923 (tmp->type == XML_ELEMENT_NODE)) {
3924 ns = xmlGetProp(tmp, BAD_CAST "ns");
3925 if (ns != NULL) {
3926 break;
3927 }
3928 tmp = tmp->parent;
3929 }
3930 if (ns != NULL) {
3931 xmlSetProp(root, BAD_CAST "ns", ns);
3932 newNs = 1;
3933 xmlFree(ns);
3934 }
3935 } else {
3936 xmlFree(ns);
3937 }
3938
3939 /*
3940 * Parsing to get a precompiled schemas.
3941 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003942 oldflags = ctxt->flags;
3943 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003944 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003945 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003946 if ((docu->schema != NULL) &&
3947 (docu->schema->topgrammar != NULL)) {
3948 docu->content = docu->schema->topgrammar->start;
3949 }
3950
3951 /*
3952 * the externalRef may be reused in a different ns context
3953 */
3954 if (newNs == 1) {
3955 xmlUnsetProp(root, BAD_CAST "ns");
3956 }
3957 }
3958 def->content = docu->content;
3959 } else {
3960 def = NULL;
3961 }
3962 return(def);
3963}
3964
3965/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003966 * xmlRelaxNGParsePattern:
3967 * @ctxt: a Relax-NG parser context
3968 * @node: the pattern node.
3969 *
3970 * parse the content of a RelaxNG pattern node.
3971 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003972 * Returns the definition pointer or NULL in case of error or if no
3973 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003974 */
3975static xmlRelaxNGDefinePtr
3976xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3977 xmlRelaxNGDefinePtr def = NULL;
3978
Daniel Veillardd2298792003-02-14 16:54:11 +00003979 if (node == NULL) {
3980 return(NULL);
3981 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003982 if (IS_RELAXNG(node, "element")) {
3983 def = xmlRelaxNGParseElement(ctxt, node);
3984 } else if (IS_RELAXNG(node, "attribute")) {
3985 def = xmlRelaxNGParseAttribute(ctxt, node);
3986 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003987 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003988 if (def == NULL)
3989 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003990 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00003991 if (node->children != NULL) {
3992 if (ctxt->error != NULL)
3993 ctxt->error(ctxt->userData, "empty: had a child node\n");
3994 ctxt->nbErrors++;
3995 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003996 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003997 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003998 if (def == NULL)
3999 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004000 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004001 if (node->children != NULL) {
4002 if (ctxt->error != NULL)
4003 ctxt->error(ctxt->userData, "text: had a child node\n");
4004 ctxt->nbErrors++;
4005 }
4006 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004007 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004008 if (def == NULL)
4009 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004010 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004011 if (node->children == NULL) {
4012 if (ctxt->error != NULL)
4013 ctxt->error(ctxt->userData,
4014 "Element %s is empty\n", node->name);
4015 ctxt->nbErrors++;
4016 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004017 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004018 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004019 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004020 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004021 if (def == NULL)
4022 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004023 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004024 if (node->children == NULL) {
4025 if (ctxt->error != NULL)
4026 ctxt->error(ctxt->userData,
4027 "Element %s is empty\n", node->name);
4028 ctxt->nbErrors++;
4029 } else {
4030 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4031 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004032 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004033 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004034 if (def == NULL)
4035 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004036 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004037 if (node->children == NULL) {
4038 if (ctxt->error != NULL)
4039 ctxt->error(ctxt->userData,
4040 "Element %s is empty\n", node->name);
4041 ctxt->nbErrors++;
4042 } else {
4043 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4044 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004045 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004046 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004047 if (def == NULL)
4048 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004049 def->type = XML_RELAXNG_CHOICE;
4050 if (node->children == NULL) {
4051 if (ctxt->error != NULL)
4052 ctxt->error(ctxt->userData,
4053 "Element %s is empty\n", node->name);
4054 ctxt->nbErrors++;
4055 } else {
4056 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4057 }
4058 } else if (IS_RELAXNG(node, "group")) {
4059 def = xmlRelaxNGNewDefine(ctxt, node);
4060 if (def == NULL)
4061 return(NULL);
4062 def->type = XML_RELAXNG_GROUP;
4063 if (node->children == NULL) {
4064 if (ctxt->error != NULL)
4065 ctxt->error(ctxt->userData,
4066 "Element %s is empty\n", node->name);
4067 ctxt->nbErrors++;
4068 } else {
4069 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4070 }
4071 } else if (IS_RELAXNG(node, "ref")) {
4072 def = xmlRelaxNGNewDefine(ctxt, node);
4073 if (def == NULL)
4074 return(NULL);
4075 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004076 def->name = xmlGetProp(node, BAD_CAST "name");
4077 if (def->name == NULL) {
4078 if (ctxt->error != NULL)
4079 ctxt->error(ctxt->userData,
4080 "ref has no name\n");
4081 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004082 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004083 xmlRelaxNGNormExtSpace(def->name);
4084 if (xmlValidateNCName(def->name, 0)) {
4085 if (ctxt->error != NULL)
4086 ctxt->error(ctxt->userData,
4087 "ref name '%s' is not an NCName\n",
4088 def->name);
4089 ctxt->nbErrors++;
4090 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004091 }
4092 if (node->children != NULL) {
4093 if (ctxt->error != NULL)
4094 ctxt->error(ctxt->userData,
4095 "ref is not empty\n");
4096 ctxt->nbErrors++;
4097 }
4098 if (ctxt->grammar->refs == NULL)
4099 ctxt->grammar->refs = xmlHashCreate(10);
4100 if (ctxt->grammar->refs == NULL) {
4101 if (ctxt->error != NULL)
4102 ctxt->error(ctxt->userData,
4103 "Could not create references hash\n");
4104 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004105 def = NULL;
4106 } else {
4107 int tmp;
4108
4109 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4110 if (tmp < 0) {
4111 xmlRelaxNGDefinePtr prev;
4112
4113 prev = (xmlRelaxNGDefinePtr)
4114 xmlHashLookup(ctxt->grammar->refs, def->name);
4115 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004116 if (def->name != NULL) {
4117 if (ctxt->error != NULL)
4118 ctxt->error(ctxt->userData,
4119 "Error refs definitions '%s'\n",
4120 def->name);
4121 } else {
4122 if (ctxt->error != NULL)
4123 ctxt->error(ctxt->userData,
4124 "Error refs definitions\n");
4125 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004126 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004127 def = NULL;
4128 } else {
4129 def->nextHash = prev->nextHash;
4130 prev->nextHash = def;
4131 }
4132 }
4133 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004134 } else if (IS_RELAXNG(node, "data")) {
4135 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004136 } else if (IS_RELAXNG(node, "value")) {
4137 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004138 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004139 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004140 if (def == NULL)
4141 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004142 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004143 if (node->children == NULL) {
4144 if (ctxt->error != NULL)
4145 ctxt->error(ctxt->userData,
4146 "Element %s is empty\n", node->name);
4147 ctxt->nbErrors++;
4148 } else {
4149 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4150 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004151 } else if (IS_RELAXNG(node, "interleave")) {
4152 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004153 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004154 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004155 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004156 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004157 if (def == NULL)
4158 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004159 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004160 if (node->children != NULL) {
4161 if (ctxt->error != NULL)
4162 ctxt->error(ctxt->userData,
4163 "xmlRelaxNGParse: notAllowed element is not empty\n");
4164 ctxt->nbErrors++;
4165 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004166 } else if (IS_RELAXNG(node, "grammar")) {
4167 xmlRelaxNGGrammarPtr grammar, old;
4168 xmlRelaxNGGrammarPtr oldparent;
4169
Daniel Veillardc482e262003-02-26 14:48:48 +00004170#ifdef DEBUG_GRAMMAR
4171 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4172#endif
4173
Daniel Veillard419a7682003-02-03 23:22:49 +00004174 oldparent = ctxt->parentgrammar;
4175 old = ctxt->grammar;
4176 ctxt->parentgrammar = old;
4177 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4178 if (old != NULL) {
4179 ctxt->grammar = old;
4180 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004181#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004182 if (grammar != NULL) {
4183 grammar->next = old->next;
4184 old->next = grammar;
4185 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004186#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004187 }
4188 if (grammar != NULL)
4189 def = grammar->start;
4190 else
4191 def = NULL;
4192 } else if (IS_RELAXNG(node, "parentRef")) {
4193 if (ctxt->parentgrammar == NULL) {
4194 if (ctxt->error != NULL)
4195 ctxt->error(ctxt->userData,
4196 "Use of parentRef without a parent grammar\n");
4197 ctxt->nbErrors++;
4198 return(NULL);
4199 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004200 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004201 if (def == NULL)
4202 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004203 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004204 def->name = xmlGetProp(node, BAD_CAST "name");
4205 if (def->name == NULL) {
4206 if (ctxt->error != NULL)
4207 ctxt->error(ctxt->userData,
4208 "parentRef has no name\n");
4209 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004210 } else {
4211 xmlRelaxNGNormExtSpace(def->name);
4212 if (xmlValidateNCName(def->name, 0)) {
4213 if (ctxt->error != NULL)
4214 ctxt->error(ctxt->userData,
4215 "parentRef name '%s' is not an NCName\n",
4216 def->name);
4217 ctxt->nbErrors++;
4218 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004219 }
4220 if (node->children != NULL) {
4221 if (ctxt->error != NULL)
4222 ctxt->error(ctxt->userData,
4223 "parentRef is not empty\n");
4224 ctxt->nbErrors++;
4225 }
4226 if (ctxt->parentgrammar->refs == NULL)
4227 ctxt->parentgrammar->refs = xmlHashCreate(10);
4228 if (ctxt->parentgrammar->refs == NULL) {
4229 if (ctxt->error != NULL)
4230 ctxt->error(ctxt->userData,
4231 "Could not create references hash\n");
4232 ctxt->nbErrors++;
4233 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004234 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004235 int tmp;
4236
4237 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4238 if (tmp < 0) {
4239 xmlRelaxNGDefinePtr prev;
4240
4241 prev = (xmlRelaxNGDefinePtr)
4242 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4243 if (prev == NULL) {
4244 if (ctxt->error != NULL)
4245 ctxt->error(ctxt->userData,
4246 "Internal error parentRef definitions '%s'\n",
4247 def->name);
4248 ctxt->nbErrors++;
4249 def = NULL;
4250 } else {
4251 def->nextHash = prev->nextHash;
4252 prev->nextHash = def;
4253 }
4254 }
4255 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004256 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004257 if (node->children == NULL) {
4258 if (ctxt->error != NULL)
4259 ctxt->error(ctxt->userData,
4260 "Mixed is empty\n");
4261 ctxt->nbErrors++;
4262 def = NULL;
4263 } else {
4264 def = xmlRelaxNGParseInterleave(ctxt, node);
4265 if (def != NULL) {
4266 xmlRelaxNGDefinePtr tmp;
4267
4268 if ((def->content != NULL) && (def->content->next != NULL)) {
4269 tmp = xmlRelaxNGNewDefine(ctxt, node);
4270 if (tmp != NULL) {
4271 tmp->type = XML_RELAXNG_GROUP;
4272 tmp->content = def->content;
4273 def->content = tmp;
4274 }
4275 }
4276
4277 tmp = xmlRelaxNGNewDefine(ctxt, node);
4278 if (tmp == NULL)
4279 return(def);
4280 tmp->type = XML_RELAXNG_TEXT;
4281 tmp->next = def->content;
4282 def->content = tmp;
4283 }
4284 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004285 } else {
4286 if (ctxt->error != NULL)
4287 ctxt->error(ctxt->userData,
4288 "Unexpected node %s is not a pattern\n",
4289 node->name);
4290 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004291 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004292 }
4293 return(def);
4294}
4295
4296/**
4297 * xmlRelaxNGParseAttribute:
4298 * @ctxt: a Relax-NG parser context
4299 * @node: the element node
4300 *
4301 * parse the content of a RelaxNG attribute node.
4302 *
4303 * Returns the definition pointer or NULL in case of error.
4304 */
4305static xmlRelaxNGDefinePtr
4306xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004307 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004308 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004309 int old_flags;
4310
Daniel Veillardfd573f12003-03-16 17:52:32 +00004311 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004312 if (ret == NULL)
4313 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004314 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004315 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004316 child = node->children;
4317 if (child == NULL) {
4318 if (ctxt->error != NULL)
4319 ctxt->error(ctxt->userData,
4320 "xmlRelaxNGParseattribute: attribute has no children\n");
4321 ctxt->nbErrors++;
4322 return(ret);
4323 }
4324 old_flags = ctxt->flags;
4325 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004326 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4327 if (cur != NULL)
4328 child = child->next;
4329
Daniel Veillardd2298792003-02-14 16:54:11 +00004330 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004331 cur = xmlRelaxNGParsePattern(ctxt, child);
4332 if (cur != NULL) {
4333 switch (cur->type) {
4334 case XML_RELAXNG_EMPTY:
4335 case XML_RELAXNG_NOT_ALLOWED:
4336 case XML_RELAXNG_TEXT:
4337 case XML_RELAXNG_ELEMENT:
4338 case XML_RELAXNG_DATATYPE:
4339 case XML_RELAXNG_VALUE:
4340 case XML_RELAXNG_LIST:
4341 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004342 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004343 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004344 case XML_RELAXNG_DEF:
4345 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004346 case XML_RELAXNG_ZEROORMORE:
4347 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004348 case XML_RELAXNG_CHOICE:
4349 case XML_RELAXNG_GROUP:
4350 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004351 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004352 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004353 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004354 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004355 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004356 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004357 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004358 if (ctxt->error != NULL)
4359 ctxt->error(ctxt->userData,
4360 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004361 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004362 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004363 case XML_RELAXNG_NOOP:
4364 TODO
4365 if (ctxt->error != NULL)
4366 ctxt->error(ctxt->userData,
4367 "Internal error, noop found\n");
4368 ctxt->nbErrors++;
4369 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004370 }
4371 }
4372 child = child->next;
4373 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004374 if (child != NULL) {
4375 if (ctxt->error != NULL)
4376 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4377 ctxt->nbErrors++;
4378 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004379 ctxt->flags = old_flags;
4380 return(ret);
4381}
4382
4383/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004384 * xmlRelaxNGParseExceptNameClass:
4385 * @ctxt: a Relax-NG parser context
4386 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004387 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004388 *
4389 * parse the content of a RelaxNG nameClass node.
4390 *
4391 * Returns the definition pointer or NULL in case of error.
4392 */
4393static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004394xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4395 xmlNodePtr node, int attr) {
4396 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4397 xmlNodePtr child;
4398
Daniel Veillardd2298792003-02-14 16:54:11 +00004399 if (!IS_RELAXNG(node, "except")) {
4400 if (ctxt->error != NULL)
4401 ctxt->error(ctxt->userData,
4402 "Expecting an except node\n");
4403 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004404 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004405 }
4406 if (node->next != NULL) {
4407 if (ctxt->error != NULL)
4408 ctxt->error(ctxt->userData,
4409 "exceptNameClass allows only a single except node\n");
4410 ctxt->nbErrors++;
4411 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004412 if (node->children == NULL) {
4413 if (ctxt->error != NULL)
4414 ctxt->error(ctxt->userData,
4415 "except has no content\n");
4416 ctxt->nbErrors++;
4417 return(NULL);
4418 }
4419
Daniel Veillardfd573f12003-03-16 17:52:32 +00004420 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004421 if (ret == NULL)
4422 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004423 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004424 child = node->children;
4425 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004426 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004427 if (cur == NULL)
4428 break;
4429 if (attr)
4430 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004431 else
4432 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004433
Daniel Veillard419a7682003-02-03 23:22:49 +00004434 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004435 if (last == NULL) {
4436 ret->content = cur;
4437 } else {
4438 last->next = cur;
4439 }
4440 last = cur;
4441 }
4442 child = child->next;
4443 }
4444
4445 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004446}
4447
4448/**
4449 * xmlRelaxNGParseNameClass:
4450 * @ctxt: a Relax-NG parser context
4451 * @node: the nameClass node
4452 * @def: the current definition
4453 *
4454 * parse the content of a RelaxNG nameClass node.
4455 *
4456 * Returns the definition pointer or NULL in case of error.
4457 */
4458static xmlRelaxNGDefinePtr
4459xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4460 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004461 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004462 xmlChar *val;
4463
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004464 ret = def;
4465 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4466 (IS_RELAXNG(node, "nsName"))) {
4467 if ((def->type != XML_RELAXNG_ELEMENT) &&
4468 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004469 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004470 if (ret == NULL)
4471 return(NULL);
4472 ret->parent = def;
4473 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4474 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004475 else
4476 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004477 }
4478 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004479 if (IS_RELAXNG(node, "name")) {
4480 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004481 xmlRelaxNGNormExtSpace(val);
4482 if (xmlValidateNCName(val, 0)) {
4483 if (ctxt->error != NULL) {
4484 if (node->parent != NULL)
4485 ctxt->error(ctxt->userData,
4486 "Element %s name '%s' is not an NCName\n",
4487 node->parent->name, val);
4488 else
4489 ctxt->error(ctxt->userData,
4490 "name '%s' is not an NCName\n",
4491 val);
4492 }
4493 ctxt->nbErrors++;
4494 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004495 ret->name = val;
4496 val = xmlGetProp(node, BAD_CAST "ns");
4497 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004498 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4499 (val != NULL) &&
4500 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4501 ctxt->error(ctxt->userData,
4502 "Attribute with namespace '%s' is not allowed\n",
4503 val);
4504 ctxt->nbErrors++;
4505 }
4506 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4507 (val != NULL) &&
4508 (val[0] == 0) &&
4509 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4510 ctxt->error(ctxt->userData,
4511 "Attribute with QName 'xmlns' is not allowed\n",
4512 val);
4513 ctxt->nbErrors++;
4514 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004515 } else if (IS_RELAXNG(node, "anyName")) {
4516 ret->name = NULL;
4517 ret->ns = NULL;
4518 if (node->children != NULL) {
4519 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004520 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4521 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004522 }
4523 } else if (IS_RELAXNG(node, "nsName")) {
4524 ret->name = NULL;
4525 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4526 if (ret->ns == NULL) {
4527 if (ctxt->error != NULL)
4528 ctxt->error(ctxt->userData,
4529 "nsName has no ns attribute\n");
4530 ctxt->nbErrors++;
4531 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004532 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4533 (ret->ns != NULL) &&
4534 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4535 ctxt->error(ctxt->userData,
4536 "Attribute with namespace '%s' is not allowed\n",
4537 ret->ns);
4538 ctxt->nbErrors++;
4539 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004540 if (node->children != NULL) {
4541 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004542 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4543 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004544 }
4545 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004546 xmlNodePtr child;
4547 xmlRelaxNGDefinePtr last = NULL;
4548
4549 ret = xmlRelaxNGNewDefine(ctxt, node);
4550 if (ret == NULL)
4551 return(NULL);
4552 ret->parent = def;
4553 ret->type = XML_RELAXNG_CHOICE;
4554
Daniel Veillardd2298792003-02-14 16:54:11 +00004555 if (node->children == NULL) {
4556 if (ctxt->error != NULL)
4557 ctxt->error(ctxt->userData,
4558 "Element choice is empty\n");
4559 ctxt->nbErrors++;
4560 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004561
4562 child = node->children;
4563 while (child != NULL) {
4564 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4565 if (tmp != NULL) {
4566 if (last == NULL) {
4567 last = ret->nameClass = tmp;
4568 } else {
4569 last->next = tmp;
4570 last = tmp;
4571 }
4572 }
4573 child = child->next;
4574 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004575 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004576 } else {
4577 if (ctxt->error != NULL)
4578 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004579 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004580 node->name);
4581 ctxt->nbErrors++;
4582 return(NULL);
4583 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004584 if (ret != def) {
4585 if (def->nameClass == NULL) {
4586 def->nameClass = ret;
4587 } else {
4588 tmp = def->nameClass;
4589 while (tmp->next != NULL) {
4590 tmp = tmp->next;
4591 }
4592 tmp->next = ret;
4593 }
4594 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004595 return(ret);
4596}
4597
4598/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004599 * xmlRelaxNGParseElement:
4600 * @ctxt: a Relax-NG parser context
4601 * @node: the element node
4602 *
4603 * parse the content of a RelaxNG element node.
4604 *
4605 * Returns the definition pointer or NULL in case of error.
4606 */
4607static xmlRelaxNGDefinePtr
4608xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4609 xmlRelaxNGDefinePtr ret, cur, last;
4610 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004611 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004612
Daniel Veillardfd573f12003-03-16 17:52:32 +00004613 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004614 if (ret == NULL)
4615 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004616 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004617 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004618 child = node->children;
4619 if (child == NULL) {
4620 if (ctxt->error != NULL)
4621 ctxt->error(ctxt->userData,
4622 "xmlRelaxNGParseElement: element has no children\n");
4623 ctxt->nbErrors++;
4624 return(ret);
4625 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004626 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4627 if (cur != NULL)
4628 child = child->next;
4629
Daniel Veillard6eadf632003-01-23 18:29:16 +00004630 if (child == NULL) {
4631 if (ctxt->error != NULL)
4632 ctxt->error(ctxt->userData,
4633 "xmlRelaxNGParseElement: element has no content\n");
4634 ctxt->nbErrors++;
4635 return(ret);
4636 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004637 olddefine = ctxt->define;
4638 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004639 last = NULL;
4640 while (child != NULL) {
4641 cur = xmlRelaxNGParsePattern(ctxt, child);
4642 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004643 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004644 switch (cur->type) {
4645 case XML_RELAXNG_EMPTY:
4646 case XML_RELAXNG_NOT_ALLOWED:
4647 case XML_RELAXNG_TEXT:
4648 case XML_RELAXNG_ELEMENT:
4649 case XML_RELAXNG_DATATYPE:
4650 case XML_RELAXNG_VALUE:
4651 case XML_RELAXNG_LIST:
4652 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004653 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004654 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004655 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004656 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004657 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004658 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004659 case XML_RELAXNG_CHOICE:
4660 case XML_RELAXNG_GROUP:
4661 case XML_RELAXNG_INTERLEAVE:
4662 if (last == NULL) {
4663 ret->content = last = cur;
4664 } else {
4665 if ((last->type == XML_RELAXNG_ELEMENT) &&
4666 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004667 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004668 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004669 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004670 ret->content->content = last;
4671 } else {
4672 ret->content = last;
4673 }
4674 }
4675 last->next = cur;
4676 last = cur;
4677 }
4678 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004679 case XML_RELAXNG_ATTRIBUTE:
4680 cur->next = ret->attrs;
4681 ret->attrs = cur;
4682 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004683 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004684 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004685 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004686 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004687 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004688 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004689 case XML_RELAXNG_NOOP:
4690 TODO
4691 if (ctxt->error != NULL)
4692 ctxt->error(ctxt->userData,
4693 "Internal error, noop found\n");
4694 ctxt->nbErrors++;
4695 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004696 }
4697 }
4698 child = child->next;
4699 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004700 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004701 return(ret);
4702}
4703
4704/**
4705 * xmlRelaxNGParsePatterns:
4706 * @ctxt: a Relax-NG parser context
4707 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004708 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 *
4710 * parse the content of a RelaxNG start node.
4711 *
4712 * Returns the definition pointer or NULL in case of error.
4713 */
4714static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004715xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4716 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004717 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004718
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004719 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004720 while (nodes != NULL) {
4721 if (IS_RELAXNG(nodes, "element")) {
4722 cur = xmlRelaxNGParseElement(ctxt, nodes);
4723 if (def == NULL) {
4724 def = last = cur;
4725 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004726 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4727 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004728 def = xmlRelaxNGNewDefine(ctxt, nodes);
4729 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004730 def->content = last;
4731 }
4732 last->next = cur;
4733 last = cur;
4734 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004735 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004736 } else {
4737 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004738 if (cur != NULL) {
4739 if (def == NULL) {
4740 def = last = cur;
4741 } else {
4742 last->next = cur;
4743 last = cur;
4744 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004745 }
4746 }
4747 nodes = nodes->next;
4748 }
4749 return(def);
4750}
4751
4752/**
4753 * xmlRelaxNGParseStart:
4754 * @ctxt: a Relax-NG parser context
4755 * @nodes: start children nodes
4756 *
4757 * parse the content of a RelaxNG start node.
4758 *
4759 * Returns 0 in case of success, -1 in case of error
4760 */
4761static int
4762xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4763 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004764 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004765
Daniel Veillardd2298792003-02-14 16:54:11 +00004766 if (nodes == NULL) {
4767 if (ctxt->error != NULL)
4768 ctxt->error(ctxt->userData,
4769 "start has no children\n");
4770 ctxt->nbErrors++;
4771 return(-1);
4772 }
4773 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004774 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004775 if (def == NULL)
4776 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004777 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004778 if (nodes->children != NULL) {
4779 if (ctxt->error != NULL)
4780 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004781 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004782 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004783 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004784 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004785 if (def == NULL)
4786 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004787 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004788 if (nodes->children != NULL) {
4789 if (ctxt->error != NULL)
4790 ctxt->error(ctxt->userData,
4791 "element notAllowed is not empty\n");
4792 ctxt->nbErrors++;
4793 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004794 } else {
4795 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004796 }
4797 if (ctxt->grammar->start != NULL) {
4798 last = ctxt->grammar->start;
4799 while (last->next != NULL)
4800 last = last->next;
4801 last->next = def;
4802 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004803 ctxt->grammar->start = def;
4804 }
4805 nodes = nodes->next;
4806 if (nodes != NULL) {
4807 if (ctxt->error != NULL)
4808 ctxt->error(ctxt->userData,
4809 "start more than one children\n");
4810 ctxt->nbErrors++;
4811 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004812 }
4813 return(ret);
4814}
4815
4816/**
4817 * xmlRelaxNGParseGrammarContent:
4818 * @ctxt: a Relax-NG parser context
4819 * @nodes: grammar children nodes
4820 *
4821 * parse the content of a RelaxNG grammar node.
4822 *
4823 * Returns 0 in case of success, -1 in case of error
4824 */
4825static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004826xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004827{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004828 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004829
4830 if (nodes == NULL) {
4831 if (ctxt->error != NULL)
4832 ctxt->error(ctxt->userData,
4833 "grammar has no children\n");
4834 ctxt->nbErrors++;
4835 return(-1);
4836 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004837 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004838 if (IS_RELAXNG(nodes, "start")) {
4839 if (nodes->children == NULL) {
4840 if (ctxt->error != NULL)
4841 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004842 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004843 ctxt->nbErrors++;
4844 } else {
4845 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4846 if (tmp != 0)
4847 ret = -1;
4848 }
4849 } else if (IS_RELAXNG(nodes, "define")) {
4850 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4851 if (tmp != 0)
4852 ret = -1;
4853 } else if (IS_RELAXNG(nodes, "include")) {
4854 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4855 if (tmp != 0)
4856 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004857 } else {
4858 if (ctxt->error != NULL)
4859 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004860 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004861 ctxt->nbErrors++;
4862 ret = -1;
4863 }
4864 nodes = nodes->next;
4865 }
4866 return (ret);
4867}
4868
4869/**
4870 * xmlRelaxNGCheckReference:
4871 * @ref: the ref
4872 * @ctxt: a Relax-NG parser context
4873 * @name: the name associated to the defines
4874 *
4875 * Applies the 4.17. combine attribute rule for all the define
4876 * element of a given grammar using the same name.
4877 */
4878static void
4879xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4880 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4881 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004882 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004883
4884 grammar = ctxt->grammar;
4885 if (grammar == NULL) {
4886 if (ctxt->error != NULL)
4887 ctxt->error(ctxt->userData,
4888 "Internal error: no grammar in CheckReference %s\n",
4889 name);
4890 ctxt->nbErrors++;
4891 return;
4892 }
4893 if (ref->content != NULL) {
4894 if (ctxt->error != NULL)
4895 ctxt->error(ctxt->userData,
4896 "Internal error: reference has content in CheckReference %s\n",
4897 name);
4898 ctxt->nbErrors++;
4899 return;
4900 }
4901 if (grammar->defs != NULL) {
4902 def = xmlHashLookup(grammar->defs, name);
4903 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004904 cur = ref;
4905 while (cur != NULL) {
4906 cur->content = def;
4907 cur = cur->nextHash;
4908 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004909 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004910 if (ctxt->error != NULL)
4911 ctxt->error(ctxt->userData,
4912 "Reference %s has no matching definition\n",
4913 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004914 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004915 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004916 } else {
4917 if (ctxt->error != NULL)
4918 ctxt->error(ctxt->userData,
4919 "Reference %s has no matching definition\n",
4920 name);
4921 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004922 }
4923 /*
4924 * TODO: make a closure and verify there is no loop !
4925 */
4926}
4927
4928/**
4929 * xmlRelaxNGCheckCombine:
4930 * @define: the define(s) list
4931 * @ctxt: a Relax-NG parser context
4932 * @name: the name associated to the defines
4933 *
4934 * Applies the 4.17. combine attribute rule for all the define
4935 * element of a given grammar using the same name.
4936 */
4937static void
4938xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4939 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4940 xmlChar *combine;
4941 int choiceOrInterleave = -1;
4942 int missing = 0;
4943 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4944
4945 if (define->nextHash == NULL)
4946 return;
4947 cur = define;
4948 while (cur != NULL) {
4949 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4950 if (combine != NULL) {
4951 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4952 if (choiceOrInterleave == -1)
4953 choiceOrInterleave = 1;
4954 else if (choiceOrInterleave == 0) {
4955 if (ctxt->error != NULL)
4956 ctxt->error(ctxt->userData,
4957 "Defines for %s use both 'choice' and 'interleave'\n",
4958 name);
4959 ctxt->nbErrors++;
4960 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004961 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004962 if (choiceOrInterleave == -1)
4963 choiceOrInterleave = 0;
4964 else if (choiceOrInterleave == 1) {
4965 if (ctxt->error != NULL)
4966 ctxt->error(ctxt->userData,
4967 "Defines for %s use both 'choice' and 'interleave'\n",
4968 name);
4969 ctxt->nbErrors++;
4970 }
4971 } else {
4972 if (ctxt->error != NULL)
4973 ctxt->error(ctxt->userData,
4974 "Defines for %s use unknown combine value '%s''\n",
4975 name, combine);
4976 ctxt->nbErrors++;
4977 }
4978 xmlFree(combine);
4979 } else {
4980 if (missing == 0)
4981 missing = 1;
4982 else {
4983 if (ctxt->error != NULL)
4984 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004985 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004986 name);
4987 ctxt->nbErrors++;
4988 }
4989 }
4990
4991 cur = cur->nextHash;
4992 }
4993#ifdef DEBUG
4994 xmlGenericError(xmlGenericErrorContext,
4995 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
4996 name, choiceOrInterleave);
4997#endif
4998 if (choiceOrInterleave == -1)
4999 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005000 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005001 if (cur == NULL)
5002 return;
5003 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005004 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005005 else
5006 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005007 tmp = define;
5008 last = NULL;
5009 while (tmp != NULL) {
5010 if (tmp->content != NULL) {
5011 if (tmp->content->next != NULL) {
5012 /*
5013 * we need first to create a wrapper.
5014 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005015 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005016 if (tmp2 == NULL)
5017 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005018 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005019 tmp2->content = tmp->content;
5020 } else {
5021 tmp2 = tmp->content;
5022 }
5023 if (last == NULL) {
5024 cur->content = tmp2;
5025 } else {
5026 last->next = tmp2;
5027 }
5028 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005029 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005030 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005031 tmp = tmp->nextHash;
5032 }
5033 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005034 if (choiceOrInterleave == 0) {
5035 if (ctxt->interleaves == NULL)
5036 ctxt->interleaves = xmlHashCreate(10);
5037 if (ctxt->interleaves == NULL) {
5038 if (ctxt->error != NULL)
5039 ctxt->error(ctxt->userData,
5040 "Failed to create interleaves hash table\n");
5041 ctxt->nbErrors++;
5042 } else {
5043 char tmpname[32];
5044
5045 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5046 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5047 if (ctxt->error != NULL)
5048 ctxt->error(ctxt->userData,
5049 "Failed to add %s to hash table\n", tmpname);
5050 ctxt->nbErrors++;
5051 }
5052 }
5053 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005054}
5055
5056/**
5057 * xmlRelaxNGCombineStart:
5058 * @ctxt: a Relax-NG parser context
5059 * @grammar: the grammar
5060 *
5061 * Applies the 4.17. combine rule for all the start
5062 * element of a given grammar.
5063 */
5064static void
5065xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5066 xmlRelaxNGGrammarPtr grammar) {
5067 xmlRelaxNGDefinePtr starts;
5068 xmlChar *combine;
5069 int choiceOrInterleave = -1;
5070 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005071 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005072
Daniel Veillard2df2de22003-02-17 23:34:33 +00005073 starts = grammar->start;
5074 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005075 return;
5076 cur = starts;
5077 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005078 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5079 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5080 combine = NULL;
5081 if (ctxt->error != NULL)
5082 ctxt->error(ctxt->userData,
5083 "Internal error: start element not found\n");
5084 ctxt->nbErrors++;
5085 } else {
5086 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5087 }
5088
Daniel Veillard6eadf632003-01-23 18:29:16 +00005089 if (combine != NULL) {
5090 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5091 if (choiceOrInterleave == -1)
5092 choiceOrInterleave = 1;
5093 else if (choiceOrInterleave == 0) {
5094 if (ctxt->error != NULL)
5095 ctxt->error(ctxt->userData,
5096 "<start> use both 'choice' and 'interleave'\n");
5097 ctxt->nbErrors++;
5098 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005099 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005100 if (choiceOrInterleave == -1)
5101 choiceOrInterleave = 0;
5102 else if (choiceOrInterleave == 1) {
5103 if (ctxt->error != NULL)
5104 ctxt->error(ctxt->userData,
5105 "<start> use both 'choice' and 'interleave'\n");
5106 ctxt->nbErrors++;
5107 }
5108 } else {
5109 if (ctxt->error != NULL)
5110 ctxt->error(ctxt->userData,
5111 "<start> uses unknown combine value '%s''\n", combine);
5112 ctxt->nbErrors++;
5113 }
5114 xmlFree(combine);
5115 } else {
5116 if (missing == 0)
5117 missing = 1;
5118 else {
5119 if (ctxt->error != NULL)
5120 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005121 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005122 ctxt->nbErrors++;
5123 }
5124 }
5125
Daniel Veillard2df2de22003-02-17 23:34:33 +00005126 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005127 }
5128#ifdef DEBUG
5129 xmlGenericError(xmlGenericErrorContext,
5130 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5131 choiceOrInterleave);
5132#endif
5133 if (choiceOrInterleave == -1)
5134 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005135 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005136 if (cur == NULL)
5137 return;
5138 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005139 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005140 else
5141 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005142 cur->content = grammar->start;
5143 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005144 if (choiceOrInterleave == 0) {
5145 if (ctxt->interleaves == NULL)
5146 ctxt->interleaves = xmlHashCreate(10);
5147 if (ctxt->interleaves == NULL) {
5148 if (ctxt->error != NULL)
5149 ctxt->error(ctxt->userData,
5150 "Failed to create interleaves hash table\n");
5151 ctxt->nbErrors++;
5152 } else {
5153 char tmpname[32];
5154
5155 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5156 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5157 if (ctxt->error != NULL)
5158 ctxt->error(ctxt->userData,
5159 "Failed to add %s to hash table\n", tmpname);
5160 ctxt->nbErrors++;
5161 }
5162 }
5163 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005164}
5165
5166/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005167 * xmlRelaxNGCheckCycles:
5168 * @ctxt: a Relax-NG parser context
5169 * @nodes: grammar children nodes
5170 * @depth: the counter
5171 *
5172 * Check for cycles.
5173 *
5174 * Returns 0 if check passed, and -1 in case of error
5175 */
5176static int
5177xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5178 xmlRelaxNGDefinePtr cur, int depth) {
5179 int ret = 0;
5180
5181 while ((ret == 0) && (cur != NULL)) {
5182 if ((cur->type == XML_RELAXNG_REF) ||
5183 (cur->type == XML_RELAXNG_PARENTREF)) {
5184 if (cur->depth == -1) {
5185 cur->depth = depth;
5186 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5187 cur->depth = -2;
5188 } else if (depth == cur->depth) {
5189 if (ctxt->error != NULL)
5190 ctxt->error(ctxt->userData,
5191 "Detected a cycle in %s references\n", cur->name);
5192 ctxt->nbErrors++;
5193 return(-1);
5194 }
5195 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5196 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5197 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005198 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005199 }
5200 cur = cur->next;
5201 }
5202 return(ret);
5203}
5204
5205/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005206 * xmlRelaxNGTryUnlink:
5207 * @ctxt: a Relax-NG parser context
5208 * @cur: the definition to unlink
5209 * @parent: the parent definition
5210 * @prev: the previous sibling definition
5211 *
5212 * Try to unlink a definition. If not possble make it a NOOP
5213 *
5214 * Returns the new prev definition
5215 */
5216static xmlRelaxNGDefinePtr
5217xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5218 xmlRelaxNGDefinePtr cur,
5219 xmlRelaxNGDefinePtr parent,
5220 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005221 if (prev != NULL) {
5222 prev->next = cur->next;
5223 } else {
5224 if (parent != NULL) {
5225 if (parent->content == cur)
5226 parent->content = cur->next;
5227 else if (parent->attrs == cur)
5228 parent->attrs = cur->next;
5229 else if (parent->nameClass == cur)
5230 parent->nameClass = cur->next;
5231 } else {
5232 cur->type = XML_RELAXNG_NOOP;
5233 prev = cur;
5234 }
5235 }
5236 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005237}
5238
5239/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005240 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005241 * @ctxt: a Relax-NG parser context
5242 * @nodes: grammar children nodes
5243 *
5244 * Check for simplification of empty and notAllowed
5245 */
5246static void
5247xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5248 xmlRelaxNGDefinePtr cur,
5249 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005250 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005251
Daniel Veillardfd573f12003-03-16 17:52:32 +00005252 while (cur != NULL) {
5253 if ((cur->type == XML_RELAXNG_REF) ||
5254 (cur->type == XML_RELAXNG_PARENTREF)) {
5255 if (cur->depth != -3) {
5256 cur->depth = -3;
5257 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005258 }
5259 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005260 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005261 if ((parent != NULL) &&
5262 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5263 (parent->type == XML_RELAXNG_LIST) ||
5264 (parent->type == XML_RELAXNG_GROUP) ||
5265 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005266 (parent->type == XML_RELAXNG_ONEORMORE) ||
5267 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005268 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005269 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005270 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005271 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005272 (parent->type == XML_RELAXNG_CHOICE)) {
5273 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5274 } else
5275 prev = cur;
5276 } else if (cur->type == XML_RELAXNG_EMPTY){
5277 cur->parent = parent;
5278 if ((parent != NULL) &&
5279 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5280 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005281 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005282 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005283 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005284 if ((parent != NULL) &&
5285 ((parent->type == XML_RELAXNG_GROUP) ||
5286 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5287 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5288 } else
5289 prev = cur;
5290 } else {
5291 cur->parent = parent;
5292 if (cur->content != NULL)
5293 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5294 if (cur->attrs != NULL)
5295 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5296 if (cur->nameClass != NULL)
5297 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5298 /*
5299 * This may result in a simplification
5300 */
5301 if ((cur->type == XML_RELAXNG_GROUP) ||
5302 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5303 if (cur->content == NULL)
5304 cur->type = XML_RELAXNG_EMPTY;
5305 else if (cur->content->next == NULL) {
5306 if ((parent == NULL) && (prev == NULL)) {
5307 cur->type = XML_RELAXNG_NOOP;
5308 } else if (prev == NULL) {
5309 parent->content = cur->content;
5310 cur->content->next = cur->next;
5311 cur = cur->content;
5312 } else {
5313 cur->content->next = cur->next;
5314 prev->next = cur->content;
5315 cur = cur->content;
5316 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005317 }
5318 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005319 /*
5320 * the current node may have been transformed back
5321 */
5322 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5323 (cur->content != NULL) &&
5324 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5325 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5326 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5327 if ((parent != NULL) &&
5328 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5329 (parent->type == XML_RELAXNG_LIST) ||
5330 (parent->type == XML_RELAXNG_GROUP) ||
5331 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5332 (parent->type == XML_RELAXNG_ONEORMORE) ||
5333 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5334 parent->type = XML_RELAXNG_NOT_ALLOWED;
5335 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005336 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005337 if ((parent != NULL) &&
5338 (parent->type == XML_RELAXNG_CHOICE)) {
5339 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5340 } else
5341 prev = cur;
5342 } else if (cur->type == XML_RELAXNG_EMPTY){
5343 if ((parent != NULL) &&
5344 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5345 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5346 parent->type = XML_RELAXNG_EMPTY;
5347 break;
5348 }
5349 if ((parent != NULL) &&
5350 ((parent->type == XML_RELAXNG_GROUP) ||
5351 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5352 (parent->type == XML_RELAXNG_CHOICE))) {
5353 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5354 } else
5355 prev = cur;
5356 } else {
5357 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005358 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005359 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005360 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005361 }
5362}
5363
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005364/**
5365 * xmlRelaxNGGroupContentType:
5366 * @ct1: the first content type
5367 * @ct2: the second content type
5368 *
5369 * Try to group 2 content types
5370 *
5371 * Returns the content type
5372 */
5373static xmlRelaxNGContentType
5374xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5375 xmlRelaxNGContentType ct2) {
5376 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5377 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5378 return(XML_RELAXNG_CONTENT_ERROR);
5379 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5380 return(ct2);
5381 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5382 return(ct1);
5383 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5384 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5385 return(XML_RELAXNG_CONTENT_COMPLEX);
5386 return(XML_RELAXNG_CONTENT_ERROR);
5387}
5388
5389/**
5390 * xmlRelaxNGMaxContentType:
5391 * @ct1: the first content type
5392 * @ct2: the second content type
5393 *
5394 * Compute the max content-type
5395 *
5396 * Returns the content type
5397 */
5398static xmlRelaxNGContentType
5399xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5400 xmlRelaxNGContentType ct2) {
5401 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5402 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5403 return(XML_RELAXNG_CONTENT_ERROR);
5404 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5405 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5406 return(XML_RELAXNG_CONTENT_SIMPLE);
5407 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5408 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5409 return(XML_RELAXNG_CONTENT_COMPLEX);
5410 return(XML_RELAXNG_CONTENT_EMPTY);
5411}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005412
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005413/**
5414 * xmlRelaxNGCheckRules:
5415 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005416 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005417 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005418 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005419 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005420 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005421 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005422 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005423 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005424static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005425xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5426 xmlRelaxNGDefinePtr cur, int flags,
5427 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005428 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005429 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005430
Daniel Veillardfd573f12003-03-16 17:52:32 +00005431 while (cur != NULL) {
5432 ret = XML_RELAXNG_CONTENT_EMPTY;
5433 if ((cur->type == XML_RELAXNG_REF) ||
5434 (cur->type == XML_RELAXNG_PARENTREF)) {
5435 if (flags & XML_RELAXNG_IN_LIST) {
5436 if (ctxt->error != NULL)
5437 ctxt->error(ctxt->userData,
5438 "Found forbidden pattern list//ref\n");
5439 ctxt->nbErrors++;
5440 }
5441 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5442 if (ctxt->error != NULL)
5443 ctxt->error(ctxt->userData,
5444 "Found forbidden pattern data/except//ref\n");
5445 ctxt->nbErrors++;
5446 }
5447 if (cur->depth > -4) {
5448 cur->depth = -4;
5449 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5450 flags, cur->type);
5451 cur->depth = ret - 15 ;
5452 } else if (cur->depth == -4) {
5453 ret = XML_RELAXNG_CONTENT_COMPLEX;
5454 } else {
5455 ret = (xmlRelaxNGContentType) cur->depth + 15;
5456 }
5457 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5458 /*
5459 * The 7.3 Attribute derivation rule for groups is plugged there
5460 */
5461 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5462 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5463 if (ctxt->error != NULL)
5464 ctxt->error(ctxt->userData,
5465 "Found forbidden pattern data/except//element(ref)\n");
5466 ctxt->nbErrors++;
5467 }
5468 if (flags & XML_RELAXNG_IN_LIST) {
5469 if (ctxt->error != NULL)
5470 ctxt->error(ctxt->userData,
5471 "Found forbidden pattern list//element(ref)\n");
5472 ctxt->nbErrors++;
5473 }
5474 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5475 if (ctxt->error != NULL)
5476 ctxt->error(ctxt->userData,
5477 "Found forbidden pattern attribute//element(ref)\n");
5478 ctxt->nbErrors++;
5479 }
5480 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5481 if (ctxt->error != NULL)
5482 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005483 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005484 ctxt->nbErrors++;
5485 }
5486 /*
5487 * reset since in the simple form elements are only child
5488 * of grammar/define
5489 */
5490 nflags = 0;
5491 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5492 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5493 if (ctxt->error != NULL)
5494 ctxt->error(ctxt->userData,
5495 "Element %s attributes have a content type error\n",
5496 cur->name);
5497 ctxt->nbErrors++;
5498 }
5499 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5500 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5501 if (ctxt->error != NULL)
5502 ctxt->error(ctxt->userData,
5503 "Element %s has a content type error\n",
5504 cur->name);
5505 ctxt->nbErrors++;
5506 } else {
5507 ret = XML_RELAXNG_CONTENT_COMPLEX;
5508 }
5509 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5510 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5511 if (ctxt->error != NULL)
5512 ctxt->error(ctxt->userData,
5513 "Found forbidden pattern attribute//attribute\n");
5514 ctxt->nbErrors++;
5515 }
5516 if (flags & XML_RELAXNG_IN_LIST) {
5517 if (ctxt->error != NULL)
5518 ctxt->error(ctxt->userData,
5519 "Found forbidden pattern list//attribute\n");
5520 ctxt->nbErrors++;
5521 }
5522 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5523 if (ctxt->error != NULL)
5524 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005525 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005526 ctxt->nbErrors++;
5527 }
5528 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5529 if (ctxt->error != NULL)
5530 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005531 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005532 ctxt->nbErrors++;
5533 }
5534 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5535 if (ctxt->error != NULL)
5536 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005537 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005538 ctxt->nbErrors++;
5539 }
5540 if (flags & XML_RELAXNG_IN_START) {
5541 if (ctxt->error != NULL)
5542 ctxt->error(ctxt->userData,
5543 "Found forbidden pattern start//attribute\n");
5544 ctxt->nbErrors++;
5545 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005546 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5547 if (cur->ns == NULL) {
5548 if (ctxt->error != NULL)
5549 ctxt->error(ctxt->userData,
5550 "Found anyName attribute without oneOrMore ancestor\n");
5551 ctxt->nbErrors++;
5552 } else {
5553 if (ctxt->error != NULL)
5554 ctxt->error(ctxt->userData,
5555 "Found nsName attribute without oneOrMore ancestor\n");
5556 ctxt->nbErrors++;
5557 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005558 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005559 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5560 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5561 ret = XML_RELAXNG_CONTENT_EMPTY;
5562 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5563 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5564 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5565 if (ctxt->error != NULL)
5566 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005567 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005568 ctxt->nbErrors++;
5569 }
5570 if (flags & XML_RELAXNG_IN_START) {
5571 if (ctxt->error != NULL)
5572 ctxt->error(ctxt->userData,
5573 "Found forbidden pattern start//oneOrMore\n");
5574 ctxt->nbErrors++;
5575 }
5576 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5577 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5578 ret = xmlRelaxNGGroupContentType(ret, ret);
5579 } else if (cur->type == XML_RELAXNG_LIST) {
5580 if (flags & XML_RELAXNG_IN_LIST) {
5581 if (ctxt->error != NULL)
5582 ctxt->error(ctxt->userData,
5583 "Found forbidden pattern list//list\n");
5584 ctxt->nbErrors++;
5585 }
5586 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5587 if (ctxt->error != NULL)
5588 ctxt->error(ctxt->userData,
5589 "Found forbidden pattern data/except//list\n");
5590 ctxt->nbErrors++;
5591 }
5592 if (flags & XML_RELAXNG_IN_START) {
5593 if (ctxt->error != NULL)
5594 ctxt->error(ctxt->userData,
5595 "Found forbidden pattern start//list\n");
5596 ctxt->nbErrors++;
5597 }
5598 nflags = flags | XML_RELAXNG_IN_LIST;
5599 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5600 } else if (cur->type == XML_RELAXNG_GROUP) {
5601 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5602 if (ctxt->error != NULL)
5603 ctxt->error(ctxt->userData,
5604 "Found forbidden pattern data/except//group\n");
5605 ctxt->nbErrors++;
5606 }
5607 if (flags & XML_RELAXNG_IN_START) {
5608 if (ctxt->error != NULL)
5609 ctxt->error(ctxt->userData,
5610 "Found forbidden pattern start//group\n");
5611 ctxt->nbErrors++;
5612 }
5613 if (flags & XML_RELAXNG_IN_ONEORMORE)
5614 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5615 else
5616 nflags = flags;
5617 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5618 /*
5619 * The 7.3 Attribute derivation rule for groups is plugged there
5620 */
5621 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5622 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5623 if (flags & XML_RELAXNG_IN_LIST) {
5624 if (ctxt->error != NULL)
5625 ctxt->error(ctxt->userData,
5626 "Found forbidden pattern list//interleave\n");
5627 ctxt->nbErrors++;
5628 }
5629 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5630 if (ctxt->error != NULL)
5631 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005632 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005633 ctxt->nbErrors++;
5634 }
5635 if (flags & XML_RELAXNG_IN_START) {
5636 if (ctxt->error != NULL)
5637 ctxt->error(ctxt->userData,
5638 "Found forbidden pattern start//interleave\n");
5639 ctxt->nbErrors++;
5640 }
5641 if (flags & XML_RELAXNG_IN_ONEORMORE)
5642 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5643 else
5644 nflags = flags;
5645 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5646 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5647 if ((cur->parent != NULL) &&
5648 (cur->parent->type == XML_RELAXNG_DATATYPE))
5649 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5650 else
5651 nflags = flags;
5652 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5653 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5654 if (flags & XML_RELAXNG_IN_START) {
5655 if (ctxt->error != NULL)
5656 ctxt->error(ctxt->userData,
5657 "Found forbidden pattern start//data\n");
5658 ctxt->nbErrors++;
5659 }
5660 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5661 ret = XML_RELAXNG_CONTENT_SIMPLE;
5662 } else if (cur->type == XML_RELAXNG_VALUE) {
5663 if (flags & XML_RELAXNG_IN_START) {
5664 if (ctxt->error != NULL)
5665 ctxt->error(ctxt->userData,
5666 "Found forbidden pattern start//value\n");
5667 ctxt->nbErrors++;
5668 }
5669 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5670 ret = XML_RELAXNG_CONTENT_SIMPLE;
5671 } else if (cur->type == XML_RELAXNG_TEXT) {
5672 if (flags & XML_RELAXNG_IN_LIST) {
5673 if (ctxt->error != NULL)
5674 ctxt->error(ctxt->userData,
5675 "Found forbidden pattern list//text\n");
5676 ctxt->nbErrors++;
5677 }
5678 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5679 if (ctxt->error != NULL)
5680 ctxt->error(ctxt->userData,
5681 "Found forbidden pattern data/except//text\n");
5682 ctxt->nbErrors++;
5683 }
5684 if (flags & XML_RELAXNG_IN_START) {
5685 if (ctxt->error != NULL)
5686 ctxt->error(ctxt->userData,
5687 "Found forbidden pattern start//text\n");
5688 ctxt->nbErrors++;
5689 }
5690 ret = XML_RELAXNG_CONTENT_COMPLEX;
5691 } else if (cur->type == XML_RELAXNG_EMPTY) {
5692 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5693 if (ctxt->error != NULL)
5694 ctxt->error(ctxt->userData,
5695 "Found forbidden pattern data/except//empty\n");
5696 ctxt->nbErrors++;
5697 }
5698 if (flags & XML_RELAXNG_IN_START) {
5699 if (ctxt->error != NULL)
5700 ctxt->error(ctxt->userData,
5701 "Found forbidden pattern start//empty\n");
5702 ctxt->nbErrors++;
5703 }
5704 ret = XML_RELAXNG_CONTENT_EMPTY;
5705 } else if (cur->type == XML_RELAXNG_CHOICE) {
5706 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5707 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5708 } else {
5709 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5710 }
5711 cur = cur->next;
5712 if (ptype == XML_RELAXNG_GROUP) {
5713 val = xmlRelaxNGGroupContentType(val, ret);
5714 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5715 tmp = xmlRelaxNGGroupContentType(val, ret);
5716 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5717 tmp = xmlRelaxNGMaxContentType(val, ret);
5718 } else if (ptype == XML_RELAXNG_CHOICE) {
5719 val = xmlRelaxNGMaxContentType(val, ret);
5720 } else if (ptype == XML_RELAXNG_LIST) {
5721 val = XML_RELAXNG_CONTENT_SIMPLE;
5722 } else if (ptype == XML_RELAXNG_EXCEPT) {
5723 if (ret == XML_RELAXNG_CONTENT_ERROR)
5724 val = XML_RELAXNG_CONTENT_ERROR;
5725 else
5726 val = XML_RELAXNG_CONTENT_SIMPLE;
5727 } else {
5728 val = xmlRelaxNGGroupContentType(val, ret);
5729 }
5730
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005731 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005732 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005733}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005734
5735/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005736 * xmlRelaxNGParseGrammar:
5737 * @ctxt: a Relax-NG parser context
5738 * @nodes: grammar children nodes
5739 *
5740 * parse a Relax-NG <grammar> node
5741 *
5742 * Returns the internal xmlRelaxNGGrammarPtr built or
5743 * NULL in case of error
5744 */
5745static xmlRelaxNGGrammarPtr
5746xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5747 xmlRelaxNGGrammarPtr ret, tmp, old;
5748
Daniel Veillardc482e262003-02-26 14:48:48 +00005749#ifdef DEBUG_GRAMMAR
5750 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5751#endif
5752
Daniel Veillard6eadf632003-01-23 18:29:16 +00005753 ret = xmlRelaxNGNewGrammar(ctxt);
5754 if (ret == NULL)
5755 return(NULL);
5756
5757 /*
5758 * Link the new grammar in the tree
5759 */
5760 ret->parent = ctxt->grammar;
5761 if (ctxt->grammar != NULL) {
5762 tmp = ctxt->grammar->children;
5763 if (tmp == NULL) {
5764 ctxt->grammar->children = ret;
5765 } else {
5766 while (tmp->next != NULL)
5767 tmp = tmp->next;
5768 tmp->next = ret;
5769 }
5770 }
5771
5772 old = ctxt->grammar;
5773 ctxt->grammar = ret;
5774 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5775 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005776 if (ctxt->grammar == NULL) {
5777 if (ctxt->error != NULL)
5778 ctxt->error(ctxt->userData,
5779 "Failed to parse <grammar> content\n");
5780 ctxt->nbErrors++;
5781 } else if (ctxt->grammar->start == NULL) {
5782 if (ctxt->error != NULL)
5783 ctxt->error(ctxt->userData,
5784 "Element <grammar> has no <start>\n");
5785 ctxt->nbErrors++;
5786 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005787
5788 /*
5789 * Apply 4.17 mergingd rules to defines and starts
5790 */
5791 xmlRelaxNGCombineStart(ctxt, ret);
5792 if (ret->defs != NULL) {
5793 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5794 ctxt);
5795 }
5796
5797 /*
5798 * link together defines and refs in this grammar
5799 */
5800 if (ret->refs != NULL) {
5801 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5802 ctxt);
5803 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005804
Daniel Veillard6eadf632003-01-23 18:29:16 +00005805 ctxt->grammar = old;
5806 return(ret);
5807}
5808
5809/**
5810 * xmlRelaxNGParseDocument:
5811 * @ctxt: a Relax-NG parser context
5812 * @node: the root node of the RelaxNG schema
5813 *
5814 * parse a Relax-NG definition resource and build an internal
5815 * xmlRelaxNG struture which can be used to validate instances.
5816 *
5817 * Returns the internal XML RelaxNG structure built or
5818 * NULL in case of error
5819 */
5820static xmlRelaxNGPtr
5821xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5822 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005823 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005824 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005825
5826 if ((ctxt == NULL) || (node == NULL))
5827 return (NULL);
5828
5829 schema = xmlRelaxNGNewRelaxNG(ctxt);
5830 if (schema == NULL)
5831 return(NULL);
5832
Daniel Veillard276be4a2003-01-24 01:03:34 +00005833 olddefine = ctxt->define;
5834 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005835 if (IS_RELAXNG(node, "grammar")) {
5836 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5837 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005838 xmlRelaxNGGrammarPtr tmp, ret;
5839
5840 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005841 if (schema->topgrammar == NULL) {
5842 return(schema);
5843 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005844 /*
5845 * Link the new grammar in the tree
5846 */
5847 ret->parent = ctxt->grammar;
5848 if (ctxt->grammar != NULL) {
5849 tmp = ctxt->grammar->children;
5850 if (tmp == NULL) {
5851 ctxt->grammar->children = ret;
5852 } else {
5853 while (tmp->next != NULL)
5854 tmp = tmp->next;
5855 tmp->next = ret;
5856 }
5857 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005858 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005859 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005860 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005861 if (old != NULL)
5862 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005863 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005864 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005865 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005866 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005867 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005868 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5869 while ((schema->topgrammar->start != NULL) &&
5870 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5871 (schema->topgrammar->start->next != NULL))
5872 schema->topgrammar->start = schema->topgrammar->start->content;
5873 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5874 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005875 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005876 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005877
5878#ifdef DEBUG
5879 if (schema == NULL)
5880 xmlGenericError(xmlGenericErrorContext,
5881 "xmlRelaxNGParseDocument() failed\n");
5882#endif
5883
5884 return (schema);
5885}
5886
5887/************************************************************************
5888 * *
5889 * Reading RelaxNGs *
5890 * *
5891 ************************************************************************/
5892
5893/**
5894 * xmlRelaxNGNewParserCtxt:
5895 * @URL: the location of the schema
5896 *
5897 * Create an XML RelaxNGs parse context for that file/resource expected
5898 * to contain an XML RelaxNGs file.
5899 *
5900 * Returns the parser context or NULL in case of error
5901 */
5902xmlRelaxNGParserCtxtPtr
5903xmlRelaxNGNewParserCtxt(const char *URL) {
5904 xmlRelaxNGParserCtxtPtr ret;
5905
5906 if (URL == NULL)
5907 return(NULL);
5908
5909 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5910 if (ret == NULL) {
5911 xmlGenericError(xmlGenericErrorContext,
5912 "Failed to allocate new schama parser context for %s\n", URL);
5913 return (NULL);
5914 }
5915 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5916 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005917 ret->error = xmlGenericError;
5918 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005919 return (ret);
5920}
5921
5922/**
5923 * xmlRelaxNGNewMemParserCtxt:
5924 * @buffer: a pointer to a char array containing the schemas
5925 * @size: the size of the array
5926 *
5927 * Create an XML RelaxNGs parse context for that memory buffer expected
5928 * to contain an XML RelaxNGs file.
5929 *
5930 * Returns the parser context or NULL in case of error
5931 */
5932xmlRelaxNGParserCtxtPtr
5933xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5934 xmlRelaxNGParserCtxtPtr ret;
5935
5936 if ((buffer == NULL) || (size <= 0))
5937 return(NULL);
5938
5939 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5940 if (ret == NULL) {
5941 xmlGenericError(xmlGenericErrorContext,
5942 "Failed to allocate new schama parser context\n");
5943 return (NULL);
5944 }
5945 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5946 ret->buffer = buffer;
5947 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005948 ret->error = xmlGenericError;
5949 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005950 return (ret);
5951}
5952
5953/**
5954 * xmlRelaxNGFreeParserCtxt:
5955 * @ctxt: the schema parser context
5956 *
5957 * Free the resources associated to the schema parser context
5958 */
5959void
5960xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5961 if (ctxt == NULL)
5962 return;
5963 if (ctxt->URL != NULL)
5964 xmlFree(ctxt->URL);
5965 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005966 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005967 if (ctxt->interleaves != NULL)
5968 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005969 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005970 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005971 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005972 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005973 if (ctxt->docTab != NULL)
5974 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005975 if (ctxt->incTab != NULL)
5976 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005977 if (ctxt->defTab != NULL) {
5978 int i;
5979
5980 for (i = 0;i < ctxt->defNr;i++)
5981 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5982 xmlFree(ctxt->defTab);
5983 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005984 xmlFree(ctxt);
5985}
5986
Daniel Veillard6eadf632003-01-23 18:29:16 +00005987/**
Daniel Veillardd2298792003-02-14 16:54:11 +00005988 * xmlRelaxNGNormExtSpace:
5989 * @value: a value
5990 *
5991 * Removes the leading and ending spaces of the value
5992 * The string is modified "in situ"
5993 */
5994static void
5995xmlRelaxNGNormExtSpace(xmlChar *value) {
5996 xmlChar *start = value;
5997 xmlChar *cur = value;
5998 if (value == NULL)
5999 return;
6000
6001 while (IS_BLANK(*cur)) cur++;
6002 if (cur == start) {
6003 do {
6004 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6005 if (*cur == 0)
6006 return;
6007 start = cur;
6008 while (IS_BLANK(*cur)) cur++;
6009 if (*cur == 0) {
6010 *start = 0;
6011 return;
6012 }
6013 } while (1);
6014 } else {
6015 do {
6016 while ((*cur != 0) && (!IS_BLANK(*cur)))
6017 *start++ = *cur++;
6018 if (*cur == 0) {
6019 *start = 0;
6020 return;
6021 }
6022 /* don't try to normalize the inner spaces */
6023 while (IS_BLANK(*cur)) cur++;
6024 *start++ = *cur++;
6025 if (*cur == 0) {
6026 *start = 0;
6027 return;
6028 }
6029 } while (1);
6030 }
6031}
6032
6033/**
6034 * xmlRelaxNGCheckAttributes:
6035 * @ctxt: a Relax-NG parser context
6036 * @node: a Relax-NG node
6037 *
6038 * Check all the attributes on the given node
6039 */
6040static void
6041xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6042 xmlAttrPtr cur, next;
6043
6044 cur = node->properties;
6045 while (cur != NULL) {
6046 next = cur->next;
6047 if ((cur->ns == NULL) ||
6048 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6049 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6050 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6051 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6052 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6053 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006054 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006055 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6056 if (ctxt->error != NULL)
6057 ctxt->error(ctxt->userData,
6058 "Attribute %s is not allowed on %s\n",
6059 cur->name, node->name);
6060 ctxt->nbErrors++;
6061 }
6062 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6063 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6064 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6065 if (ctxt->error != NULL)
6066 ctxt->error(ctxt->userData,
6067 "Attribute %s is not allowed on %s\n",
6068 cur->name, node->name);
6069 ctxt->nbErrors++;
6070 }
6071 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6072 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6073 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6074 if (ctxt->error != NULL)
6075 ctxt->error(ctxt->userData,
6076 "Attribute %s is not allowed on %s\n",
6077 cur->name, node->name);
6078 ctxt->nbErrors++;
6079 }
6080 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6081 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6082 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6083 if (ctxt->error != NULL)
6084 ctxt->error(ctxt->userData,
6085 "Attribute %s is not allowed on %s\n",
6086 cur->name, node->name);
6087 ctxt->nbErrors++;
6088 }
6089 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6090 xmlChar *val;
6091 xmlURIPtr uri;
6092
6093 val = xmlNodeListGetString(node->doc, cur->children, 1);
6094 if (val != NULL) {
6095 if (val[0] != 0) {
6096 uri = xmlParseURI((const char *) val);
6097 if (uri == NULL) {
6098 if (ctxt->error != NULL)
6099 ctxt->error(ctxt->userData,
6100 "Attribute %s contains invalid URI %s\n",
6101 cur->name, val);
6102 ctxt->nbErrors++;
6103 } else {
6104 if (uri->scheme == NULL) {
6105 if (ctxt->error != NULL)
6106 ctxt->error(ctxt->userData,
6107 "Attribute %s URI %s is not absolute\n",
6108 cur->name, val);
6109 ctxt->nbErrors++;
6110 }
6111 if (uri->fragment != NULL) {
6112 if (ctxt->error != NULL)
6113 ctxt->error(ctxt->userData,
6114 "Attribute %s URI %s has a fragment ID\n",
6115 cur->name, val);
6116 ctxt->nbErrors++;
6117 }
6118 xmlFreeURI(uri);
6119 }
6120 }
6121 xmlFree(val);
6122 }
6123 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6124 if (ctxt->error != NULL)
6125 ctxt->error(ctxt->userData,
6126 "Unknown attribute %s on %s\n",
6127 cur->name, node->name);
6128 ctxt->nbErrors++;
6129 }
6130 }
6131 cur = next;
6132 }
6133}
6134
6135/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006136 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006137 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006138 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006139 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006140 * Cleanup the subtree from unwanted nodes for parsing, resolve
6141 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006142 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006143static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006144xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006145 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006146
Daniel Veillard6eadf632003-01-23 18:29:16 +00006147 delete = NULL;
6148 cur = root;
6149 while (cur != NULL) {
6150 if (delete != NULL) {
6151 xmlUnlinkNode(delete);
6152 xmlFreeNode(delete);
6153 delete = NULL;
6154 }
6155 if (cur->type == XML_ELEMENT_NODE) {
6156 /*
6157 * Simplification 4.1. Annotations
6158 */
6159 if ((cur->ns == NULL) ||
6160 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006161 if ((cur->parent != NULL) &&
6162 (cur->parent->type == XML_ELEMENT_NODE) &&
6163 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6164 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6165 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6166 if (ctxt->error != NULL)
6167 ctxt->error(ctxt->userData,
6168 "element %s doesn't allow foreign elements\n",
6169 cur->parent->name);
6170 ctxt->nbErrors++;
6171 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006172 delete = cur;
6173 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006174 } else {
6175 xmlRelaxNGCleanupAttributes(ctxt, cur);
6176 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6177 xmlChar *href, *ns, *base, *URL;
6178 xmlRelaxNGDocumentPtr docu;
6179 xmlNodePtr tmp;
6180
6181 ns = xmlGetProp(cur, BAD_CAST "ns");
6182 if (ns == NULL) {
6183 tmp = cur->parent;
6184 while ((tmp != NULL) &&
6185 (tmp->type == XML_ELEMENT_NODE)) {
6186 ns = xmlGetProp(tmp, BAD_CAST "ns");
6187 if (ns != NULL)
6188 break;
6189 tmp = tmp->parent;
6190 }
6191 }
6192 href = xmlGetProp(cur, BAD_CAST "href");
6193 if (href == NULL) {
6194 if (ctxt->error != NULL)
6195 ctxt->error(ctxt->userData,
6196 "xmlRelaxNGParse: externalRef has no href attribute\n");
6197 ctxt->nbErrors++;
6198 delete = cur;
6199 goto skip_children;
6200 }
6201 base = xmlNodeGetBase(cur->doc, cur);
6202 URL = xmlBuildURI(href, base);
6203 if (URL == NULL) {
6204 if (ctxt->error != NULL)
6205 ctxt->error(ctxt->userData,
6206 "Failed to compute URL for externalRef %s\n", href);
6207 ctxt->nbErrors++;
6208 if (href != NULL)
6209 xmlFree(href);
6210 if (base != NULL)
6211 xmlFree(base);
6212 delete = cur;
6213 goto skip_children;
6214 }
6215 if (href != NULL)
6216 xmlFree(href);
6217 if (base != NULL)
6218 xmlFree(base);
6219 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6220 if (docu == NULL) {
6221 if (ctxt->error != NULL)
6222 ctxt->error(ctxt->userData,
6223 "Failed to load externalRef %s\n", URL);
6224 ctxt->nbErrors++;
6225 xmlFree(URL);
6226 delete = cur;
6227 goto skip_children;
6228 }
6229 if (ns != NULL)
6230 xmlFree(ns);
6231 xmlFree(URL);
6232 cur->_private = docu;
6233 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6234 xmlChar *href, *ns, *base, *URL;
6235 xmlRelaxNGIncludePtr incl;
6236 xmlNodePtr tmp;
6237
6238 href = xmlGetProp(cur, BAD_CAST "href");
6239 if (href == NULL) {
6240 if (ctxt->error != NULL)
6241 ctxt->error(ctxt->userData,
6242 "xmlRelaxNGParse: include has no href attribute\n");
6243 ctxt->nbErrors++;
6244 delete = cur;
6245 goto skip_children;
6246 }
6247 base = xmlNodeGetBase(cur->doc, cur);
6248 URL = xmlBuildURI(href, base);
6249 if (URL == NULL) {
6250 if (ctxt->error != NULL)
6251 ctxt->error(ctxt->userData,
6252 "Failed to compute URL for include %s\n", href);
6253 ctxt->nbErrors++;
6254 if (href != NULL)
6255 xmlFree(href);
6256 if (base != NULL)
6257 xmlFree(base);
6258 delete = cur;
6259 goto skip_children;
6260 }
6261 if (href != NULL)
6262 xmlFree(href);
6263 if (base != NULL)
6264 xmlFree(base);
6265 ns = xmlGetProp(cur, BAD_CAST "ns");
6266 if (ns == NULL) {
6267 tmp = cur->parent;
6268 while ((tmp != NULL) &&
6269 (tmp->type == XML_ELEMENT_NODE)) {
6270 ns = xmlGetProp(tmp, BAD_CAST "ns");
6271 if (ns != NULL)
6272 break;
6273 tmp = tmp->parent;
6274 }
6275 }
6276 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6277 if (ns != NULL)
6278 xmlFree(ns);
6279 if (incl == NULL) {
6280 if (ctxt->error != NULL)
6281 ctxt->error(ctxt->userData,
6282 "Failed to load include %s\n", URL);
6283 ctxt->nbErrors++;
6284 xmlFree(URL);
6285 delete = cur;
6286 goto skip_children;
6287 }
6288 xmlFree(URL);
6289 cur->_private = incl;
6290 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6291 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6292 xmlChar *name, *ns;
6293 xmlNodePtr text = NULL;
6294
6295 /*
6296 * Simplification 4.8. name attribute of element
6297 * and attribute elements
6298 */
6299 name = xmlGetProp(cur, BAD_CAST "name");
6300 if (name != NULL) {
6301 if (cur->children == NULL) {
6302 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6303 name);
6304 } else {
6305 xmlNodePtr node;
6306 node = xmlNewNode(cur->ns, BAD_CAST "name");
6307 if (node != NULL) {
6308 xmlAddPrevSibling(cur->children, node);
6309 text = xmlNewText(name);
6310 xmlAddChild(node, text);
6311 text = node;
6312 }
6313 }
6314 if (text == NULL) {
6315 if (ctxt->error != NULL)
6316 ctxt->error(ctxt->userData,
6317 "Failed to create a name %s element\n", name);
6318 ctxt->nbErrors++;
6319 }
6320 xmlUnsetProp(cur, BAD_CAST "name");
6321 xmlFree(name);
6322 ns = xmlGetProp(cur, BAD_CAST "ns");
6323 if (ns != NULL) {
6324 if (text != NULL) {
6325 xmlSetProp(text, BAD_CAST "ns", ns);
6326 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6327 }
6328 xmlFree(ns);
6329 } else if (xmlStrEqual(cur->name,
6330 BAD_CAST "attribute")) {
6331 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6332 }
6333 }
6334 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6335 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6336 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6337 /*
6338 * Simplification 4.8. name attribute of element
6339 * and attribute elements
6340 */
6341 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6342 xmlNodePtr node;
6343 xmlChar *ns = NULL;
6344
6345 node = cur->parent;
6346 while ((node != NULL) &&
6347 (node->type == XML_ELEMENT_NODE)) {
6348 ns = xmlGetProp(node, BAD_CAST "ns");
6349 if (ns != NULL) {
6350 break;
6351 }
6352 node = node->parent;
6353 }
6354 if (ns == NULL) {
6355 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6356 } else {
6357 xmlSetProp(cur, BAD_CAST "ns", ns);
6358 xmlFree(ns);
6359 }
6360 }
6361 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6362 xmlChar *name, *local, *prefix;
6363
6364 /*
6365 * Simplification: 4.10. QNames
6366 */
6367 name = xmlNodeGetContent(cur);
6368 if (name != NULL) {
6369 local = xmlSplitQName2(name, &prefix);
6370 if (local != NULL) {
6371 xmlNsPtr ns;
6372
6373 ns = xmlSearchNs(cur->doc, cur, prefix);
6374 if (ns == NULL) {
6375 if (ctxt->error != NULL)
6376 ctxt->error(ctxt->userData,
6377 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6378 ctxt->nbErrors++;
6379 } else {
6380 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6381 xmlNodeSetContent(cur, local);
6382 }
6383 xmlFree(local);
6384 xmlFree(prefix);
6385 }
6386 xmlFree(name);
6387 }
6388 }
6389 /*
6390 * 4.16
6391 */
6392 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6393 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6394 if (ctxt->error != NULL)
6395 ctxt->error(ctxt->userData,
6396 "Found nsName/except//nsName forbidden construct\n");
6397 ctxt->nbErrors++;
6398 }
6399 }
6400 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6401 (cur != root)) {
6402 int oldflags = ctxt->flags;
6403
6404 /*
6405 * 4.16
6406 */
6407 if ((cur->parent != NULL) &&
6408 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6409 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6410 xmlRelaxNGCleanupTree(ctxt, cur);
6411 ctxt->flags = oldflags;
6412 goto skip_children;
6413 } else if ((cur->parent != NULL) &&
6414 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6415 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6416 xmlRelaxNGCleanupTree(ctxt, cur);
6417 ctxt->flags = oldflags;
6418 goto skip_children;
6419 }
6420 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6421 /*
6422 * 4.16
6423 */
6424 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6425 if (ctxt->error != NULL)
6426 ctxt->error(ctxt->userData,
6427 "Found anyName/except//anyName forbidden construct\n");
6428 ctxt->nbErrors++;
6429 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6430 if (ctxt->error != NULL)
6431 ctxt->error(ctxt->userData,
6432 "Found nsName/except//anyName forbidden construct\n");
6433 ctxt->nbErrors++;
6434 }
6435 }
6436 /*
6437 * Thisd is not an else since "include" is transformed
6438 * into a div
6439 */
6440 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6441 xmlChar *ns;
6442 xmlNodePtr child, ins, tmp;
6443
6444 /*
6445 * implements rule 4.11
6446 */
6447
6448 ns = xmlGetProp(cur, BAD_CAST "ns");
6449
6450 child = cur->children;
6451 ins = cur;
6452 while (child != NULL) {
6453 if (ns != NULL) {
6454 if (!xmlHasProp(child, BAD_CAST "ns")) {
6455 xmlSetProp(child, BAD_CAST "ns", ns);
6456 }
6457 }
6458 tmp = child->next;
6459 xmlUnlinkNode(child);
6460 ins = xmlAddNextSibling(ins, child);
6461 child = tmp;
6462 }
6463 if (ns != NULL)
6464 xmlFree(ns);
6465 delete = cur;
6466 goto skip_children;
6467 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006468 }
6469 }
6470 /*
6471 * Simplification 4.2 whitespaces
6472 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006473 else if ((cur->type == XML_TEXT_NODE) ||
6474 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006475 if (IS_BLANK_NODE(cur)) {
6476 if (cur->parent->type == XML_ELEMENT_NODE) {
6477 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6478 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6479 delete = cur;
6480 } else {
6481 delete = cur;
6482 goto skip_children;
6483 }
6484 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006485 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006486 delete = cur;
6487 goto skip_children;
6488 }
6489
6490 /*
6491 * Skip to next node
6492 */
6493 if (cur->children != NULL) {
6494 if ((cur->children->type != XML_ENTITY_DECL) &&
6495 (cur->children->type != XML_ENTITY_REF_NODE) &&
6496 (cur->children->type != XML_ENTITY_NODE)) {
6497 cur = cur->children;
6498 continue;
6499 }
6500 }
6501skip_children:
6502 if (cur->next != NULL) {
6503 cur = cur->next;
6504 continue;
6505 }
6506
6507 do {
6508 cur = cur->parent;
6509 if (cur == NULL)
6510 break;
6511 if (cur == root) {
6512 cur = NULL;
6513 break;
6514 }
6515 if (cur->next != NULL) {
6516 cur = cur->next;
6517 break;
6518 }
6519 } while (cur != NULL);
6520 }
6521 if (delete != NULL) {
6522 xmlUnlinkNode(delete);
6523 xmlFreeNode(delete);
6524 delete = NULL;
6525 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006526}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006527
Daniel Veillardc5312d72003-02-21 17:14:10 +00006528/**
6529 * xmlRelaxNGCleanupDoc:
6530 * @ctxt: a Relax-NG parser context
6531 * @doc: an xmldocPtr document pointer
6532 *
6533 * Cleanup the document from unwanted nodes for parsing, resolve
6534 * Include and externalRef lookups.
6535 *
6536 * Returns the cleaned up document or NULL in case of error
6537 */
6538static xmlDocPtr
6539xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6540 xmlNodePtr root;
6541
6542 /*
6543 * Extract the root
6544 */
6545 root = xmlDocGetRootElement(doc);
6546 if (root == NULL) {
6547 if (ctxt->error != NULL)
6548 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6549 ctxt->URL);
6550 ctxt->nbErrors++;
6551 return (NULL);
6552 }
6553 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006554 return(doc);
6555}
6556
6557/**
6558 * xmlRelaxNGParse:
6559 * @ctxt: a Relax-NG parser context
6560 *
6561 * parse a schema definition resource and build an internal
6562 * XML Shema struture which can be used to validate instances.
6563 * *WARNING* this interface is highly subject to change
6564 *
6565 * Returns the internal XML RelaxNG structure built from the resource or
6566 * NULL in case of error
6567 */
6568xmlRelaxNGPtr
6569xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6570{
6571 xmlRelaxNGPtr ret = NULL;
6572 xmlDocPtr doc;
6573 xmlNodePtr root;
6574
6575 xmlRelaxNGInitTypes();
6576
6577 if (ctxt == NULL)
6578 return (NULL);
6579
6580 /*
6581 * First step is to parse the input document into an DOM/Infoset
6582 */
6583 if (ctxt->URL != NULL) {
6584 doc = xmlParseFile((const char *) ctxt->URL);
6585 if (doc == NULL) {
6586 if (ctxt->error != NULL)
6587 ctxt->error(ctxt->userData,
6588 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6589 ctxt->nbErrors++;
6590 return (NULL);
6591 }
6592 } else if (ctxt->buffer != NULL) {
6593 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6594 if (doc == NULL) {
6595 if (ctxt->error != NULL)
6596 ctxt->error(ctxt->userData,
6597 "xmlRelaxNGParse: could not parse schemas\n");
6598 ctxt->nbErrors++;
6599 return (NULL);
6600 }
6601 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6602 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6603 } else {
6604 if (ctxt->error != NULL)
6605 ctxt->error(ctxt->userData,
6606 "xmlRelaxNGParse: nothing to parse\n");
6607 ctxt->nbErrors++;
6608 return (NULL);
6609 }
6610 ctxt->document = doc;
6611
6612 /*
6613 * Some preprocessing of the document content
6614 */
6615 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6616 if (doc == NULL) {
6617 xmlFreeDoc(ctxt->document);
6618 ctxt->document = NULL;
6619 return(NULL);
6620 }
6621
Daniel Veillard6eadf632003-01-23 18:29:16 +00006622 /*
6623 * Then do the parsing for good
6624 */
6625 root = xmlDocGetRootElement(doc);
6626 if (root == NULL) {
6627 if (ctxt->error != NULL)
6628 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6629 ctxt->URL);
6630 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006631 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006632 return (NULL);
6633 }
6634 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006635 if (ret == NULL) {
6636 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006637 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006638 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006639
6640 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006641 * Check the ref/defines links
6642 */
6643 /*
6644 * try to preprocess interleaves
6645 */
6646 if (ctxt->interleaves != NULL) {
6647 xmlHashScan(ctxt->interleaves,
6648 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6649 }
6650
6651 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006652 * if there was a parsing error return NULL
6653 */
6654 if (ctxt->nbErrors > 0) {
6655 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006656 ctxt->document = NULL;
6657 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006658 return(NULL);
6659 }
6660
6661 /*
6662 * Transfer the pointer for cleanup at the schema level.
6663 */
6664 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006665 ctxt->document = NULL;
6666 ret->documents = ctxt->documents;
6667 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006668
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006669 ret->includes = ctxt->includes;
6670 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006671 ret->defNr = ctxt->defNr;
6672 ret->defTab = ctxt->defTab;
6673 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006674 if (ctxt->idref == 1)
6675 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006676
6677 return (ret);
6678}
6679
6680/**
6681 * xmlRelaxNGSetParserErrors:
6682 * @ctxt: a Relax-NG validation context
6683 * @err: the error callback
6684 * @warn: the warning callback
6685 * @ctx: contextual data for the callbacks
6686 *
6687 * Set the callback functions used to handle errors for a validation context
6688 */
6689void
6690xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6691 xmlRelaxNGValidityErrorFunc err,
6692 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6693 if (ctxt == NULL)
6694 return;
6695 ctxt->error = err;
6696 ctxt->warning = warn;
6697 ctxt->userData = ctx;
6698}
6699/************************************************************************
6700 * *
6701 * Dump back a compiled form *
6702 * *
6703 ************************************************************************/
6704static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6705
6706/**
6707 * xmlRelaxNGDumpDefines:
6708 * @output: the file output
6709 * @defines: a list of define structures
6710 *
6711 * Dump a RelaxNG structure back
6712 */
6713static void
6714xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6715 while (defines != NULL) {
6716 xmlRelaxNGDumpDefine(output, defines);
6717 defines = defines->next;
6718 }
6719}
6720
6721/**
6722 * xmlRelaxNGDumpDefine:
6723 * @output: the file output
6724 * @define: a define structure
6725 *
6726 * Dump a RelaxNG structure back
6727 */
6728static void
6729xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6730 if (define == NULL)
6731 return;
6732 switch(define->type) {
6733 case XML_RELAXNG_EMPTY:
6734 fprintf(output, "<empty/>\n");
6735 break;
6736 case XML_RELAXNG_NOT_ALLOWED:
6737 fprintf(output, "<notAllowed/>\n");
6738 break;
6739 case XML_RELAXNG_TEXT:
6740 fprintf(output, "<text/>\n");
6741 break;
6742 case XML_RELAXNG_ELEMENT:
6743 fprintf(output, "<element>\n");
6744 if (define->name != NULL) {
6745 fprintf(output, "<name");
6746 if (define->ns != NULL)
6747 fprintf(output, " ns=\"%s\"", define->ns);
6748 fprintf(output, ">%s</name>\n", define->name);
6749 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006750 xmlRelaxNGDumpDefines(output, define->attrs);
6751 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006752 fprintf(output, "</element>\n");
6753 break;
6754 case XML_RELAXNG_LIST:
6755 fprintf(output, "<list>\n");
6756 xmlRelaxNGDumpDefines(output, define->content);
6757 fprintf(output, "</list>\n");
6758 break;
6759 case XML_RELAXNG_ONEORMORE:
6760 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006761 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006762 fprintf(output, "</oneOrMore>\n");
6763 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006764 case XML_RELAXNG_ZEROORMORE:
6765 fprintf(output, "<zeroOrMore>\n");
6766 xmlRelaxNGDumpDefines(output, define->content);
6767 fprintf(output, "</zeroOrMore>\n");
6768 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006769 case XML_RELAXNG_CHOICE:
6770 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006771 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006772 fprintf(output, "</choice>\n");
6773 break;
6774 case XML_RELAXNG_GROUP:
6775 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006776 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006777 fprintf(output, "</group>\n");
6778 break;
6779 case XML_RELAXNG_INTERLEAVE:
6780 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006781 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006782 fprintf(output, "</interleave>\n");
6783 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006784 case XML_RELAXNG_OPTIONAL:
6785 fprintf(output, "<optional>\n");
6786 xmlRelaxNGDumpDefines(output, define->content);
6787 fprintf(output, "</optional>\n");
6788 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006789 case XML_RELAXNG_ATTRIBUTE:
6790 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006791 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006792 fprintf(output, "</attribute>\n");
6793 break;
6794 case XML_RELAXNG_DEF:
6795 fprintf(output, "<define");
6796 if (define->name != NULL)
6797 fprintf(output, " name=\"%s\"", define->name);
6798 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006799 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006800 fprintf(output, "</define>\n");
6801 break;
6802 case XML_RELAXNG_REF:
6803 fprintf(output, "<ref");
6804 if (define->name != NULL)
6805 fprintf(output, " name=\"%s\"", define->name);
6806 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006807 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006808 fprintf(output, "</ref>\n");
6809 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006810 case XML_RELAXNG_PARENTREF:
6811 fprintf(output, "<parentRef");
6812 if (define->name != NULL)
6813 fprintf(output, " name=\"%s\"", define->name);
6814 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006815 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006816 fprintf(output, "</parentRef>\n");
6817 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006818 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006819 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006820 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006821 fprintf(output, "</externalRef>\n");
6822 break;
6823 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006824 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006825 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006826 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006827 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006828 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006829 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006830 TODO
6831 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006832 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006833 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006834 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006835 }
6836}
6837
6838/**
6839 * xmlRelaxNGDumpGrammar:
6840 * @output: the file output
6841 * @grammar: a grammar structure
6842 * @top: is this a top grammar
6843 *
6844 * Dump a RelaxNG structure back
6845 */
6846static void
6847xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6848{
6849 if (grammar == NULL)
6850 return;
6851
6852 fprintf(output, "<grammar");
6853 if (top)
6854 fprintf(output,
6855 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6856 switch(grammar->combine) {
6857 case XML_RELAXNG_COMBINE_UNDEFINED:
6858 break;
6859 case XML_RELAXNG_COMBINE_CHOICE:
6860 fprintf(output, " combine=\"choice\"");
6861 break;
6862 case XML_RELAXNG_COMBINE_INTERLEAVE:
6863 fprintf(output, " combine=\"interleave\"");
6864 break;
6865 default:
6866 fprintf(output, " <!-- invalid combine value -->");
6867 }
6868 fprintf(output, ">\n");
6869 if (grammar->start == NULL) {
6870 fprintf(output, " <!-- grammar had no start -->");
6871 } else {
6872 fprintf(output, "<start>\n");
6873 xmlRelaxNGDumpDefine(output, grammar->start);
6874 fprintf(output, "</start>\n");
6875 }
6876 /* TODO ? Dump the defines ? */
6877 fprintf(output, "</grammar>\n");
6878}
6879
6880/**
6881 * xmlRelaxNGDump:
6882 * @output: the file output
6883 * @schema: a schema structure
6884 *
6885 * Dump a RelaxNG structure back
6886 */
6887void
6888xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6889{
6890 if (schema == NULL) {
6891 fprintf(output, "RelaxNG empty or failed to compile\n");
6892 return;
6893 }
6894 fprintf(output, "RelaxNG: ");
6895 if (schema->doc == NULL) {
6896 fprintf(output, "no document\n");
6897 } else if (schema->doc->URL != NULL) {
6898 fprintf(output, "%s\n", schema->doc->URL);
6899 } else {
6900 fprintf(output, "\n");
6901 }
6902 if (schema->topgrammar == NULL) {
6903 fprintf(output, "RelaxNG has no top grammar\n");
6904 return;
6905 }
6906 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6907}
6908
Daniel Veillardfebcca42003-02-16 15:44:18 +00006909/**
6910 * xmlRelaxNGDumpTree:
6911 * @output: the file output
6912 * @schema: a schema structure
6913 *
6914 * Dump the transformed RelaxNG tree.
6915 */
6916void
6917xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6918{
6919 if (schema == NULL) {
6920 fprintf(output, "RelaxNG empty or failed to compile\n");
6921 return;
6922 }
6923 if (schema->doc == NULL) {
6924 fprintf(output, "no document\n");
6925 } else {
6926 xmlDocDump(output, schema->doc);
6927 }
6928}
6929
Daniel Veillard6eadf632003-01-23 18:29:16 +00006930/************************************************************************
6931 * *
6932 * Validation implementation *
6933 * *
6934 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006935static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6936 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006937static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6938 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006939
6940/**
6941 * xmlRelaxNGSkipIgnored:
6942 * @ctxt: a schema validation context
6943 * @node: the top node.
6944 *
6945 * Skip ignorable nodes in that context
6946 *
6947 * Returns the new sibling or NULL in case of error.
6948 */
6949static xmlNodePtr
6950xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6951 xmlNodePtr node) {
6952 /*
6953 * TODO complete and handle entities
6954 */
6955 while ((node != NULL) &&
6956 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006957 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006958 (((node->type == XML_TEXT_NODE) ||
6959 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00006960 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
6961 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006962 node = node->next;
6963 }
6964 return(node);
6965}
6966
6967/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006968 * xmlRelaxNGNormalize:
6969 * @ctxt: a schema validation context
6970 * @str: the string to normalize
6971 *
6972 * Implements the normalizeWhiteSpace( s ) function from
6973 * section 6.2.9 of the spec
6974 *
6975 * Returns the new string or NULL in case of error.
6976 */
6977static xmlChar *
6978xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6979 xmlChar *ret, *p;
6980 const xmlChar *tmp;
6981 int len;
6982
6983 if (str == NULL)
6984 return(NULL);
6985 tmp = str;
6986 while (*tmp != 0) tmp++;
6987 len = tmp - str;
6988
6989 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
6990 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00006991 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00006992 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00006993 } else {
6994 xmlGenericError(xmlGenericErrorContext,
6995 "xmlRelaxNGNormalize: out of memory\n");
6996 }
Daniel Veillardedc91922003-01-26 00:52:04 +00006997 return(NULL);
6998 }
6999 p = ret;
7000 while (IS_BLANK(*str)) str++;
7001 while (*str != 0) {
7002 if (IS_BLANK(*str)) {
7003 while (IS_BLANK(*str)) str++;
7004 if (*str == 0)
7005 break;
7006 *p++ = ' ';
7007 } else
7008 *p++ = *str++;
7009 }
7010 *p = 0;
7011 return(ret);
7012}
7013
7014/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007015 * xmlRelaxNGValidateDatatype:
7016 * @ctxt: a Relax-NG validation context
7017 * @value: the string value
7018 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007019 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007020 *
7021 * Validate the given value against the dataype
7022 *
7023 * Returns 0 if the validation succeeded or an error code.
7024 */
7025static int
7026xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007027 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007028 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007029 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007030 void *result = NULL;
7031 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007032
7033 if ((define == NULL) || (define->data == NULL)) {
7034 return(-1);
7035 }
7036 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007037 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007038 if ((define->attrs != NULL) &&
7039 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007040 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007041 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007042 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007043 }
7044 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007045 ret = -1;
7046 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007047 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007048 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7049 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007050 return(-1);
7051 } else if (ret == 1) {
7052 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007053 } else if (ret == 2) {
7054 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007055 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007056 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007057 ret = -1;
7058 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007059 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007060 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7061 if (lib->facet != NULL) {
7062 tmp = lib->facet(lib->data, define->name, cur->name,
7063 cur->value, value, result);
7064 if (tmp != 0)
7065 ret = -1;
7066 }
7067 cur = cur->next;
7068 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007069 if ((ret == 0) && (define->content != NULL)) {
7070 const xmlChar *oldvalue, *oldendvalue;
7071
7072 oldvalue = ctxt->state->value;
7073 oldendvalue = ctxt->state->endvalue;
7074 ctxt->state->value = (xmlChar *) value;
7075 ctxt->state->endvalue = NULL;
7076 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7077 ctxt->state->value = (xmlChar *) oldvalue;
7078 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7079 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007080 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7081 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007082 return(ret);
7083}
7084
7085/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007086 * xmlRelaxNGNextValue:
7087 * @ctxt: a Relax-NG validation context
7088 *
7089 * Skip to the next value when validating within a list
7090 *
7091 * Returns 0 if the operation succeeded or an error code.
7092 */
7093static int
7094xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7095 xmlChar *cur;
7096
7097 cur = ctxt->state->value;
7098 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7099 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007100 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007101 return(0);
7102 }
7103 while (*cur != 0) cur++;
7104 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7105 if (cur == ctxt->state->endvalue)
7106 ctxt->state->value = NULL;
7107 else
7108 ctxt->state->value = cur;
7109 return(0);
7110}
7111
7112/**
7113 * xmlRelaxNGValidateValueList:
7114 * @ctxt: a Relax-NG validation context
7115 * @defines: the list of definitions to verify
7116 *
7117 * Validate the given set of definitions for the current value
7118 *
7119 * Returns 0 if the validation succeeded or an error code.
7120 */
7121static int
7122xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7123 xmlRelaxNGDefinePtr defines) {
7124 int ret = 0;
7125
7126 while (defines != NULL) {
7127 ret = xmlRelaxNGValidateValue(ctxt, defines);
7128 if (ret != 0)
7129 break;
7130 defines = defines->next;
7131 }
7132 return(ret);
7133}
7134
7135/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007136 * xmlRelaxNGValidateValue:
7137 * @ctxt: a Relax-NG validation context
7138 * @define: the definition to verify
7139 *
7140 * Validate the given definition for the current value
7141 *
7142 * Returns 0 if the validation succeeded or an error code.
7143 */
7144static int
7145xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7146 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007147 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007148 xmlChar *value;
7149
7150 value = ctxt->state->value;
7151 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007152 case XML_RELAXNG_EMPTY: {
7153 if ((value != NULL) && (value[0] != 0)) {
7154 int idx = 0;
7155
7156 while (IS_BLANK(value[idx]))
7157 idx++;
7158 if (value[idx] != 0)
7159 ret = -1;
7160 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007161 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007162 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007163 case XML_RELAXNG_TEXT:
7164 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007165 case XML_RELAXNG_VALUE: {
7166 if (!xmlStrEqual(value, define->value)) {
7167 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007168 xmlRelaxNGTypeLibraryPtr lib;
7169
7170 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
7171 if ((lib != NULL) && (lib->comp != NULL))
7172 ret = lib->comp(lib->data, define->name, value,
7173 define->value);
7174 else
7175 ret = -1;
7176 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007177 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007178 return(-1);
7179 } else if (ret == 1) {
7180 ret = 0;
7181 } else {
7182 ret = -1;
7183 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007184 } else {
7185 xmlChar *nval, *nvalue;
7186
7187 /*
7188 * TODO: trivial optimizations are possible by
7189 * computing at compile-time
7190 */
7191 nval = xmlRelaxNGNormalize(ctxt, define->value);
7192 nvalue = xmlRelaxNGNormalize(ctxt, value);
7193
Daniel Veillardea3f3982003-01-26 19:45:18 +00007194 if ((nval == NULL) || (nvalue == NULL) ||
7195 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007196 ret = -1;
7197 if (nval != NULL)
7198 xmlFree(nval);
7199 if (nvalue != NULL)
7200 xmlFree(nvalue);
7201 }
7202 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007203 if (ret == 0)
7204 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007205 break;
7206 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007207 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007208 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7209 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007210 if (ret == 0)
7211 xmlRelaxNGNextValue(ctxt);
7212
7213 break;
7214 }
7215 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007216 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007217 xmlChar *oldvalue;
7218
7219 oldflags = ctxt->flags;
7220 ctxt->flags |= FLAGS_IGNORABLE;
7221
7222 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007223 while (list != NULL) {
7224 ret = xmlRelaxNGValidateValue(ctxt, list);
7225 if (ret == 0) {
7226 break;
7227 }
7228 ctxt->state->value = oldvalue;
7229 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007230 }
7231 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007232 if (ret != 0) {
7233 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7234 xmlRelaxNGDumpValidError(ctxt);
7235 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007236 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007237 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007238 if (ret == 0)
7239 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007240 break;
7241 }
7242 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007243 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007244 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007245#ifdef DEBUG_LIST
7246 int nb_values = 0;
7247#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007248
7249 oldvalue = ctxt->state->value;
7250 oldend = ctxt->state->endvalue;
7251
7252 val = xmlStrdup(oldvalue);
7253 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007254 val = xmlStrdup(BAD_CAST "");
7255 }
7256 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007257 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007258 return(-1);
7259 }
7260 cur = val;
7261 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007262 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007263 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007264 cur++;
7265#ifdef DEBUG_LIST
7266 nb_values++;
7267#endif
7268 while (IS_BLANK(*cur))
7269 *cur++ = 0;
7270 } else
7271 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007272 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007273#ifdef DEBUG_LIST
7274 xmlGenericError(xmlGenericErrorContext,
7275 "list value: '%s' found %d items\n", oldvalue, nb_values);
7276 nb_values = 0;
7277#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007278 ctxt->state->endvalue = cur;
7279 cur = val;
7280 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007281
Daniel Veillardfd573f12003-03-16 17:52:32 +00007282 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007283
Daniel Veillardfd573f12003-03-16 17:52:32 +00007284 while (list != NULL) {
7285 if (ctxt->state->value == ctxt->state->endvalue)
7286 ctxt->state->value = NULL;
7287 ret = xmlRelaxNGValidateValue(ctxt, list);
7288 if (ret != 0) {
7289#ifdef DEBUG_LIST
7290 xmlGenericError(xmlGenericErrorContext,
7291 "Failed to validate value: '%s' with %d rule\n",
7292 ctxt->state->value, nb_values);
7293#endif
7294 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007295 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007296#ifdef DEBUG_LIST
7297 nb_values++;
7298#endif
7299 list = list->next;
7300 }
7301
7302 if ((ret == 0) && (ctxt->state->value != NULL) &&
7303 (ctxt->state->value != ctxt->state->endvalue)) {
7304 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7305 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007306 }
7307 xmlFree(val);
7308 ctxt->state->value = oldvalue;
7309 ctxt->state->endvalue = oldend;
7310 break;
7311 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007312 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007313 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7314 if (ret != 0) {
7315 break;
7316 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007317 /* no break on purpose */
7318 case XML_RELAXNG_ZEROORMORE: {
7319 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007320
7321 oldflags = ctxt->flags;
7322 ctxt->flags |= FLAGS_IGNORABLE;
7323 cur = ctxt->state->value;
7324 temp = NULL;
7325 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7326 (temp != cur)) {
7327 temp = cur;
7328 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7329 if (ret != 0) {
7330 ctxt->state->value = temp;
7331 ret = 0;
7332 break;
7333 }
7334 cur = ctxt->state->value;
7335 }
7336 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007337 if (ret != 0) {
7338 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7339 xmlRelaxNGDumpValidError(ctxt);
7340 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007341 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007342 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007343 break;
7344 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007345 case XML_RELAXNG_EXCEPT: {
7346 xmlRelaxNGDefinePtr list;
7347
7348 list = define->content;
7349 while (list != NULL) {
7350 ret = xmlRelaxNGValidateValue(ctxt, list);
7351 if (ret == 0) {
7352 ret = -1;
7353 break;
7354 } else
7355 ret = 0;
7356 list = list->next;
7357 }
7358 break;
7359 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007360 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007361 case XML_RELAXNG_GROUP: {
7362 xmlRelaxNGDefinePtr list;
7363
7364 list = define->content;
7365 while (list != NULL) {
7366 ret = xmlRelaxNGValidateValue(ctxt, list);
7367 if (ret != 0) {
7368 ret = -1;
7369 break;
7370 } else
7371 ret = 0;
7372 list = list->next;
7373 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007374 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007375 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007376 case XML_RELAXNG_REF:
7377 case XML_RELAXNG_PARENTREF:
7378 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7379 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007380 default:
7381 TODO
7382 ret = -1;
7383 }
7384 return(ret);
7385}
7386
7387/**
7388 * xmlRelaxNGValidateValueContent:
7389 * @ctxt: a Relax-NG validation context
7390 * @defines: the list of definitions to verify
7391 *
7392 * Validate the given definitions for the current value
7393 *
7394 * Returns 0 if the validation succeeded or an error code.
7395 */
7396static int
7397xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7398 xmlRelaxNGDefinePtr defines) {
7399 int ret = 0;
7400
7401 while (defines != NULL) {
7402 ret = xmlRelaxNGValidateValue(ctxt, defines);
7403 if (ret != 0)
7404 break;
7405 defines = defines->next;
7406 }
7407 return(ret);
7408}
7409
7410/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007411 * xmlRelaxNGAttributeMatch:
7412 * @ctxt: a Relax-NG validation context
7413 * @define: the definition to check
7414 * @prop: the attribute
7415 *
7416 * Check if the attribute matches the definition nameClass
7417 *
7418 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7419 */
7420static int
7421xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7422 xmlRelaxNGDefinePtr define,
7423 xmlAttrPtr prop) {
7424 int ret;
7425
7426 if (define->name != NULL) {
7427 if (!xmlStrEqual(define->name, prop->name))
7428 return(0);
7429 }
7430 if (define->ns != NULL) {
7431 if (define->ns[0] == 0) {
7432 if (prop->ns != NULL)
7433 return(0);
7434 } else {
7435 if ((prop->ns == NULL) ||
7436 (!xmlStrEqual(define->ns, prop->ns->href)))
7437 return(0);
7438 }
7439 }
7440 if (define->nameClass == NULL)
7441 return(1);
7442 define = define->nameClass;
7443 if (define->type == XML_RELAXNG_EXCEPT) {
7444 xmlRelaxNGDefinePtr list;
7445
7446 list = define->content;
7447 while (list != NULL) {
7448 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7449 if (ret == 1)
7450 return(0);
7451 if (ret < 0)
7452 return(ret);
7453 list = list->next;
7454 }
7455 } else {
7456 TODO
7457 }
7458 return(1);
7459}
7460
7461/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007462 * xmlRelaxNGValidateAttribute:
7463 * @ctxt: a Relax-NG validation context
7464 * @define: the definition to verify
7465 *
7466 * Validate the given attribute definition for that node
7467 *
7468 * Returns 0 if the validation succeeded or an error code.
7469 */
7470static int
7471xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7472 xmlRelaxNGDefinePtr define) {
7473 int ret = 0, i;
7474 xmlChar *value, *oldvalue;
7475 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007476 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007477
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007478 if (ctxt->state->nbAttrLeft <= 0)
7479 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007480 if (define->name != NULL) {
7481 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7482 tmp = ctxt->state->attrs[i];
7483 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7484 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7485 (tmp->ns == NULL)) ||
7486 ((tmp->ns != NULL) &&
7487 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7488 prop = tmp;
7489 break;
7490 }
7491 }
7492 }
7493 if (prop != NULL) {
7494 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7495 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007496 oldseq = ctxt->state->seq;
7497 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007498 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007499 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007500 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007501 if (ctxt->state->value != NULL)
7502 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007503 if (value != NULL)
7504 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007505 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007506 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007507 if (ret == 0) {
7508 /*
7509 * flag the attribute as processed
7510 */
7511 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007512 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007513 }
7514 } else {
7515 ret = -1;
7516 }
7517#ifdef DEBUG
7518 xmlGenericError(xmlGenericErrorContext,
7519 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7520#endif
7521 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007522 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7523 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007524 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007525 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007526 prop = tmp;
7527 break;
7528 }
7529 }
7530 if (prop != NULL) {
7531 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7532 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007533 oldseq = ctxt->state->seq;
7534 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007535 ctxt->state->value = value;
7536 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007537 if (ctxt->state->value != NULL)
7538 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007539 if (value != NULL)
7540 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007541 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007542 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007543 if (ret == 0) {
7544 /*
7545 * flag the attribute as processed
7546 */
7547 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007548 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007549 }
7550 } else {
7551 ret = -1;
7552 }
7553#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007554 if (define->ns != NULL) {
7555 xmlGenericError(xmlGenericErrorContext,
7556 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7557 define->ns, ret);
7558 } else {
7559 xmlGenericError(xmlGenericErrorContext,
7560 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7561 ret);
7562 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007563#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007564 }
7565
7566 return(ret);
7567}
7568
7569/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007570 * xmlRelaxNGValidateAttributeList:
7571 * @ctxt: a Relax-NG validation context
7572 * @define: the list of definition to verify
7573 *
7574 * Validate the given node against the list of attribute definitions
7575 *
7576 * Returns 0 if the validation succeeded or an error code.
7577 */
7578static int
7579xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7580 xmlRelaxNGDefinePtr defines) {
7581 int ret = 0;
7582 while (defines != NULL) {
7583 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7584 ret = -1;
7585 defines = defines->next;
7586 }
7587 return(ret);
7588}
7589
7590/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007591 * xmlRelaxNGNodeMatchesList:
7592 * @node: the node
7593 * @list: a NULL terminated array of definitions
7594 *
7595 * Check if a node can be matched by one of the definitions
7596 *
7597 * Returns 1 if matches 0 otherwise
7598 */
7599static int
7600xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7601 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007602 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007603
7604 if ((node == NULL) || (list == NULL))
7605 return(0);
7606
7607 cur = list[i++];
7608 while (cur != NULL) {
7609 if ((node->type == XML_ELEMENT_NODE) &&
7610 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007611 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7612 if (tmp == 1)
7613 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007614 } else if (((node->type == XML_TEXT_NODE) ||
7615 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007616 (cur->type == XML_RELAXNG_TEXT)) {
7617 return(1);
7618 }
7619 cur = list[i++];
7620 }
7621 return(0);
7622}
7623
7624/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007625 * xmlRelaxNGValidateInterleave:
7626 * @ctxt: a Relax-NG validation context
7627 * @define: the definition to verify
7628 *
7629 * Validate an interleave definition for a node.
7630 *
7631 * Returns 0 if the validation succeeded or an error code.
7632 */
7633static int
7634xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7635 xmlRelaxNGDefinePtr define) {
7636 int ret = 0, i, nbgroups, left;
7637 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007638 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007639
7640 xmlRelaxNGValidStatePtr oldstate;
7641 xmlRelaxNGPartitionPtr partitions;
7642 xmlRelaxNGInterleaveGroupPtr group = NULL;
7643 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7644 xmlNodePtr *list = NULL, *lasts = NULL;
7645
7646 if (define->data != NULL) {
7647 partitions = (xmlRelaxNGPartitionPtr) define->data;
7648 nbgroups = partitions->nbgroups;
7649 left = nbgroups;
7650 } else {
7651 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7652 return(-1);
7653 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007654 /*
7655 * Optimizations for MIXED
7656 */
7657 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007658 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007659 ctxt->flags |= FLAGS_MIXED_CONTENT;
7660 if (nbgroups == 2) {
7661 /*
7662 * this is a pure <mixed> case
7663 */
7664 if (ctxt->state != NULL)
7665 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7666 ctxt->state->seq);
7667 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7668 ret = xmlRelaxNGValidateDefinition(ctxt,
7669 partitions->groups[1]->rule);
7670 else
7671 ret = xmlRelaxNGValidateDefinition(ctxt,
7672 partitions->groups[0]->rule);
7673 if (ret == 0) {
7674 if (ctxt->state != NULL)
7675 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7676 ctxt->state->seq);
7677 }
7678 ctxt->flags = oldflags;
7679 return(ret);
7680 }
7681 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007682
7683 /*
7684 * Build arrays to store the first and last node of the chain
7685 * pertaining to each group
7686 */
7687 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7688 if (list == NULL) {
7689 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7690 return(-1);
7691 }
7692 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7693 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7694 if (lasts == NULL) {
7695 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7696 return(-1);
7697 }
7698 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7699
7700 /*
7701 * Walk the sequence of children finding the right group and
7702 * sorting them in sequences.
7703 */
7704 cur = ctxt->state->seq;
7705 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7706 start = cur;
7707 while (cur != NULL) {
7708 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007709 if ((partitions->triage != NULL) &&
7710 (partitions->flags & IS_DETERMINIST)) {
7711 void *tmp = NULL;
7712
7713 if ((cur->type == XML_TEXT_NODE) ||
7714 (cur->type == XML_CDATA_SECTION_NODE)) {
7715 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7716 NULL);
7717 } else if (cur->type == XML_ELEMENT_NODE) {
7718 if (cur->ns != NULL) {
7719 tmp = xmlHashLookup2(partitions->triage, cur->name,
7720 cur->ns->href);
7721 if (tmp == NULL)
7722 tmp = xmlHashLookup2(partitions->triage,
7723 BAD_CAST "#any", cur->ns->href);
7724 } else
7725 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7726 if (tmp == NULL)
7727 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7728 NULL);
7729 }
7730
7731 if (tmp == NULL) {
7732 i = nbgroups;
7733 } else {
7734 i = ((long) tmp) - 1;
7735 if (partitions->flags & IS_NEEDCHECK) {
7736 group = partitions->groups[i];
7737 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7738 i = nbgroups;
7739 }
7740 }
7741 } else {
7742 for (i = 0;i < nbgroups;i++) {
7743 group = partitions->groups[i];
7744 if (group == NULL)
7745 continue;
7746 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7747 break;
7748 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007749 }
7750 /*
7751 * We break as soon as an element not matched is found
7752 */
7753 if (i >= nbgroups) {
7754 break;
7755 }
7756 if (lasts[i] != NULL) {
7757 lasts[i]->next = cur;
7758 lasts[i] = cur;
7759 } else {
7760 list[i] = cur;
7761 lasts[i] = cur;
7762 }
7763 if (cur->next != NULL)
7764 lastchg = cur->next;
7765 else
7766 lastchg = cur;
7767 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7768 }
7769 if (ret != 0) {
7770 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7771 ret = -1;
7772 goto done;
7773 }
7774 lastelem = cur;
7775 oldstate = ctxt->state;
7776 for (i = 0;i < nbgroups;i++) {
7777 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7778 group = partitions->groups[i];
7779 if (lasts[i] != NULL) {
7780 last = lasts[i]->next;
7781 lasts[i]->next = NULL;
7782 }
7783 ctxt->state->seq = list[i];
7784 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7785 if (ret != 0)
7786 break;
7787 if (ctxt->state != NULL) {
7788 cur = ctxt->state->seq;
7789 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007790 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007791 oldstate = ctxt->state;
7792 ctxt->state = NULL;
7793 if (cur != NULL) {
7794 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7795 ret = -1;
7796 ctxt->state = oldstate;
7797 goto done;
7798 }
7799 } else if (ctxt->states != NULL) {
7800 int j;
7801 int found = 0;
7802
7803 for (j = 0;j < ctxt->states->nbState;j++) {
7804 cur = ctxt->states->tabState[j]->seq;
7805 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7806 if (cur == NULL) {
7807 found = 1;
7808 break;
7809 }
7810 }
7811 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007812 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007813 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7814 }
7815 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007816 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007817 }
7818 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7819 ctxt->states = NULL;
7820 if (found == 0) {
7821 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7822 ret = -1;
7823 ctxt->state = oldstate;
7824 goto done;
7825 }
7826 } else {
7827 ret = -1;
7828 break;
7829 }
7830 if (lasts[i] != NULL) {
7831 lasts[i]->next = last;
7832 }
7833 }
7834 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007835 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007836 ctxt->state = oldstate;
7837 ctxt->state->seq = lastelem;
7838 if (ret != 0) {
7839 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7840 ret = -1;
7841 goto done;
7842 }
7843
7844done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007845 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007846 /*
7847 * builds the next links chain from the prev one
7848 */
7849 cur = lastchg;
7850 while (cur != NULL) {
7851 if ((cur == start) || (cur->prev == NULL))
7852 break;
7853 cur->prev->next = cur;
7854 cur = cur->prev;
7855 }
7856 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007857 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007858 }
7859
7860 xmlFree(list);
7861 xmlFree(lasts);
7862 return(ret);
7863}
7864
7865/**
7866 * xmlRelaxNGValidateDefinitionList:
7867 * @ctxt: a Relax-NG validation context
7868 * @define: the list of definition to verify
7869 *
7870 * Validate the given node content against the (list) of definitions
7871 *
7872 * Returns 0 if the validation succeeded or an error code.
7873 */
7874static int
7875xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7876 xmlRelaxNGDefinePtr defines) {
7877 int ret = 0, res;
7878
7879
Daniel Veillard952379b2003-03-17 15:37:12 +00007880 if (defines == NULL) {
7881 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7882 return(-1);
7883 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007884 while (defines != NULL) {
7885 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7886 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7887 if (res < 0)
7888 ret = -1;
7889 } else {
7890 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7891 return(-1);
7892 }
7893 if (ret < 0)
7894 break;
7895 defines = defines->next;
7896 }
7897
7898 return(ret);
7899}
7900
7901/**
7902 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007903 * @ctxt: a Relax-NG validation context
7904 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007905 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007906 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007907 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007908 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007909 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007910 */
7911static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007912xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7913 xmlRelaxNGDefinePtr define,
7914 xmlNodePtr elem) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007915 int ret = 0, oldflags;
Daniel Veillard416589a2003-02-17 17:25:42 +00007916
Daniel Veillardfd573f12003-03-16 17:52:32 +00007917 if (define->name != NULL) {
7918 if (!xmlStrEqual(elem->name, define->name)) {
7919 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7920 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007921 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007922 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007923 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7924 if (elem->ns == NULL) {
7925 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7926 elem->name);
7927 return(0);
7928 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7929 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7930 elem->name, define->ns);
7931 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007932 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007933 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7934 (define->name == NULL)) {
7935 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7936 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007937 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007938 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7939 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7940 define->name);
7941 return(0);
7942 }
7943
7944 if (define->nameClass == NULL)
7945 return(1);
7946
7947 define = define->nameClass;
7948 if (define->type == XML_RELAXNG_EXCEPT) {
7949 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007950 if (ctxt != NULL) {
7951 oldflags = ctxt->flags;
7952 ctxt->flags |= FLAGS_IGNORABLE;
7953 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007954
7955 list = define->content;
7956 while (list != NULL) {
7957 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7958 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007959 if (ctxt != NULL)
7960 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007961 return(0);
7962 }
7963 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007964 if (ctxt != NULL)
7965 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007966 return(ret);
7967 }
7968 list = list->next;
7969 }
7970 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007971 if (ctxt != NULL) {
7972 ctxt->flags = oldflags;
7973 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007974 } else if (define->type == XML_RELAXNG_CHOICE) {
7975 xmlRelaxNGDefinePtr list;
7976
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007977 if (ctxt != NULL) {
7978 oldflags = ctxt->flags;
7979 ctxt->flags |= FLAGS_IGNORABLE;
7980 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007981
7982 list = define->nameClass;
7983 while (list != NULL) {
7984 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7985 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007986 if (ctxt != NULL)
7987 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007988 return(1);
7989 }
7990 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007991 if (ctxt != NULL)
7992 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007993 return(ret);
7994 }
7995 list = list->next;
7996 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007997 if (ctxt != NULL) {
7998 if (ret != 0) {
7999 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8000 xmlRelaxNGDumpValidError(ctxt);
8001 } else {
8002 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8003 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008004 }
8005 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008006 if (ctxt != NULL) {
8007 ctxt->flags = oldflags;
8008 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008009 } else {
8010 TODO
8011 ret = -1;
8012 }
8013 return(ret);
8014}
8015
8016/**
8017 * xmlRelaxNGValidateElementEnd:
8018 * @ctxt: a Relax-NG validation context
8019 *
8020 * Validate the end of the element, implements check that
8021 * there is nothing left not consumed in the element content
8022 * or in the attribute list.
8023 *
8024 * Returns 0 if the validation succeeded or an error code.
8025 */
8026static int
8027xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8028 int ret = 0, i;
8029 xmlRelaxNGValidStatePtr state;
8030
8031 state = ctxt->state;
8032 if (state->seq != NULL) {
8033 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8034 if (state->seq != NULL) {
8035 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8036 state->node->name, state->seq->name);
8037 ret = -1;
8038 }
8039 }
8040 for (i = 0;i < state->nbAttrs;i++) {
8041 if (state->attrs[i] != NULL) {
8042 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8043 state->attrs[i]->name, state->node->name);
8044 ret = -1;
8045 }
8046 }
8047 return(ret);
8048}
8049
8050/**
8051 * xmlRelaxNGValidateState:
8052 * @ctxt: a Relax-NG validation context
8053 * @define: the definition to verify
8054 *
8055 * Validate the current state against the definition
8056 *
8057 * Returns 0 if the validation succeeded or an error code.
8058 */
8059static int
8060xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8061 xmlRelaxNGDefinePtr define) {
8062 xmlNodePtr node;
8063 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008064 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008065
8066 if (define == NULL) {
8067 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8068 return(-1);
8069 }
8070
8071 if (ctxt->state != NULL) {
8072 node = ctxt->state->seq;
8073 } else {
8074 node = NULL;
8075 }
8076#ifdef DEBUG
8077 for (i = 0;i < ctxt->depth;i++)
8078 xmlGenericError(xmlGenericErrorContext, " ");
8079 xmlGenericError(xmlGenericErrorContext,
8080 "Start validating %s ", xmlRelaxNGDefName(define));
8081 if (define->name != NULL)
8082 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8083 if ((node != NULL) && (node->name != NULL))
8084 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8085 else
8086 xmlGenericError(xmlGenericErrorContext, "\n");
8087#endif
8088 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008089 switch (define->type) {
8090 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008091 node = xmlRelaxNGSkipIgnored(ctxt, node);
8092 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008093 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008094 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008095 ret = -1;
8096 break;
8097 case XML_RELAXNG_TEXT:
8098 while ((node != NULL) &&
8099 ((node->type == XML_TEXT_NODE) ||
8100 (node->type == XML_COMMENT_NODE) ||
8101 (node->type == XML_PI_NODE) ||
8102 (node->type == XML_CDATA_SECTION_NODE)))
8103 node = node->next;
8104 ctxt->state->seq = node;
8105 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008106 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008107 errNr = ctxt->errNr;
8108 node = xmlRelaxNGSkipIgnored(ctxt, node);
8109 if (node == NULL) {
8110 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8111 ret = -1;
8112 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8113 xmlRelaxNGDumpValidError(ctxt);
8114 break;
8115 }
8116 if (node->type != XML_ELEMENT_NODE) {
8117 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8118 ret = -1;
8119 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8120 xmlRelaxNGDumpValidError(ctxt);
8121 break;
8122 }
8123 /*
8124 * This node was already validated successfully against
8125 * this definition.
8126 */
8127 if (node->_private == define) {
8128 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008129 if (ctxt->errNr != 0) {
8130 while ((ctxt->err != NULL) &&
8131 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8132 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
8133 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8134 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8135 xmlRelaxNGValidErrorPop(ctxt);
8136 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008137 break;
8138 }
8139
8140 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8141 if (ret <= 0) {
8142 ret = -1;
8143 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8144 xmlRelaxNGDumpValidError(ctxt);
8145 break;
8146 }
8147 ret = 0;
8148 if (ctxt->errNr != 0) {
8149 while ((ctxt->err != NULL) &&
8150 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8151 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
8152 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8153 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8154 xmlRelaxNGValidErrorPop(ctxt);
8155 }
8156 errNr = ctxt->errNr;
8157
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008158 oldflags = ctxt->flags;
8159 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8160 ctxt->flags -= FLAGS_MIXED_CONTENT;
8161 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008162 state = xmlRelaxNGNewValidState(ctxt, node);
8163 if (state == NULL) {
8164 ret = -1;
8165 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8166 xmlRelaxNGDumpValidError(ctxt);
8167 break;
8168 }
8169
8170 oldstate = ctxt->state;
8171 ctxt->state = state;
8172 if (define->attrs != NULL) {
8173 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8174 if (tmp != 0) {
8175 ret = -1;
8176 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8177 }
8178 }
8179 if (define->content != NULL) {
8180 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8181 if (tmp != 0) {
8182 ret = -1;
8183 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8184 }
8185 }
8186 if (ctxt->states != NULL) {
8187 tmp = -1;
8188
Daniel Veillardfd573f12003-03-16 17:52:32 +00008189 ctxt->flags |= FLAGS_IGNORABLE;
8190
8191 for (i = 0;i < ctxt->states->nbState;i++) {
8192 state = ctxt->states->tabState[i];
8193 ctxt->state = state;
8194
8195 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8196 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008197 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008198 }
8199 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8200 ctxt->flags = oldflags;
8201 ctxt->states = NULL;
8202 if ((ret == 0) && (tmp == -1))
8203 ret = -1;
8204 } else {
8205 state = ctxt->state;
8206 if (ret == 0)
8207 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008208 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008209 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008210 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008211 ctxt->state = oldstate;
8212 if (oldstate != NULL)
8213 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8214 if (ret == 0) {
8215 node->_private = define;
8216 }
8217 if (ret != 0) {
8218 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8219 xmlRelaxNGDumpValidError(ctxt);
8220 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008221 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008222 }
8223
8224#ifdef DEBUG
8225 xmlGenericError(xmlGenericErrorContext,
8226 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8227 node->name, ret);
8228 if (oldstate == NULL)
8229 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8230 else if (oldstate->seq == NULL)
8231 xmlGenericError(xmlGenericErrorContext, ": done\n");
8232 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8233 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8234 oldstate->seq->name);
8235 else
8236 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8237 oldstate->seq->name, oldstate->seq->type);
8238#endif
8239 break;
8240 case XML_RELAXNG_OPTIONAL: {
8241 oldflags = ctxt->flags;
8242 ctxt->flags |= FLAGS_IGNORABLE;
8243 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8244 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8245 if (ret != 0) {
8246 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008247 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008248 ctxt->state = oldstate;
8249 ctxt->flags = oldflags;
8250 ret = 0;
8251 break;
8252 }
8253 if (ctxt->states != NULL) {
8254 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8255 } else {
8256 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8257 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008258 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008259 ctxt->flags = oldflags;
8260 ret = -1;
8261 break;
8262 }
8263 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8264 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8265 ctxt->state = NULL;
8266 }
8267 ctxt->flags = oldflags;
8268 ret = 0;
8269 break;
8270 }
8271 case XML_RELAXNG_ONEORMORE:
8272 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8273 if (ret != 0) {
8274 break;
8275 }
8276 /* no break on purpose */
8277 case XML_RELAXNG_ZEROORMORE: {
8278 int progress;
8279 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8280 int base, j;
8281
8282 res = xmlRelaxNGNewStates(ctxt, 1);
8283 if (res == NULL) {
8284 ret = -1;
8285 break;
8286 }
8287 /*
8288 * All the input states are also exit states
8289 */
8290 if (ctxt->state != NULL) {
8291 xmlRelaxNGAddStates(ctxt, res,
8292 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8293 } else {
8294 for (j = 0;j < ctxt->states->nbState;j++) {
8295 xmlRelaxNGAddStates(ctxt, res,
8296 xmlRelaxNGCopyValidState(ctxt,
8297 ctxt->states->tabState[j]));
8298 }
8299 }
8300 oldflags = ctxt->flags;
8301 ctxt->flags |= FLAGS_IGNORABLE;
8302 do {
8303 progress = 0;
8304 base = res->nbState;
8305
8306 if (ctxt->states != NULL) {
8307 states = ctxt->states;
8308 for (i = 0;i < states->nbState;i++) {
8309 ctxt->state = states->tabState[i];
8310 ctxt->states = NULL;
8311 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8312 define->content);
8313 if (ret == 0) {
8314 if (ctxt->state != NULL) {
8315 tmp = xmlRelaxNGAddStates(ctxt, res,
8316 ctxt->state);
8317 ctxt->state = NULL;
8318 if (tmp == 1)
8319 progress = 1;
8320 } else if (ctxt->states != NULL) {
8321 for (j = 0;j < ctxt->states->nbState;j++) {
8322 tmp = xmlRelaxNGAddStates(ctxt, res,
8323 ctxt->states->tabState[j]);
8324 if (tmp == 1)
8325 progress = 1;
8326 }
8327 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8328 ctxt->states = NULL;
8329 }
8330 } else {
8331 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008332 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008333 ctxt->state = NULL;
8334 }
8335 }
8336 }
8337 } else {
8338 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8339 define->content);
8340 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008341 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008342 ctxt->state = NULL;
8343 } else {
8344 base = res->nbState;
8345 if (ctxt->state != NULL) {
8346 tmp = xmlRelaxNGAddStates(ctxt, res,
8347 ctxt->state);
8348 ctxt->state = NULL;
8349 if (tmp == 1)
8350 progress = 1;
8351 } else if (ctxt->states != NULL) {
8352 for (j = 0;j < ctxt->states->nbState;j++) {
8353 tmp = xmlRelaxNGAddStates(ctxt, res,
8354 ctxt->states->tabState[j]);
8355 if (tmp == 1)
8356 progress = 1;
8357 }
8358 if (states == NULL) {
8359 states = ctxt->states;
8360 } else {
8361 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8362 }
8363 ctxt->states = NULL;
8364 }
8365 }
8366 }
8367 if (progress) {
8368 /*
8369 * Collect all the new nodes added at that step
8370 * and make them the new node set
8371 */
8372 if (res->nbState - base == 1) {
8373 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8374 res->tabState[base]);
8375 } else {
8376 if (states == NULL) {
8377 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8378 }
8379 states->nbState = 0;
8380 for (i = base;i < res->nbState;i++)
8381 xmlRelaxNGAddStates(ctxt, states,
8382 xmlRelaxNGCopyValidState(ctxt,
8383 res->tabState[i]));
8384 ctxt->states = states;
8385 }
8386 }
8387 } while (progress == 1);
8388 if (states != NULL) {
8389 xmlRelaxNGFreeStates(ctxt, states);
8390 }
8391 ctxt->states = res;
8392 ctxt->flags = oldflags;
8393 ret = 0;
8394 break;
8395 }
8396 case XML_RELAXNG_CHOICE: {
Daniel Veillarde063f482003-03-21 16:53:17 +00008397 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008398 xmlRelaxNGStatesPtr states = NULL;
8399
Daniel Veillarde063f482003-03-21 16:53:17 +00008400 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008401
Daniel Veillarde063f482003-03-21 16:53:17 +00008402 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8403 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8404
8405 /*
8406 * Something we can optimize cleanly there is only one
8407 * possble branch out !
8408 */
8409 if (node == NULL) {
8410 ret = -1;
8411 break;
8412 }
8413 if ((node->type == XML_TEXT_NODE) ||
8414 (node->type == XML_CDATA_SECTION_NODE)) {
8415 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8416 } else if (node->type == XML_ELEMENT_NODE) {
8417 if (node->ns != NULL) {
8418 list = xmlHashLookup2(triage, node->name,
8419 node->ns->href);
8420 if (list == NULL)
8421 list = xmlHashLookup2(triage, BAD_CAST "#any",
8422 node->ns->href);
8423 } else
8424 list = xmlHashLookup2(triage, node->name, NULL);
8425 if (list == NULL)
8426 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8427 }
8428 if (list == NULL) {
8429 ret = -1;
8430 break;
8431 }
8432 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8433 break;
8434 }
8435
8436 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008437 oldflags = ctxt->flags;
8438 errNr = ctxt->errNr;
8439 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008440
8441 while (list != NULL) {
8442 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8443 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8444 if (ret == 0) {
8445 if (states == NULL) {
8446 states = xmlRelaxNGNewStates(ctxt, 1);
8447 }
8448 if (ctxt->state != NULL) {
8449 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8450 } else if (ctxt->states != NULL) {
8451 for (i = 0;i < ctxt->states->nbState;i++) {
8452 xmlRelaxNGAddStates(ctxt, states,
8453 ctxt->states->tabState[i]);
8454 }
8455 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8456 ctxt->states = NULL;
8457 }
8458 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008459 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008460 }
8461 ctxt->state = oldstate;
8462 list = list->next;
8463 }
8464 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008465 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008466 ctxt->states = states;
8467 ctxt->state = NULL;
8468 ret = 0;
8469 } else {
8470 ctxt->states = NULL;
8471 }
8472 ctxt->flags = oldflags;
8473 if (ret != 0) {
8474 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8475 xmlRelaxNGDumpValidError(ctxt);
8476 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008477 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008478 }
8479 break;
8480 }
8481 case XML_RELAXNG_DEF:
8482 case XML_RELAXNG_GROUP:
8483 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008484 break;
8485 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008486 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008487 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008488 case XML_RELAXNG_ATTRIBUTE:
8489 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8490 break;
8491 case XML_RELAXNG_NOOP:
8492 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008493 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008494 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8495 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008496 case XML_RELAXNG_PARENTREF:
8497 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8498 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008499 case XML_RELAXNG_DATATYPE: {
8500 xmlNodePtr child;
8501 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008502
Daniel Veillardfd573f12003-03-16 17:52:32 +00008503 child = node;
8504 while (child != NULL) {
8505 if (child->type == XML_ELEMENT_NODE) {
8506 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8507 node->parent->name);
8508 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008509 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008510 } else if ((child->type == XML_TEXT_NODE) ||
8511 (child->type == XML_CDATA_SECTION_NODE)) {
8512 content = xmlStrcat(content, child->content);
8513 }
8514 /* TODO: handle entities ... */
8515 child = child->next;
8516 }
8517 if (ret == -1) {
8518 if (content != NULL)
8519 xmlFree(content);
8520 break;
8521 }
8522 if (content == NULL) {
8523 content = xmlStrdup(BAD_CAST "");
8524 if (content == NULL) {
8525 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8526 ret = -1;
8527 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008528 }
8529 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008530 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8531 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008532 if (ret == -1) {
8533 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8534 } else if (ret == 0) {
8535 ctxt->state->seq = NULL;
8536 }
8537 if (content != NULL)
8538 xmlFree(content);
8539 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008540 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008541 case XML_RELAXNG_VALUE: {
8542 xmlChar *content = NULL;
8543 xmlChar *oldvalue;
8544 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008545
Daniel Veillardfd573f12003-03-16 17:52:32 +00008546 child = node;
8547 while (child != NULL) {
8548 if (child->type == XML_ELEMENT_NODE) {
8549 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8550 node->parent->name);
8551 ret = -1;
8552 break;
8553 } else if ((child->type == XML_TEXT_NODE) ||
8554 (child->type == XML_CDATA_SECTION_NODE)) {
8555 content = xmlStrcat(content, child->content);
8556 }
8557 /* TODO: handle entities ... */
8558 child = child->next;
8559 }
8560 if (ret == -1) {
8561 if (content != NULL)
8562 xmlFree(content);
8563 break;
8564 }
8565 if (content == NULL) {
8566 content = xmlStrdup(BAD_CAST "");
8567 if (content == NULL) {
8568 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8569 ret = -1;
8570 break;
8571 }
8572 }
8573 oldvalue = ctxt->state->value;
8574 ctxt->state->value = content;
8575 ret = xmlRelaxNGValidateValue(ctxt, define);
8576 ctxt->state->value = oldvalue;
8577 if (ret == -1) {
8578 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8579 } else if (ret == 0) {
8580 ctxt->state->seq = NULL;
8581 }
8582 if (content != NULL)
8583 xmlFree(content);
8584 break;
8585 }
8586 case XML_RELAXNG_LIST: {
8587 xmlChar *content;
8588 xmlNodePtr child;
8589 xmlChar *oldvalue, *oldendvalue;
8590 int len;
8591
8592 /*
8593 * Make sure it's only text nodes
8594 */
8595
8596 content = NULL;
8597 child = node;
8598 while (child != NULL) {
8599 if (child->type == XML_ELEMENT_NODE) {
8600 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8601 node->parent->name);
8602 ret = -1;
8603 break;
8604 } else if ((child->type == XML_TEXT_NODE) ||
8605 (child->type == XML_CDATA_SECTION_NODE)) {
8606 content = xmlStrcat(content, child->content);
8607 }
8608 /* TODO: handle entities ... */
8609 child = child->next;
8610 }
8611 if (ret == -1) {
8612 if (content != NULL)
8613 xmlFree(content);
8614 break;
8615 }
8616 if (content == NULL) {
8617 content = xmlStrdup(BAD_CAST "");
8618 if (content == NULL) {
8619 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8620 ret = -1;
8621 break;
8622 }
8623 }
8624 len = xmlStrlen(content);
8625 oldvalue = ctxt->state->value;
8626 oldendvalue = ctxt->state->endvalue;
8627 ctxt->state->value = content;
8628 ctxt->state->endvalue = content + len;
8629 ret = xmlRelaxNGValidateValue(ctxt, define);
8630 ctxt->state->value = oldvalue;
8631 ctxt->state->endvalue = oldendvalue;
8632 if (ret == -1) {
8633 VALID_ERR(XML_RELAXNG_ERR_LIST);
8634 } else if ((ret == 0) && (node != NULL)) {
8635 ctxt->state->seq = node->next;
8636 }
8637 if (content != NULL)
8638 xmlFree(content);
8639 break;
8640 }
8641 case XML_RELAXNG_START:
8642 case XML_RELAXNG_EXCEPT:
8643 case XML_RELAXNG_PARAM:
8644 TODO
8645 ret = -1;
8646 break;
8647 }
8648 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008649#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008650 for (i = 0;i < ctxt->depth;i++)
8651 xmlGenericError(xmlGenericErrorContext, " ");
8652 xmlGenericError(xmlGenericErrorContext,
8653 "Validating %s ", xmlRelaxNGDefName(define));
8654 if (define->name != NULL)
8655 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8656 if (ret == 0)
8657 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8658 else
8659 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008660#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008661 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008662}
8663
8664/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008665 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008666 * @ctxt: a Relax-NG validation context
8667 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008668 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008669 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008670 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008671 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008672 */
8673static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008674xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8675 xmlRelaxNGDefinePtr define) {
8676 xmlRelaxNGStatesPtr states, res;
8677 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008678
Daniel Veillardfd573f12003-03-16 17:52:32 +00008679 /*
8680 * We should NOT have both ctxt->state and ctxt->states
8681 */
8682 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8683 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008684 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008685 ctxt->state = NULL;
8686 }
8687
8688 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8689 if (ctxt->states != NULL) {
8690 ctxt->state = ctxt->states->tabState[0];
8691 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8692 ctxt->states = NULL;
8693 }
8694 ret = xmlRelaxNGValidateState(ctxt, define);
8695 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8696 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008697 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008698 ctxt->state = NULL;
8699 }
8700 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8701 ctxt->state = ctxt->states->tabState[0];
8702 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8703 ctxt->states = NULL;
8704 }
8705 return(ret);
8706 }
8707
8708 states = ctxt->states;
8709 ctxt->states = NULL;
8710 res = NULL;
8711 j = 0;
8712 oldflags = ctxt->flags;
8713 ctxt->flags |= FLAGS_IGNORABLE;
8714 for (i = 0;i < states->nbState;i++) {
8715 ctxt->state = states->tabState[i];
8716 ctxt->states = NULL;
8717 ret = xmlRelaxNGValidateState(ctxt, define);
8718 /*
8719 * We should NOT have both ctxt->state and ctxt->states
8720 */
8721 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8722 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008723 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008724 ctxt->state = NULL;
8725 }
8726 if (ret == 0) {
8727 if (ctxt->states == NULL) {
8728 if (res != NULL) {
8729 /* add the state to the container */
8730 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8731 ctxt->state = NULL;
8732 } else {
8733 /* add the state directly in states */
8734 states->tabState[j++] = ctxt->state;
8735 ctxt->state = NULL;
8736 }
8737 } else {
8738 if (res == NULL) {
8739 /* make it the new container and copy other results */
8740 res = ctxt->states;
8741 ctxt->states = NULL;
8742 for (k = 0;k < j;k++)
8743 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8744 } else {
8745 /* add all the new results to res and reff the container */
8746 for (k = 0;k < ctxt->states->nbState;k++)
8747 xmlRelaxNGAddStates(ctxt, res,
8748 ctxt->states->tabState[k]);
8749 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8750 ctxt->states = NULL;
8751 }
8752 }
8753 } else {
8754 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008755 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008756 ctxt->state = NULL;
8757 } else if (ctxt->states != NULL) {
8758 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008759 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008760 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8761 ctxt->states = NULL;
8762 }
8763 }
8764 }
8765 ctxt->flags = oldflags;
8766 if (res != NULL) {
8767 xmlRelaxNGFreeStates(ctxt, states);
8768 ctxt->states = res;
8769 ret = 0;
8770 } else if (j > 1) {
8771 states->nbState = j;
8772 ctxt->states = states;
8773 ret =0;
8774 } else if (j == 1) {
8775 ctxt->state = states->tabState[0];
8776 xmlRelaxNGFreeStates(ctxt, states);
8777 ret = 0;
8778 } else {
8779 ret = -1;
8780 xmlRelaxNGFreeStates(ctxt, states);
8781 if (ctxt->states != NULL) {
8782 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8783 ctxt->states = NULL;
8784 }
8785 }
8786 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8787 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008788 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008789 ctxt->state = NULL;
8790 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008791 return(ret);
8792}
8793
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008794/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008795 * xmlRelaxNGValidateDocument:
8796 * @ctxt: a Relax-NG validation context
8797 * @doc: the document
8798 *
8799 * Validate the given document
8800 *
8801 * Returns 0 if the validation succeeded or an error code.
8802 */
8803static int
8804xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8805 int ret;
8806 xmlRelaxNGPtr schema;
8807 xmlRelaxNGGrammarPtr grammar;
8808 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008809 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008810
8811 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8812 return(-1);
8813
8814 schema = ctxt->schema;
8815 grammar = schema->topgrammar;
8816 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008817 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008818 return(-1);
8819 }
8820 state = xmlRelaxNGNewValidState(ctxt, NULL);
8821 ctxt->state = state;
8822 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008823 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8824 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008825 node = state->seq;
8826 node = xmlRelaxNGSkipIgnored(ctxt, node);
8827 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008828 if (ret != -1) {
8829 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8830 ret = -1;
8831 }
8832 }
8833 } else if (ctxt->states != NULL) {
8834 int i;
8835 int tmp = -1;
8836
8837 for (i = 0;i < ctxt->states->nbState;i++) {
8838 state = ctxt->states->tabState[i];
8839 node = state->seq;
8840 node = xmlRelaxNGSkipIgnored(ctxt, node);
8841 if (node == NULL)
8842 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008843 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008844 }
8845 if (tmp == -1) {
8846 if (ret != -1) {
8847 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8848 ret = -1;
8849 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008850 }
8851 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008852 if (ctxt->state != NULL) {
8853 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8854 ctxt->state = NULL;
8855 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008856 if (ret != 0)
8857 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008858 if (ctxt->idref == 1) {
8859 xmlValidCtxt vctxt;
8860
8861 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8862 vctxt.valid = 1;
8863 vctxt.error = ctxt->error;
8864 vctxt.warning = ctxt->warning;
8865 vctxt.userData = ctxt->userData;
8866
8867 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8868 ret = -1;
8869 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008870
8871 return(ret);
8872}
8873
Daniel Veillardfd573f12003-03-16 17:52:32 +00008874/************************************************************************
8875 * *
8876 * Validation interfaces *
8877 * *
8878 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008879/**
8880 * xmlRelaxNGNewValidCtxt:
8881 * @schema: a precompiled XML RelaxNGs
8882 *
8883 * Create an XML RelaxNGs validation context based on the given schema
8884 *
8885 * Returns the validation context or NULL in case of error
8886 */
8887xmlRelaxNGValidCtxtPtr
8888xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8889 xmlRelaxNGValidCtxtPtr ret;
8890
8891 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8892 if (ret == NULL) {
8893 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008894 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008895 return (NULL);
8896 }
8897 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8898 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008899 ret->error = xmlGenericError;
8900 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008901 ret->errNr = 0;
8902 ret->errMax = 0;
8903 ret->err = NULL;
8904 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008905 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00008906 ret->states = NULL;
8907 ret->freeState = NULL;
8908 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008909 return (ret);
8910}
8911
8912/**
8913 * xmlRelaxNGFreeValidCtxt:
8914 * @ctxt: the schema validation context
8915 *
8916 * Free the resources associated to the schema validation context
8917 */
8918void
8919xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008920 int k;
8921
Daniel Veillard6eadf632003-01-23 18:29:16 +00008922 if (ctxt == NULL)
8923 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008924 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008925 xmlRelaxNGFreeStates(NULL, ctxt->states);
8926 if (ctxt->freeState != NULL) {
8927 for (k = 0;k < ctxt->freeState->nbState;k++) {
8928 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
8929 }
8930 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
8931 }
Daniel Veillard798024a2003-03-19 10:36:09 +00008932 if (ctxt->freeStates != NULL) {
8933 for (k = 0;k < ctxt->freeStatesNr;k++) {
8934 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
8935 }
8936 xmlFree(ctxt->freeStates);
8937 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00008938 if (ctxt->errTab != NULL)
8939 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008940 xmlFree(ctxt);
8941}
8942
8943/**
8944 * xmlRelaxNGSetValidErrors:
8945 * @ctxt: a Relax-NG validation context
8946 * @err: the error function
8947 * @warn: the warning function
8948 * @ctx: the functions context
8949 *
8950 * Set the error and warning callback informations
8951 */
8952void
8953xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8954 xmlRelaxNGValidityErrorFunc err,
8955 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8956 if (ctxt == NULL)
8957 return;
8958 ctxt->error = err;
8959 ctxt->warning = warn;
8960 ctxt->userData = ctx;
8961}
8962
8963/**
8964 * xmlRelaxNGValidateDoc:
8965 * @ctxt: a Relax-NG validation context
8966 * @doc: a parsed document tree
8967 *
8968 * Validate a document tree in memory.
8969 *
8970 * Returns 0 if the document is valid, a positive error code
8971 * number otherwise and -1 in case of internal or API error.
8972 */
8973int
8974xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8975 int ret;
8976
8977 if ((ctxt == NULL) || (doc == NULL))
8978 return(-1);
8979
8980 ctxt->doc = doc;
8981
8982 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00008983 /*
8984 * TODO: build error codes
8985 */
8986 if (ret == -1)
8987 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008988 return(ret);
8989}
8990
8991#endif /* LIBXML_SCHEMAS_ENABLED */
8992