blob: b1245d7759eeb0c31b067c4597be2fe459e9dbce [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
Daniel Veillard580ced82003-03-21 21:22:48 +00001596 if (ctxt->errNr <= 0) {
1597 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001598 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001599 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001600 ctxt->errNr--;
1601 if (ctxt->errNr > 0)
1602 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1603 else
1604 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001605 cur = &ctxt->errTab[ctxt->errNr];
1606 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001607 if (cur->arg1 != NULL)
1608 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001609 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001610 if (cur->arg2 != NULL)
1611 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001612 cur->arg2 = NULL;
1613 cur->flags = 0;
1614 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001615}
1616
Daniel Veillard42f12e92003-03-07 18:32:59 +00001617/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001618 * xmlRelaxNGDocumentPush:
1619 * @ctxt: the parser context
1620 * @value: the element doc
1621 *
1622 * Pushes a new doc on top of the doc stack
1623 *
1624 * Returns 0 in case of error, the index in the stack otherwise
1625 */
1626static int
1627xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1628 xmlRelaxNGDocumentPtr value)
1629{
1630 if (ctxt->docTab == NULL) {
1631 ctxt->docMax = 4;
1632 ctxt->docNr = 0;
1633 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1634 ctxt->docMax * sizeof(ctxt->docTab[0]));
1635 if (ctxt->docTab == NULL) {
1636 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1637 return (0);
1638 }
1639 }
1640 if (ctxt->docNr >= ctxt->docMax) {
1641 ctxt->docMax *= 2;
1642 ctxt->docTab =
1643 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1644 ctxt->docMax *
1645 sizeof(ctxt->docTab[0]));
1646 if (ctxt->docTab == NULL) {
1647 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1648 return (0);
1649 }
1650 }
1651 ctxt->docTab[ctxt->docNr] = value;
1652 ctxt->doc = value;
1653 return (ctxt->docNr++);
1654}
1655
1656/**
1657 * xmlRelaxNGDocumentPop:
1658 * @ctxt: the parser context
1659 *
1660 * Pops the top doc from the doc stack
1661 *
1662 * Returns the doc just removed
1663 */
1664static xmlRelaxNGDocumentPtr
1665xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1666{
1667 xmlRelaxNGDocumentPtr ret;
1668
1669 if (ctxt->docNr <= 0)
1670 return (0);
1671 ctxt->docNr--;
1672 if (ctxt->docNr > 0)
1673 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1674 else
1675 ctxt->doc = NULL;
1676 ret = ctxt->docTab[ctxt->docNr];
1677 ctxt->docTab[ctxt->docNr] = 0;
1678 return (ret);
1679}
1680
1681/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001682 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001683 * @ctxt: the parser context
1684 * @URL: the normalized URL
1685 * @ns: the inherited ns if any
1686 *
1687 * First lookup if the document is already loaded into the parser context,
1688 * check against recursion. If not found the resource is loaded and
1689 * the content is preprocessed before being returned back to the caller.
1690 *
1691 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1692 */
1693static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001694xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001695 const xmlChar *ns) {
1696 xmlRelaxNGDocumentPtr ret = NULL;
1697 xmlDocPtr doc;
1698 xmlNodePtr root;
1699 int i;
1700
1701 /*
1702 * check against recursion in the stack
1703 */
1704 for (i = 0;i < ctxt->docNr;i++) {
1705 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1706 if (ctxt->error != NULL)
1707 ctxt->error(ctxt->userData,
1708 "Detected an externalRef recursion for %s\n",
1709 URL);
1710 ctxt->nbErrors++;
1711 return(NULL);
1712 }
1713 }
1714
1715 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001716 * load the document
1717 */
1718 doc = xmlParseFile((const char *) URL);
1719 if (doc == NULL) {
1720 if (ctxt->error != NULL)
1721 ctxt->error(ctxt->userData,
1722 "xmlRelaxNG: could not load %s\n", URL);
1723 ctxt->nbErrors++;
1724 return (NULL);
1725 }
1726
1727 /*
1728 * Allocate the document structures and register it first.
1729 */
1730 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1731 if (ret == NULL) {
1732 if (ctxt->error != NULL)
1733 ctxt->error(ctxt->userData,
1734 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1735 ctxt->nbErrors++;
1736 xmlFreeDoc(doc);
1737 return (NULL);
1738 }
1739 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1740 ret->doc = doc;
1741 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001742 ret->next = ctxt->documents;
1743 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001744
1745 /*
1746 * transmit the ns if needed
1747 */
1748 if (ns != NULL) {
1749 root = xmlDocGetRootElement(doc);
1750 if (root != NULL) {
1751 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1752 xmlSetProp(root, BAD_CAST"ns", ns);
1753 }
1754 }
1755 }
1756
1757 /*
1758 * push it on the stack and register it in the hash table
1759 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001760 xmlRelaxNGDocumentPush(ctxt, ret);
1761
1762 /*
1763 * Some preprocessing of the document content
1764 */
1765 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1766 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001767 ctxt->doc = NULL;
1768 return(NULL);
1769 }
1770
1771 xmlRelaxNGDocumentPop(ctxt);
1772
1773 return(ret);
1774}
1775
1776/************************************************************************
1777 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001778 * Error functions *
1779 * *
1780 ************************************************************************/
1781
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001782#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1783#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1784#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1785#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1786#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001787
Daniel Veillardfd573f12003-03-16 17:52:32 +00001788#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001789static const char *
1790xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1791 if (def == NULL)
1792 return("none");
1793 switch(def->type) {
1794 case XML_RELAXNG_EMPTY: return("empty");
1795 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1796 case XML_RELAXNG_EXCEPT: return("except");
1797 case XML_RELAXNG_TEXT: return("text");
1798 case XML_RELAXNG_ELEMENT: return("element");
1799 case XML_RELAXNG_DATATYPE: return("datatype");
1800 case XML_RELAXNG_VALUE: return("value");
1801 case XML_RELAXNG_LIST: return("list");
1802 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1803 case XML_RELAXNG_DEF: return("def");
1804 case XML_RELAXNG_REF: return("ref");
1805 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1806 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001807 case XML_RELAXNG_OPTIONAL: return("optional");
1808 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001809 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1810 case XML_RELAXNG_CHOICE: return("choice");
1811 case XML_RELAXNG_GROUP: return("group");
1812 case XML_RELAXNG_INTERLEAVE: return("interleave");
1813 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001814 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001815 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001816 }
1817 return("unknown");
1818}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001819#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001820
Daniel Veillard6eadf632003-01-23 18:29:16 +00001821/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001822 * xmlRelaxNGGetErrorString:
1823 * @err: the error code
1824 * @arg1: the first string argument
1825 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001826 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001827 * computes a formatted error string for the given error code and args
1828 *
1829 * Returns the error string, it must be deallocated by the caller
1830 */
1831static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001832xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1833 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001834 char msg[1000];
1835
1836 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001837 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001838 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001839 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001840
1841 msg[0] = 0;
1842 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001843 case XML_RELAXNG_OK:
1844 return(NULL);
1845 case XML_RELAXNG_ERR_MEMORY:
1846 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001847 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001848 snprintf(msg, 1000, "failed to validate type %s", arg1);
1849 break;
1850 case XML_RELAXNG_ERR_TYPEVAL:
1851 snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
1852 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001853 case XML_RELAXNG_ERR_DUPID:
1854 snprintf(msg, 1000, "ID %s redefined", arg1);
1855 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001856 case XML_RELAXNG_ERR_TYPECMP:
1857 snprintf(msg, 1000, "failed to compare type %s", arg1);
1858 break;
1859 case XML_RELAXNG_ERR_NOSTATE:
1860 return(xmlCharStrdup("Internal error: no state"));
1861 case XML_RELAXNG_ERR_NODEFINE:
1862 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001863 case XML_RELAXNG_ERR_INTERNAL:
1864 snprintf(msg, 1000, "Internal error: %s", arg1);
1865 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001866 case XML_RELAXNG_ERR_LISTEXTRA:
1867 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1868 break;
1869 case XML_RELAXNG_ERR_INTERNODATA:
1870 return(xmlCharStrdup("Internal: interleave block has no data"));
1871 case XML_RELAXNG_ERR_INTERSEQ:
1872 return(xmlCharStrdup("Invalid sequence in interleave"));
1873 case XML_RELAXNG_ERR_INTEREXTRA:
1874 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1875 break;
1876 case XML_RELAXNG_ERR_ELEMNAME:
1877 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1878 break;
1879 case XML_RELAXNG_ERR_ELEMNONS:
1880 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1881 break;
1882 case XML_RELAXNG_ERR_ELEMWRONGNS:
1883 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1884 arg1, arg2);
1885 break;
1886 case XML_RELAXNG_ERR_ELEMEXTRANS:
1887 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1888 break;
1889 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1890 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1891 break;
1892 case XML_RELAXNG_ERR_NOELEM:
1893 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1894 break;
1895 case XML_RELAXNG_ERR_NOTELEM:
1896 return(xmlCharStrdup("Expecting an element got text"));
1897 case XML_RELAXNG_ERR_ATTRVALID:
1898 snprintf(msg, 1000, "Element %s failed to validate attributes",
1899 arg1);
1900 break;
1901 case XML_RELAXNG_ERR_CONTENTVALID:
1902 snprintf(msg, 1000, "Element %s failed to validate content",
1903 arg1);
1904 break;
1905 case XML_RELAXNG_ERR_EXTRACONTENT:
1906 snprintf(msg, 1000, "Element %s has extra content: %s",
1907 arg1, arg2);
1908 break;
1909 case XML_RELAXNG_ERR_INVALIDATTR:
1910 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1911 arg1, arg2);
1912 break;
1913 case XML_RELAXNG_ERR_DATAELEM:
1914 snprintf(msg, 1000, "Datatype element %s has child elements",
1915 arg1);
1916 break;
1917 case XML_RELAXNG_ERR_VALELEM:
1918 snprintf(msg, 1000, "Value element %s has child elements",
1919 arg1);
1920 break;
1921 case XML_RELAXNG_ERR_LISTELEM:
1922 snprintf(msg, 1000, "List element %s has child elements",
1923 arg1);
1924 break;
1925 case XML_RELAXNG_ERR_DATATYPE:
1926 snprintf(msg, 1000, "Error validating datatype %s",
1927 arg1);
1928 break;
1929 case XML_RELAXNG_ERR_VALUE:
1930 snprintf(msg, 1000, "Error validating value %s",
1931 arg1);
1932 break;
1933 case XML_RELAXNG_ERR_LIST:
1934 return(xmlCharStrdup("Error validating list"));
1935 case XML_RELAXNG_ERR_NOGRAMMAR:
1936 return(xmlCharStrdup("No top grammar defined"));
1937 case XML_RELAXNG_ERR_EXTRADATA:
1938 return(xmlCharStrdup("Extra data in the document"));
1939 default:
1940 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001941 }
1942 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001943 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001944 }
1945 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001946 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001947}
1948
1949/**
1950 * xmlRelaxNGValidErrorContext:
1951 * @ctxt: the validation context
1952 * @node: the node
1953 * @child: the node child generating the problem.
1954 *
1955 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001956 */
1957static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001958xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1959 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001960{
1961 int line = 0;
1962 const xmlChar *file = NULL;
1963 const xmlChar *name = NULL;
1964 const char *type = "error";
1965
1966 if ((ctxt == NULL) || (ctxt->error == NULL))
1967 return;
1968
1969 if (child != NULL)
1970 node = child;
1971
1972 if (node != NULL) {
1973 if ((node->type == XML_DOCUMENT_NODE) ||
1974 (node->type == XML_HTML_DOCUMENT_NODE)) {
1975 xmlDocPtr doc = (xmlDocPtr) node;
1976
1977 file = doc->URL;
1978 } else {
1979 /*
1980 * Try to find contextual informations to report
1981 */
1982 if (node->type == XML_ELEMENT_NODE) {
1983 line = (int) node->content;
1984 } else if ((node->prev != NULL) &&
1985 (node->prev->type == XML_ELEMENT_NODE)) {
1986 line = (int) node->prev->content;
1987 } else if ((node->parent != NULL) &&
1988 (node->parent->type == XML_ELEMENT_NODE)) {
1989 line = (int) node->parent->content;
1990 }
1991 if ((node->doc != NULL) && (node->doc->URL != NULL))
1992 file = node->doc->URL;
1993 if (node->name != NULL)
1994 name = node->name;
1995 }
1996 }
1997
Daniel Veillard42f12e92003-03-07 18:32:59 +00001998 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00001999
2000 if ((file != NULL) && (line != 0) && (name != NULL))
2001 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2002 type, file, line, name);
2003 else if ((file != NULL) && (name != NULL))
2004 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2005 type, file, name);
2006 else if ((file != NULL) && (line != 0))
2007 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2008 else if (file != NULL)
2009 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2010 else if (name != NULL)
2011 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2012 else
2013 ctxt->error(ctxt->userData, "%s\n", type);
2014}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002015
2016/**
2017 * xmlRelaxNGShowValidError:
2018 * @ctxt: the validation context
2019 * @err: the error number
2020 * @node: the node
2021 * @child: the node child generating the problem.
2022 * @arg1: the first argument
2023 * @arg2: the second argument
2024 *
2025 * Show a validation error.
2026 */
2027static void
2028xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2029 xmlNodePtr node, xmlNodePtr child,
2030 const xmlChar *arg1, const xmlChar *arg2)
2031{
2032 xmlChar *msg;
2033
2034 if (ctxt->error == NULL)
2035 return;
2036
2037 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2038 if (msg == NULL)
2039 return;
2040
2041 xmlRelaxNGValidErrorContext(ctxt, node, child);
2042 ctxt->error(ctxt->userData, "%s\n", msg);
2043 xmlFree(msg);
2044}
2045
2046/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002047 * xmlRelaxNGPopErrors:
2048 * @ctxt: the validation context
2049 * @level: the error level in the stack
2050 *
2051 * pop and discard all errors until the given level is reached
2052 */
2053static void
2054xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2055 int i;
2056 xmlRelaxNGValidErrorPtr err;
2057
2058 for (i = level;i < ctxt->errNr;i++) {
2059 err = &ctxt->errTab[i];
2060 if (err->flags & ERROR_IS_DUP) {
2061 if (err->arg1 != NULL)
2062 xmlFree((xmlChar *)err->arg1);
2063 err->arg1 = NULL;
2064 if (err->arg2 != NULL)
2065 xmlFree((xmlChar *)err->arg2);
2066 err->arg2 = NULL;
2067 err->flags = 0;
2068 }
2069 }
2070 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002071 if (ctxt->errNr <= 0)
2072 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002073}
2074/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002075 * xmlRelaxNGDumpValidError:
2076 * @ctxt: the validation context
2077 *
2078 * Show all validation error over a given index.
2079 */
2080static void
2081xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002082 int i, j;
2083 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002084
2085 for (i = 0;i < ctxt->errNr;i++) {
2086 err = &ctxt->errTab[i];
Daniel Veillard580ced82003-03-21 21:22:48 +00002087 for (j = 0;j < i;j++) {
2088 dup = &ctxt->errTab[j];
2089 if ((err->err == dup->err) && (err->node == dup->node) &&
2090 (xmlStrEqual(err->arg1, dup->arg1)) &&
2091 (xmlStrEqual(err->arg2, dup->arg2))) {
2092 goto skip;
2093 }
2094 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002095 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2096 err->arg1, err->arg2);
Daniel Veillard580ced82003-03-21 21:22:48 +00002097skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002098 if (err->flags & ERROR_IS_DUP) {
2099 if (err->arg1 != NULL)
2100 xmlFree((xmlChar *)err->arg1);
2101 err->arg1 = NULL;
2102 if (err->arg2 != NULL)
2103 xmlFree((xmlChar *)err->arg2);
2104 err->arg2 = NULL;
2105 err->flags = 0;
2106 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002107 }
2108 ctxt->errNr = 0;
2109}
2110/**
2111 * xmlRelaxNGAddValidError:
2112 * @ctxt: the validation context
2113 * @err: the error number
2114 * @arg1: the first argument
2115 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002116 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002117 *
2118 * Register a validation error, either generating it if it's sure
2119 * or stacking it for later handling if unsure.
2120 */
2121static void
2122xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002123 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002124{
2125 if ((ctxt == NULL) || (ctxt->error == NULL))
2126 return;
2127
2128 /*
2129 * generate the error directly
2130 */
2131 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2132 xmlNodePtr node, seq;
2133 /*
2134 * Flush first any stacked error which might be the
2135 * real cause of the problem.
2136 */
2137 if (ctxt->errNr != 0)
2138 xmlRelaxNGDumpValidError(ctxt);
2139 if (ctxt->state != NULL) {
2140 node = ctxt->state->node;
2141 seq = ctxt->state->seq;
2142 } else {
2143 node = seq = NULL;
2144 }
2145 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2146 }
2147 /*
2148 * Stack the error for later processing if needed
2149 */
2150 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002151 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002152 }
2153}
2154
Daniel Veillard6eadf632003-01-23 18:29:16 +00002155
2156/************************************************************************
2157 * *
2158 * Type library hooks *
2159 * *
2160 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002161static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2162 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002163
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002164/**
2165 * xmlRelaxNGSchemaTypeHave:
2166 * @data: data needed for the library
2167 * @type: the type name
2168 *
2169 * Check if the given type is provided by
2170 * the W3C XMLSchema Datatype library.
2171 *
2172 * Returns 1 if yes, 0 if no and -1 in case of error.
2173 */
2174static int
2175xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002176 const xmlChar *type) {
2177 xmlSchemaTypePtr typ;
2178
2179 if (type == NULL)
2180 return(-1);
2181 typ = xmlSchemaGetPredefinedType(type,
2182 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2183 if (typ == NULL)
2184 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002185 return(1);
2186}
2187
2188/**
2189 * xmlRelaxNGSchemaTypeCheck:
2190 * @data: data needed for the library
2191 * @type: the type name
2192 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002193 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002194 *
2195 * Check if the given type and value are validated by
2196 * the W3C XMLSchema Datatype library.
2197 *
2198 * Returns 1 if yes, 0 if no and -1 in case of error.
2199 */
2200static int
2201xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002202 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002203 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002204 void **result,
2205 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002206 xmlSchemaTypePtr typ;
2207 int ret;
2208
2209 /*
2210 * TODO: the type should be cached ab provided back, interface subject
2211 * to changes.
2212 * TODO: handle facets, may require an additional interface and keep
2213 * the value returned from the validation.
2214 */
2215 if ((type == NULL) || (value == NULL))
2216 return(-1);
2217 typ = xmlSchemaGetPredefinedType(type,
2218 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2219 if (typ == NULL)
2220 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002221 ret = xmlSchemaValPredefTypeNode(typ, value,
2222 (xmlSchemaValPtr *) result, node);
2223 if (ret == 2) /* special ID error code */
2224 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002225 if (ret == 0)
2226 return(1);
2227 if (ret > 0)
2228 return(0);
2229 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002230}
2231
2232/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002233 * xmlRelaxNGSchemaFacetCheck:
2234 * @data: data needed for the library
2235 * @type: the type name
2236 * @facet: the facet name
2237 * @val: the facet value
2238 * @strval: the string value
2239 * @value: the value to check
2240 *
2241 * Function provided by a type library to check a value facet
2242 *
2243 * Returns 1 if yes, 0 if no and -1 in case of error.
2244 */
2245static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002246xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002247 const xmlChar *facetname, const xmlChar *val,
2248 const xmlChar *strval, void *value) {
2249 xmlSchemaFacetPtr facet;
2250 xmlSchemaTypePtr typ;
2251 int ret;
2252
2253 if ((type == NULL) || (strval == NULL))
2254 return(-1);
2255 typ = xmlSchemaGetPredefinedType(type,
2256 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2257 if (typ == NULL)
2258 return(-1);
2259
2260 facet = xmlSchemaNewFacet();
2261 if (facet == NULL)
2262 return(-1);
2263
2264 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2265 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2266 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2267 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2268 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2269 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2270 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2271 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2272 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2273 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2274 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2275 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2276 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2277 facet->type = XML_SCHEMA_FACET_PATTERN;
2278 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2279 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2280 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2281 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2282 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2283 facet->type = XML_SCHEMA_FACET_LENGTH;
2284 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2285 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2286 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2287 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2288 } else {
2289 xmlSchemaFreeFacet(facet);
2290 return(-1);
2291 }
2292 facet->value = xmlStrdup(val);
2293 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2294 if (ret != 0) {
2295 xmlSchemaFreeFacet(facet);
2296 return(-1);
2297 }
2298 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2299 xmlSchemaFreeFacet(facet);
2300 if (ret != 0)
2301 return(-1);
2302 return(0);
2303}
2304
2305/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002306 * xmlRelaxNGSchemaTypeCompare:
2307 * @data: data needed for the library
2308 * @type: the type name
2309 * @value1: the first value
2310 * @value2: the second value
2311 *
2312 * Compare two values accordingly a type from the W3C XMLSchema
2313 * Datatype library.
2314 *
2315 * Returns 1 if yes, 0 if no and -1 in case of error.
2316 */
2317static int
2318xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2319 const xmlChar *type ATTRIBUTE_UNUSED,
2320 const xmlChar *value1 ATTRIBUTE_UNUSED,
2321 const xmlChar *value2 ATTRIBUTE_UNUSED) {
2322 TODO
2323 return(1);
2324}
2325
2326/**
2327 * xmlRelaxNGDefaultTypeHave:
2328 * @data: data needed for the library
2329 * @type: the type name
2330 *
2331 * Check if the given type is provided by
2332 * the default datatype library.
2333 *
2334 * Returns 1 if yes, 0 if no and -1 in case of error.
2335 */
2336static int
2337xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2338 if (type == NULL)
2339 return(-1);
2340 if (xmlStrEqual(type, BAD_CAST "string"))
2341 return(1);
2342 if (xmlStrEqual(type, BAD_CAST "token"))
2343 return(1);
2344 return(0);
2345}
2346
2347/**
2348 * xmlRelaxNGDefaultTypeCheck:
2349 * @data: data needed for the library
2350 * @type: the type name
2351 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002352 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002353 *
2354 * Check if the given type and value are validated by
2355 * the default datatype library.
2356 *
2357 * Returns 1 if yes, 0 if no and -1 in case of error.
2358 */
2359static int
2360xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2361 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002362 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002363 void **result ATTRIBUTE_UNUSED,
2364 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002365 if (value == NULL)
2366 return(-1);
2367 if (xmlStrEqual(type, BAD_CAST "string"))
2368 return(1);
2369 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002370 return(1);
2371 }
2372
2373 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002374}
2375
2376/**
2377 * xmlRelaxNGDefaultTypeCompare:
2378 * @data: data needed for the library
2379 * @type: the type name
2380 * @value1: the first value
2381 * @value2: the second value
2382 *
2383 * Compare two values accordingly a type from the default
2384 * datatype library.
2385 *
2386 * Returns 1 if yes, 0 if no and -1 in case of error.
2387 */
2388static int
2389xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2390 const xmlChar *type ATTRIBUTE_UNUSED,
2391 const xmlChar *value1 ATTRIBUTE_UNUSED,
2392 const xmlChar *value2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002393 int ret = -1;
2394
2395 if (xmlStrEqual(type, BAD_CAST "string")) {
2396 ret = xmlStrEqual(value1, value2);
2397 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2398 if (!xmlStrEqual(value1, value2)) {
2399 xmlChar *nval, *nvalue;
2400
2401 /*
2402 * TODO: trivial optimizations are possible by
2403 * computing at compile-time
2404 */
2405 nval = xmlRelaxNGNormalize(NULL, value1);
2406 nvalue = xmlRelaxNGNormalize(NULL, value2);
2407
Daniel Veillardd4310742003-02-18 21:12:46 +00002408 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002409 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002410 else if (xmlStrEqual(nval, nvalue))
2411 ret = 1;
2412 else
2413 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002414 if (nval != NULL)
2415 xmlFree(nval);
2416 if (nvalue != NULL)
2417 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002418 } else
2419 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002420 }
2421 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002422}
2423
2424static int xmlRelaxNGTypeInitialized = 0;
2425static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2426
2427/**
2428 * xmlRelaxNGFreeTypeLibrary:
2429 * @lib: the type library structure
2430 * @namespace: the URI bound to the library
2431 *
2432 * Free the structure associated to the type library
2433 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002434static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002435xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2436 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2437 if (lib == NULL)
2438 return;
2439 if (lib->namespace != NULL)
2440 xmlFree((xmlChar *)lib->namespace);
2441 xmlFree(lib);
2442}
2443
2444/**
2445 * xmlRelaxNGRegisterTypeLibrary:
2446 * @namespace: the URI bound to the library
2447 * @data: data associated to the library
2448 * @have: the provide function
2449 * @check: the checking function
2450 * @comp: the comparison function
2451 *
2452 * Register a new type library
2453 *
2454 * Returns 0 in case of success and -1 in case of error.
2455 */
2456static int
2457xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2458 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002459 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2460 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002461 xmlRelaxNGTypeLibraryPtr lib;
2462 int ret;
2463
2464 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2465 (check == NULL) || (comp == NULL))
2466 return(-1);
2467 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2468 xmlGenericError(xmlGenericErrorContext,
2469 "Relax-NG types library '%s' already registered\n",
2470 namespace);
2471 return(-1);
2472 }
2473 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2474 if (lib == NULL) {
2475 xmlGenericError(xmlGenericErrorContext,
2476 "Relax-NG types library '%s' malloc() failed\n",
2477 namespace);
2478 return (-1);
2479 }
2480 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2481 lib->namespace = xmlStrdup(namespace);
2482 lib->data = data;
2483 lib->have = have;
2484 lib->comp = comp;
2485 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002486 lib->facet = facet;
2487 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002488 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2489 if (ret < 0) {
2490 xmlGenericError(xmlGenericErrorContext,
2491 "Relax-NG types library failed to register '%s'\n",
2492 namespace);
2493 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2494 return(-1);
2495 }
2496 return(0);
2497}
2498
2499/**
2500 * xmlRelaxNGInitTypes:
2501 *
2502 * Initilize the default type libraries.
2503 *
2504 * Returns 0 in case of success and -1 in case of error.
2505 */
2506static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002507xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002508 if (xmlRelaxNGTypeInitialized != 0)
2509 return(0);
2510 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2511 if (xmlRelaxNGRegisteredTypes == NULL) {
2512 xmlGenericError(xmlGenericErrorContext,
2513 "Failed to allocate sh table for Relax-NG types\n");
2514 return(-1);
2515 }
2516 xmlRelaxNGRegisterTypeLibrary(
2517 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2518 NULL,
2519 xmlRelaxNGSchemaTypeHave,
2520 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002521 xmlRelaxNGSchemaTypeCompare,
2522 xmlRelaxNGSchemaFacetCheck,
2523 (xmlRelaxNGTypeFree) xmlSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002524 xmlRelaxNGRegisterTypeLibrary(
2525 xmlRelaxNGNs,
2526 NULL,
2527 xmlRelaxNGDefaultTypeHave,
2528 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002529 xmlRelaxNGDefaultTypeCompare,
2530 NULL,
2531 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002532 xmlRelaxNGTypeInitialized = 1;
2533 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002534}
2535
2536/**
2537 * xmlRelaxNGCleanupTypes:
2538 *
2539 * Cleanup the default Schemas type library associated to RelaxNG
2540 */
2541void
2542xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002543 if (xmlRelaxNGTypeInitialized == 0)
2544 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002545 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002546 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2547 xmlRelaxNGFreeTypeLibrary);
2548 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002549}
2550
2551/************************************************************************
2552 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002553 * Compiling element content into regexp *
2554 * *
2555 * Sometime the element content can be compiled into a pure regexp, *
2556 * This allows a faster execution and streamability at that level *
2557 * *
2558 ************************************************************************/
2559
2560/**
2561 * xmlRelaxNGIsCompileable:
2562 * @define: the definition to check
2563 *
2564 * Check if a definition is nullable.
2565 *
2566 * Returns 1 if yes, 0 if no and -1 in case of error
2567 */
2568static int
2569xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2570 if (def == NULL) {
2571 return(-1);
2572 }
2573 switch(def->type) {
2574 case XML_RELAXNG_REF:
2575 case XML_RELAXNG_EXTERNALREF:
2576 case XML_RELAXNG_PARENTREF:
2577 case XML_RELAXNG_NOOP:
2578 case XML_RELAXNG_START:
2579 return(xmlRelaxNGIsCompileable(def->content));
2580 case XML_RELAXNG_TEXT:
2581 case XML_RELAXNG_DATATYPE:
2582 case XML_RELAXNG_LIST:
2583 case XML_RELAXNG_PARAM:
2584 case XML_RELAXNG_VALUE:
2585
2586 case XML_RELAXNG_EMPTY:
2587 case XML_RELAXNG_ELEMENT:
2588 return(1);
2589 case XML_RELAXNG_OPTIONAL:
2590 case XML_RELAXNG_ZEROORMORE:
2591 case XML_RELAXNG_ONEORMORE:
2592 case XML_RELAXNG_CHOICE:
2593 case XML_RELAXNG_GROUP:
2594 case XML_RELAXNG_DEF: {
2595 xmlRelaxNGDefinePtr list;
2596 int ret;
2597
2598 list = def->content;
2599 while (list != NULL) {
2600 ret = xmlRelaxNGIsCompileable(list);
2601 if (ret != 1)
2602 return(ret);
2603 list = list->next;
2604 }
2605 return(1);
2606 }
2607 case XML_RELAXNG_EXCEPT:
2608 case XML_RELAXNG_ATTRIBUTE:
2609 case XML_RELAXNG_INTERLEAVE:
2610 return(0);
2611 case XML_RELAXNG_NOT_ALLOWED:
2612 return(-1);
2613 }
2614 return(-1);
2615}
2616
2617/************************************************************************
2618 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002619 * Parsing functions *
2620 * *
2621 ************************************************************************/
2622
2623static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2624 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2625static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2626 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2627static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002628 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002629static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2630 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002631static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2632 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002633static int xmlRelaxNGParseGrammarContent(
2634 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002635static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2636 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2637 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002638static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2639 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002640static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2641 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002642
2643
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002644#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002645
2646/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002647 * xmlRelaxNGIsNullable:
2648 * @define: the definition to verify
2649 *
2650 * Check if a definition is nullable.
2651 *
2652 * Returns 1 if yes, 0 if no and -1 in case of error
2653 */
2654static int
2655xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2656 int ret;
2657 if (define == NULL)
2658 return(-1);
2659
Daniel Veillarde063f482003-03-21 16:53:17 +00002660 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002661 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002662 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002663 return(0);
2664 switch (define->type) {
2665 case XML_RELAXNG_EMPTY:
2666 case XML_RELAXNG_TEXT:
2667 ret = 1; break;
2668 case XML_RELAXNG_NOOP:
2669 case XML_RELAXNG_DEF:
2670 case XML_RELAXNG_REF:
2671 case XML_RELAXNG_EXTERNALREF:
2672 case XML_RELAXNG_PARENTREF:
2673 case XML_RELAXNG_ONEORMORE:
2674 ret = xmlRelaxNGIsNullable(define->content);
2675 break;
2676 case XML_RELAXNG_EXCEPT:
2677 case XML_RELAXNG_NOT_ALLOWED:
2678 case XML_RELAXNG_ELEMENT:
2679 case XML_RELAXNG_DATATYPE:
2680 case XML_RELAXNG_PARAM:
2681 case XML_RELAXNG_VALUE:
2682 case XML_RELAXNG_LIST:
2683 case XML_RELAXNG_ATTRIBUTE:
2684 ret = 0; break;
2685 case XML_RELAXNG_CHOICE: {
2686 xmlRelaxNGDefinePtr list = define->content;
2687
2688 while (list != NULL) {
2689 ret = xmlRelaxNGIsNullable(list);
2690 if (ret != 0)
2691 goto done;
2692 list = list->next;
2693 }
2694 ret = 0; break;
2695 }
2696 case XML_RELAXNG_START:
2697 case XML_RELAXNG_INTERLEAVE:
2698 case XML_RELAXNG_GROUP: {
2699 xmlRelaxNGDefinePtr list = define->content;
2700
2701 while (list != NULL) {
2702 ret = xmlRelaxNGIsNullable(list);
2703 if (ret != 1)
2704 goto done;
2705 list = list->next;
2706 }
2707 return(1);
2708 }
2709 default:
2710 return(-1);
2711 }
2712done:
2713 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002714 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002715 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002716 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002717 return(ret);
2718}
2719
2720/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002721 * xmlRelaxNGIsBlank:
2722 * @str: a string
2723 *
2724 * Check if a string is ignorable c.f. 4.2. Whitespace
2725 *
2726 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2727 */
2728static int
2729xmlRelaxNGIsBlank(xmlChar *str) {
2730 if (str == NULL)
2731 return(1);
2732 while (*str != 0) {
2733 if (!(IS_BLANK(*str))) return(0);
2734 str++;
2735 }
2736 return(1);
2737}
2738
Daniel Veillard6eadf632003-01-23 18:29:16 +00002739/**
2740 * xmlRelaxNGGetDataTypeLibrary:
2741 * @ctxt: a Relax-NG parser context
2742 * @node: the current data or value element
2743 *
2744 * Applies algorithm from 4.3. datatypeLibrary attribute
2745 *
2746 * Returns the datatypeLibary value or NULL if not found
2747 */
2748static xmlChar *
2749xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2750 xmlNodePtr node) {
2751 xmlChar *ret, *escape;
2752
Daniel Veillard6eadf632003-01-23 18:29:16 +00002753 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2754 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2755 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002756 if (ret[0] == 0) {
2757 xmlFree(ret);
2758 return(NULL);
2759 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002760 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002761 if (escape == NULL) {
2762 return(ret);
2763 }
2764 xmlFree(ret);
2765 return(escape);
2766 }
2767 }
2768 node = node->parent;
2769 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002770 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2771 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002772 if (ret[0] == 0) {
2773 xmlFree(ret);
2774 return(NULL);
2775 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002776 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2777 if (escape == NULL) {
2778 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002779 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002780 xmlFree(ret);
2781 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002782 }
2783 node = node->parent;
2784 }
2785 return(NULL);
2786}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002787
2788/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002789 * xmlRelaxNGParseValue:
2790 * @ctxt: a Relax-NG parser context
2791 * @node: the data node.
2792 *
2793 * parse the content of a RelaxNG value node.
2794 *
2795 * Returns the definition pointer or NULL in case of error
2796 */
2797static xmlRelaxNGDefinePtr
2798xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2799 xmlRelaxNGDefinePtr def = NULL;
2800 xmlRelaxNGTypeLibraryPtr lib;
2801 xmlChar *type;
2802 xmlChar *library;
2803 int tmp;
2804
Daniel Veillardfd573f12003-03-16 17:52:32 +00002805 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002806 if (def == NULL)
2807 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002808 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002809
2810 type = xmlGetProp(node, BAD_CAST "type");
2811 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002812 xmlRelaxNGNormExtSpace(type);
2813 if (xmlValidateNCName(type, 0)) {
2814 if (ctxt->error != NULL)
2815 ctxt->error(ctxt->userData,
2816 "value type '%s' is not an NCName\n",
2817 type);
2818 ctxt->nbErrors++;
2819 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002820 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2821 if (library == NULL)
2822 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2823
2824 def->name = type;
2825 def->ns = library;
2826
2827 lib = (xmlRelaxNGTypeLibraryPtr)
2828 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2829 if (lib == NULL) {
2830 if (ctxt->error != NULL)
2831 ctxt->error(ctxt->userData,
2832 "Use of unregistered type library '%s'\n",
2833 library);
2834 ctxt->nbErrors++;
2835 def->data = NULL;
2836 } else {
2837 def->data = lib;
2838 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002839 if (ctxt->error != NULL)
2840 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002841 "Internal error with type library '%s': no 'have'\n",
2842 library);
2843 ctxt->nbErrors++;
2844 } else {
2845 tmp = lib->have(lib->data, def->name);
2846 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002847 if (ctxt->error != NULL)
2848 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002849 "Error type '%s' is not exported by type library '%s'\n",
2850 def->name, library);
2851 ctxt->nbErrors++;
2852 }
2853 }
2854 }
2855 }
2856 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002857 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002858 } else if (((node->children->type != XML_TEXT_NODE) &&
2859 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002860 (node->children->next != NULL)) {
2861 if (ctxt->error != NULL)
2862 ctxt->error(ctxt->userData,
2863 "Expecting a single text value for <value>content\n");
2864 ctxt->nbErrors++;
2865 } else {
2866 def->value = xmlNodeGetContent(node);
2867 if (def->value == NULL) {
2868 if (ctxt->error != NULL)
2869 ctxt->error(ctxt->userData,
2870 "Element <value> has no content\n");
2871 ctxt->nbErrors++;
2872 }
2873 }
2874 /* TODO check ahead of time that the value is okay per the type */
2875 return(def);
2876}
2877
2878/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002879 * xmlRelaxNGParseData:
2880 * @ctxt: a Relax-NG parser context
2881 * @node: the data node.
2882 *
2883 * parse the content of a RelaxNG data node.
2884 *
2885 * Returns the definition pointer or NULL in case of error
2886 */
2887static xmlRelaxNGDefinePtr
2888xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002889 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002890 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002891 xmlRelaxNGTypeLibraryPtr lib;
2892 xmlChar *type;
2893 xmlChar *library;
2894 xmlNodePtr content;
2895 int tmp;
2896
2897 type = xmlGetProp(node, BAD_CAST "type");
2898 if (type == NULL) {
2899 if (ctxt->error != NULL)
2900 ctxt->error(ctxt->userData,
2901 "data has no type\n");
2902 ctxt->nbErrors++;
2903 return(NULL);
2904 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002905 xmlRelaxNGNormExtSpace(type);
2906 if (xmlValidateNCName(type, 0)) {
2907 if (ctxt->error != NULL)
2908 ctxt->error(ctxt->userData,
2909 "data type '%s' is not an NCName\n",
2910 type);
2911 ctxt->nbErrors++;
2912 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002913 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2914 if (library == NULL)
2915 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2916
Daniel Veillardfd573f12003-03-16 17:52:32 +00002917 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002918 if (def == NULL) {
2919 xmlFree(type);
2920 return(NULL);
2921 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00002922 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002923 def->name = type;
2924 def->ns = library;
2925
2926 lib = (xmlRelaxNGTypeLibraryPtr)
2927 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2928 if (lib == NULL) {
2929 if (ctxt->error != NULL)
2930 ctxt->error(ctxt->userData,
2931 "Use of unregistered type library '%s'\n",
2932 library);
2933 ctxt->nbErrors++;
2934 def->data = NULL;
2935 } else {
2936 def->data = lib;
2937 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002938 if (ctxt->error != NULL)
2939 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002940 "Internal error with type library '%s': no 'have'\n",
2941 library);
2942 ctxt->nbErrors++;
2943 } else {
2944 tmp = lib->have(lib->data, def->name);
2945 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002946 if (ctxt->error != NULL)
2947 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002948 "Error type '%s' is not exported by type library '%s'\n",
2949 def->name, library);
2950 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002951 } else if ((xmlStrEqual(library, BAD_CAST
2952 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
2953 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
2954 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
2955 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002956 }
2957 }
2958 }
2959 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00002960
2961 /*
2962 * Handle optional params
2963 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002964 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002965 if (!xmlStrEqual(content->name, BAD_CAST "param"))
2966 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002967 if (xmlStrEqual(library,
2968 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
2969 if (ctxt->error != NULL)
2970 ctxt->error(ctxt->userData,
2971 "Type library '%s' does not allow type parameters\n",
2972 library);
2973 ctxt->nbErrors++;
2974 content = content->next;
2975 while ((content != NULL) &&
2976 (xmlStrEqual(content->name, BAD_CAST "param")))
2977 content = content->next;
2978 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002979 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002980 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002981 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002982 param->name = xmlGetProp(content, BAD_CAST "name");
2983 if (param->name == NULL) {
2984 if (ctxt->error != NULL)
2985 ctxt->error(ctxt->userData,
2986 "param has no name\n");
2987 ctxt->nbErrors++;
2988 }
2989 param->value = xmlNodeGetContent(content);
2990 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00002991 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002992 } else {
2993 lastparam->next = param;
2994 lastparam = param;
2995 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002996 if (lib != NULL) {
2997 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00002998 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00002999 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003000 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003001 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003002 /*
3003 * Handle optional except
3004 */
3005 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3006 xmlNodePtr child;
3007 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3008
Daniel Veillardfd573f12003-03-16 17:52:32 +00003009 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003010 if (except == NULL) {
3011 return(def);
3012 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003013 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003014 child = content->children;
3015 if (last == NULL) {
3016 def->content = except;
3017 } else {
3018 last->next = except;
3019 }
3020 if (child == NULL) {
3021 if (ctxt->error != NULL)
3022 ctxt->error(ctxt->userData,
3023 "except has no content\n");
3024 ctxt->nbErrors++;
3025 }
3026 while (child != NULL) {
3027 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3028 if (tmp2 != NULL) {
3029 if (last2 == NULL) {
3030 except->content = last2 = tmp2;
3031 } else {
3032 last2->next = tmp2;
3033 last2 = tmp2;
3034 }
3035 }
3036 child = child->next;
3037 }
3038 content = content->next;
3039 }
3040 /*
3041 * Check there is no unhandled data
3042 */
3043 if (content != NULL) {
3044 if (ctxt->error != NULL)
3045 ctxt->error(ctxt->userData,
3046 "Element data has unexpected content %s\n", content->name);
3047 ctxt->nbErrors++;
3048 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003049
3050 return(def);
3051}
3052
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003053static const xmlChar *invalidName = BAD_CAST "\1";
3054
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003055/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003056 * xmlRelaxNGCompareNameClasses:
3057 * @defs1: the first element/attribute defs
3058 * @defs2: the second element/attribute defs
3059 * @name: the restriction on the name
3060 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003061 *
3062 * Compare the 2 lists of element definitions. The comparison is
3063 * that if both lists do not accept the same QNames, it returns 1
3064 * If the 2 lists can accept the same QName the comparison returns 0
3065 *
3066 * Returns 1 disttinct, 0 if equal
3067 */
3068static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003069xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3070 xmlRelaxNGDefinePtr def2) {
3071 int ret = 1;
3072 xmlNode node;
3073 xmlNs ns;
3074 xmlRelaxNGValidCtxt ctxt;
3075 ctxt.flags = FLAGS_IGNORABLE;
3076
Daniel Veillard42f12e92003-03-07 18:32:59 +00003077 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3078
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003079 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3080 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3081 if (def2->type == XML_RELAXNG_TEXT)
3082 return(1);
3083 if (def1->name != NULL) {
3084 node.name = def1->name;
3085 } else {
3086 node.name = invalidName;
3087 }
3088 node.ns = &ns;
3089 if (def1->ns != NULL) {
3090 if (def1->ns[0] == 0) {
3091 node.ns = NULL;
3092 } else {
3093 ns.href = def1->ns;
3094 }
3095 } else {
3096 ns.href = invalidName;
3097 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003098 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003099 if (def1->nameClass != NULL) {
3100 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3101 } else {
3102 ret = 0;
3103 }
3104 } else {
3105 ret = 1;
3106 }
3107 } else if (def1->type == XML_RELAXNG_TEXT) {
3108 if (def2->type == XML_RELAXNG_TEXT)
3109 return(0);
3110 return(1);
3111 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003112 TODO
3113 ret = 0;
3114 } else {
3115 TODO
3116 ret = 0;
3117 }
3118 if (ret == 0)
3119 return(ret);
3120 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3121 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3122 if (def2->name != NULL) {
3123 node.name = def2->name;
3124 } else {
3125 node.name = invalidName;
3126 }
3127 node.ns = &ns;
3128 if (def2->ns != NULL) {
3129 if (def2->ns[0] == 0) {
3130 node.ns = NULL;
3131 } else {
3132 ns.href = def2->ns;
3133 }
3134 } else {
3135 ns.href = invalidName;
3136 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003137 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003138 if (def2->nameClass != NULL) {
3139 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3140 } else {
3141 ret = 0;
3142 }
3143 } else {
3144 ret = 1;
3145 }
3146 } else {
3147 TODO
3148 ret = 0;
3149 }
3150
3151 return(ret);
3152}
3153
3154/**
3155 * xmlRelaxNGCompareElemDefLists:
3156 * @ctxt: a Relax-NG parser context
3157 * @defs1: the first list of element/attribute defs
3158 * @defs2: the second list of element/attribute defs
3159 *
3160 * Compare the 2 lists of element or attribute definitions. The comparison
3161 * is that if both lists do not accept the same QNames, it returns 1
3162 * If the 2 lists can accept the same QName the comparison returns 0
3163 *
3164 * Returns 1 disttinct, 0 if equal
3165 */
3166static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003167xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3168 xmlRelaxNGDefinePtr *def1,
3169 xmlRelaxNGDefinePtr *def2) {
3170 xmlRelaxNGDefinePtr *basedef2 = def2;
3171
Daniel Veillard154877e2003-01-30 12:17:05 +00003172 if ((def1 == NULL) || (def2 == NULL))
3173 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003174 if ((*def1 == NULL) || (*def2 == NULL))
3175 return(1);
3176 while (*def1 != NULL) {
3177 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003178 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3179 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003180 def2++;
3181 }
3182 def2 = basedef2;
3183 def1++;
3184 }
3185 return(1);
3186}
3187
3188/**
3189 * xmlRelaxNGGetElements:
3190 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003191 * @def: the definition definition
3192 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003193 *
3194 * Compute the list of top elements a definition can generate
3195 *
3196 * Returns a list of elements or NULL if none was found.
3197 */
3198static xmlRelaxNGDefinePtr *
3199xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003200 xmlRelaxNGDefinePtr def,
3201 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003202 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003203 int len = 0;
3204 int max = 0;
3205
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003206 /*
3207 * Don't run that check in case of error. Infinite recursion
3208 * becomes possible.
3209 */
3210 if (ctxt->nbErrors != 0)
3211 return(NULL);
3212
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003213 parent = NULL;
3214 cur = def;
3215 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003216 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3217 (cur->type == XML_RELAXNG_TEXT))) ||
3218 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003219 if (ret == NULL) {
3220 max = 10;
3221 ret = (xmlRelaxNGDefinePtr *)
3222 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3223 if (ret == NULL) {
3224 if (ctxt->error != NULL)
3225 ctxt->error(ctxt->userData,
3226 "Out of memory in element search\n");
3227 ctxt->nbErrors++;
3228 return(NULL);
3229 }
3230 } else if (max <= len) {
3231 max *= 2;
3232 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3233 if (ret == NULL) {
3234 if (ctxt->error != NULL)
3235 ctxt->error(ctxt->userData,
3236 "Out of memory in element search\n");
3237 ctxt->nbErrors++;
3238 return(NULL);
3239 }
3240 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003241 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003242 ret[len] = NULL;
3243 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3244 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3245 (cur->type == XML_RELAXNG_GROUP) ||
3246 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003247 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3248 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003249 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003250 (cur->type == XML_RELAXNG_REF) ||
3251 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003252 /*
3253 * Don't go within elements or attributes or string values.
3254 * Just gather the element top list
3255 */
3256 if (cur->content != NULL) {
3257 parent = cur;
3258 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003259 tmp = cur;
3260 while (tmp != NULL) {
3261 tmp->parent = parent;
3262 tmp = tmp->next;
3263 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003264 continue;
3265 }
3266 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003267 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003268 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003269 if (cur->next != NULL) {
3270 cur = cur->next;
3271 continue;
3272 }
3273 do {
3274 cur = cur->parent;
3275 if (cur == NULL) break;
3276 if (cur == def) return(ret);
3277 if (cur->next != NULL) {
3278 cur = cur->next;
3279 break;
3280 }
3281 } while (cur != NULL);
3282 }
3283 return(ret);
3284}
3285
3286/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003287 * xmlRelaxNGCheckChoiceDeterminism:
3288 * @ctxt: a Relax-NG parser context
3289 * @def: the choice definition
3290 *
3291 * Also used to find indeterministic pattern in choice
3292 */
3293static void
3294xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3295 xmlRelaxNGDefinePtr def) {
3296 xmlRelaxNGDefinePtr **list;
3297 xmlRelaxNGDefinePtr cur;
3298 int nbchild = 0, i, j, ret;
3299 int is_nullable = 0;
3300 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003301 xmlHashTablePtr triage = NULL;
3302 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003303
3304 if ((def == NULL) ||
3305 (def->type != XML_RELAXNG_CHOICE))
3306 return;
3307
Daniel Veillarde063f482003-03-21 16:53:17 +00003308 if (def->dflags & IS_PROCESSED)
3309 return;
3310
Daniel Veillardfd573f12003-03-16 17:52:32 +00003311 /*
3312 * Don't run that check in case of error. Infinite recursion
3313 * becomes possible.
3314 */
3315 if (ctxt->nbErrors != 0)
3316 return;
3317
3318 is_nullable = xmlRelaxNGIsNullable(def);
3319
3320 cur = def->content;
3321 while (cur != NULL) {
3322 nbchild++;
3323 cur = cur->next;
3324 }
3325
3326 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3327 sizeof(xmlRelaxNGDefinePtr *));
3328 if (list == NULL) {
3329 if (ctxt->error != NULL)
3330 ctxt->error(ctxt->userData,
3331 "Out of memory in choice computation\n");
3332 ctxt->nbErrors++;
3333 return;
3334 }
3335 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003336 /*
3337 * a bit strong but safe
3338 */
3339 if (is_nullable == 0) {
3340 triage = xmlHashCreate(10);
3341 } else {
3342 is_triable = 0;
3343 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003344 cur = def->content;
3345 while (cur != NULL) {
3346 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003347 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3348 is_triable = 0;
3349 } else if (is_triable == 1) {
3350 xmlRelaxNGDefinePtr *tmp;
3351 int res;
3352
3353 tmp = list[i];
3354 while ((*tmp != NULL) && (is_triable == 1)) {
3355 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3356 res = xmlHashAddEntry2(triage,
3357 BAD_CAST "#text", NULL,
3358 (void *)cur);
3359 if (res != 0)
3360 is_triable = -1;
3361 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3362 ((*tmp)->name != NULL)) {
3363 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3364 res = xmlHashAddEntry2(triage,
3365 (*tmp)->name, NULL,
3366 (void *)cur);
3367 else
3368 res = xmlHashAddEntry2(triage,
3369 (*tmp)->name, (*tmp)->ns,
3370 (void *)cur);
3371 if (res != 0)
3372 is_triable = -1;
3373 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3374 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3375 res = xmlHashAddEntry2(triage,
3376 BAD_CAST "#any", NULL,
3377 (void *)cur);
3378 else
3379 res = xmlHashAddEntry2(triage,
3380 BAD_CAST "#any", (*tmp)->ns,
3381 (void *)cur);
3382 if (res != 0)
3383 is_triable = -1;
3384 } else {
3385 is_triable = -1;
3386 }
3387 tmp++;
3388 }
3389 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003390 i++;
3391 cur = cur->next;
3392 }
3393
3394 for (i = 0;i < nbchild;i++) {
3395 if (list[i] == NULL)
3396 continue;
3397 for (j = 0;j < i;j++) {
3398 if (list[j] == NULL)
3399 continue;
3400 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3401 if (ret == 0) {
3402 is_indeterminist = 1;
3403 }
3404 }
3405 }
3406 for (i = 0;i < nbchild;i++) {
3407 if (list[i] != NULL)
3408 xmlFree(list[i]);
3409 }
3410
3411 xmlFree(list);
3412 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003413 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003414 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003415 if (is_triable == 1) {
3416 def->dflags |= IS_TRIABLE;
3417 def->data = triage;
3418 } else if (triage != NULL) {
3419 xmlHashFree(triage, NULL);
3420 }
3421 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003422}
3423
3424/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003425 * xmlRelaxNGCheckGroupAttrs:
3426 * @ctxt: a Relax-NG parser context
3427 * @def: the group definition
3428 *
3429 * Detects violations of rule 7.3
3430 */
3431static void
3432xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3433 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003434 xmlRelaxNGDefinePtr **list;
3435 xmlRelaxNGDefinePtr cur;
3436 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003437
3438 if ((def == NULL) ||
3439 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003440 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003441 return;
3442
Daniel Veillarde063f482003-03-21 16:53:17 +00003443 if (def->dflags & IS_PROCESSED)
3444 return;
3445
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003446 /*
3447 * Don't run that check in case of error. Infinite recursion
3448 * becomes possible.
3449 */
3450 if (ctxt->nbErrors != 0)
3451 return;
3452
Daniel Veillardfd573f12003-03-16 17:52:32 +00003453 cur = def->attrs;
3454 while (cur != NULL) {
3455 nbchild++;
3456 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003457 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003458 cur = def->content;
3459 while (cur != NULL) {
3460 nbchild++;
3461 cur = cur->next;
3462 }
3463
3464 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3465 sizeof(xmlRelaxNGDefinePtr *));
3466 if (list == NULL) {
3467 if (ctxt->error != NULL)
3468 ctxt->error(ctxt->userData,
3469 "Out of memory in group computation\n");
3470 ctxt->nbErrors++;
3471 return;
3472 }
3473 i = 0;
3474 cur = def->attrs;
3475 while (cur != NULL) {
3476 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3477 i++;
3478 cur = cur->next;
3479 }
3480 cur = def->content;
3481 while (cur != NULL) {
3482 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3483 i++;
3484 cur = cur->next;
3485 }
3486
3487 for (i = 0;i < nbchild;i++) {
3488 if (list[i] == NULL)
3489 continue;
3490 for (j = 0;j < i;j++) {
3491 if (list[j] == NULL)
3492 continue;
3493 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3494 if (ret == 0) {
3495 if (ctxt->error != NULL)
3496 ctxt->error(ctxt->userData,
3497 "Attributes conflicts in group\n");
3498 ctxt->nbErrors++;
3499 }
3500 }
3501 }
3502 for (i = 0;i < nbchild;i++) {
3503 if (list[i] != NULL)
3504 xmlFree(list[i]);
3505 }
3506
3507 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003508 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003509}
3510
3511/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003512 * xmlRelaxNGComputeInterleaves:
3513 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003514 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003515 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003516 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003517 * A lot of work for preprocessing interleave definitions
3518 * is potentially needed to get a decent execution speed at runtime
3519 * - trying to get a total order on the element nodes generated
3520 * by the interleaves, order the list of interleave definitions
3521 * following that order.
3522 * - if <text/> is used to handle mixed content, it is better to
3523 * flag this in the define and simplify the runtime checking
3524 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003525 */
3526static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003527xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3528 xmlRelaxNGParserCtxtPtr ctxt,
3529 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003530 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003531
Daniel Veillardfd573f12003-03-16 17:52:32 +00003532 xmlRelaxNGPartitionPtr partitions = NULL;
3533 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3534 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003535 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003536 int nbgroups = 0;
3537 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003538 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003539 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003540
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003541 /*
3542 * Don't run that check in case of error. Infinite recursion
3543 * becomes possible.
3544 */
3545 if (ctxt->nbErrors != 0)
3546 return;
3547
Daniel Veillardfd573f12003-03-16 17:52:32 +00003548#ifdef DEBUG_INTERLEAVE
3549 xmlGenericError(xmlGenericErrorContext,
3550 "xmlRelaxNGComputeInterleaves(%s)\n",
3551 name);
3552#endif
3553 cur = def->content;
3554 while (cur != NULL) {
3555 nbchild++;
3556 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003557 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003558
3559#ifdef DEBUG_INTERLEAVE
3560 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3561#endif
3562 groups = (xmlRelaxNGInterleaveGroupPtr *)
3563 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3564 if (groups == NULL)
3565 goto error;
3566 cur = def->content;
3567 while (cur != NULL) {
3568 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3569 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3570 if (groups[nbgroups] == NULL)
3571 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003572 if (cur->type == XML_RELAXNG_TEXT)
3573 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003574 groups[nbgroups]->rule = cur;
3575 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3576 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3577 nbgroups++;
3578 cur = cur->next;
3579 }
3580#ifdef DEBUG_INTERLEAVE
3581 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3582#endif
3583
3584 /*
3585 * Let's check that all rules makes a partitions according to 7.4
3586 */
3587 partitions = (xmlRelaxNGPartitionPtr)
3588 xmlMalloc(sizeof(xmlRelaxNGPartition));
3589 if (partitions == NULL)
3590 goto error;
3591 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003592 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003593 for (i = 0;i < nbgroups;i++) {
3594 group = groups[i];
3595 for (j = i+1;j < nbgroups;j++) {
3596 if (groups[j] == NULL)
3597 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003598
Daniel Veillardfd573f12003-03-16 17:52:32 +00003599 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3600 groups[j]->defs);
3601 if (ret == 0) {
3602 if (ctxt->error != NULL)
3603 ctxt->error(ctxt->userData,
3604 "Element or text conflicts in interleave\n");
3605 ctxt->nbErrors++;
3606 }
3607 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3608 groups[j]->attrs);
3609 if (ret == 0) {
3610 if (ctxt->error != NULL)
3611 ctxt->error(ctxt->userData,
3612 "Attributes conflicts in interleave\n");
3613 ctxt->nbErrors++;
3614 }
3615 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003616 tmp = group->defs;
3617 if ((tmp != NULL) && (*tmp != NULL)) {
3618 while (*tmp != NULL) {
3619 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3620 res = xmlHashAddEntry2(partitions->triage,
3621 BAD_CAST "#text", NULL,
3622 (void *)(i + 1));
3623 if (res != 0)
3624 is_determinist = -1;
3625 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3626 ((*tmp)->name != NULL)) {
3627 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3628 res = xmlHashAddEntry2(partitions->triage,
3629 (*tmp)->name, NULL,
3630 (void *)(i + 1));
3631 else
3632 res = xmlHashAddEntry2(partitions->triage,
3633 (*tmp)->name, (*tmp)->ns,
3634 (void *)(i + 1));
3635 if (res != 0)
3636 is_determinist = -1;
3637 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3638 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3639 res = xmlHashAddEntry2(partitions->triage,
3640 BAD_CAST "#any", NULL,
3641 (void *)(i + 1));
3642 else
3643 res = xmlHashAddEntry2(partitions->triage,
3644 BAD_CAST "#any", (*tmp)->ns,
3645 (void *)(i + 1));
3646 if ((*tmp)->nameClass != NULL)
3647 is_determinist = 2;
3648 if (res != 0)
3649 is_determinist = -1;
3650 } else {
3651 is_determinist = -1;
3652 }
3653 tmp++;
3654 }
3655 } else {
3656 is_determinist = 0;
3657 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003658 }
3659 partitions->groups = groups;
3660
3661 /*
3662 * and save the partition list back in the def
3663 */
3664 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003665 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003666 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003667 if (is_determinist == 1)
3668 partitions->flags = IS_DETERMINIST;
3669 if (is_determinist == 2)
3670 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003671 return;
3672
3673error:
3674 if (ctxt->error != NULL)
3675 ctxt->error(ctxt->userData,
3676 "Out of memory in interleave computation\n");
3677 ctxt->nbErrors++;
3678 if (groups != NULL) {
3679 for (i = 0;i < nbgroups;i++)
3680 if (groups[i] != NULL) {
3681 if (groups[i]->defs != NULL)
3682 xmlFree(groups[i]->defs);
3683 xmlFree(groups[i]);
3684 }
3685 xmlFree(groups);
3686 }
3687 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003688}
3689
3690/**
3691 * xmlRelaxNGParseInterleave:
3692 * @ctxt: a Relax-NG parser context
3693 * @node: the data node.
3694 *
3695 * parse the content of a RelaxNG interleave node.
3696 *
3697 * Returns the definition pointer or NULL in case of error
3698 */
3699static xmlRelaxNGDefinePtr
3700xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3701 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003702 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003703 xmlNodePtr child;
3704
Daniel Veillardfd573f12003-03-16 17:52:32 +00003705 def = xmlRelaxNGNewDefine(ctxt, node);
3706 if (def == NULL) {
3707 return(NULL);
3708 }
3709 def->type = XML_RELAXNG_INTERLEAVE;
3710
3711 if (ctxt->interleaves == NULL)
3712 ctxt->interleaves = xmlHashCreate(10);
3713 if (ctxt->interleaves == NULL) {
3714 if (ctxt->error != NULL)
3715 ctxt->error(ctxt->userData,
3716 "Failed to create interleaves hash table\n");
3717 ctxt->nbErrors++;
3718 } else {
3719 char name[32];
3720
3721 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3722 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3723 if (ctxt->error != NULL)
3724 ctxt->error(ctxt->userData,
3725 "Failed to add %s to hash table\n", name);
3726 ctxt->nbErrors++;
3727 }
3728 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003729 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003730 if (child == NULL) {
3731 if (ctxt->error != NULL)
3732 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3733 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003734 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003735 while (child != NULL) {
3736 if (IS_RELAXNG(child, "element")) {
3737 cur = xmlRelaxNGParseElement(ctxt, child);
3738 } else {
3739 cur = xmlRelaxNGParsePattern(ctxt, child);
3740 }
3741 if (cur != NULL) {
3742 cur->parent = def;
3743 if (last == NULL) {
3744 def->content = last = cur;
3745 } else {
3746 last->next = cur;
3747 last = cur;
3748 }
3749 }
3750 child = child->next;
3751 }
3752
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003753 return(def);
3754}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003755
3756/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003757 * xmlRelaxNGParseInclude:
3758 * @ctxt: a Relax-NG parser context
3759 * @node: the include node
3760 *
3761 * Integrate the content of an include node in the current grammar
3762 *
3763 * Returns 0 in case of success or -1 in case of error
3764 */
3765static int
3766xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3767 xmlRelaxNGIncludePtr incl;
3768 xmlNodePtr root;
3769 int ret = 0, tmp;
3770
3771 incl = node->_private;
3772 if (incl == NULL) {
3773 if (ctxt->error != NULL)
3774 ctxt->error(ctxt->userData,
3775 "Include node has no data\n");
3776 ctxt->nbErrors++;
3777 return(-1);
3778 }
3779 root = xmlDocGetRootElement(incl->doc);
3780 if (root == NULL) {
3781 if (ctxt->error != NULL)
3782 ctxt->error(ctxt->userData,
3783 "Include document is empty\n");
3784 ctxt->nbErrors++;
3785 return(-1);
3786 }
3787 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3788 if (ctxt->error != NULL)
3789 ctxt->error(ctxt->userData,
3790 "Include document root is not a grammar\n");
3791 ctxt->nbErrors++;
3792 return(-1);
3793 }
3794
3795 /*
3796 * Merge the definition from both the include and the internal list
3797 */
3798 if (root->children != NULL) {
3799 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3800 if (tmp != 0)
3801 ret = -1;
3802 }
3803 if (node->children != NULL) {
3804 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3805 if (tmp != 0)
3806 ret = -1;
3807 }
3808 return(ret);
3809}
3810
3811/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003812 * xmlRelaxNGParseDefine:
3813 * @ctxt: a Relax-NG parser context
3814 * @node: the define node
3815 *
3816 * parse the content of a RelaxNG define element node.
3817 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003818 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003819 */
3820static int
3821xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3822 xmlChar *name;
3823 int ret = 0, tmp;
3824 xmlRelaxNGDefinePtr def;
3825 const xmlChar *olddefine;
3826
3827 name = xmlGetProp(node, BAD_CAST "name");
3828 if (name == NULL) {
3829 if (ctxt->error != NULL)
3830 ctxt->error(ctxt->userData,
3831 "define has no name\n");
3832 ctxt->nbErrors++;
3833 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003834 xmlRelaxNGNormExtSpace(name);
3835 if (xmlValidateNCName(name, 0)) {
3836 if (ctxt->error != NULL)
3837 ctxt->error(ctxt->userData,
3838 "define name '%s' is not an NCName\n",
3839 name);
3840 ctxt->nbErrors++;
3841 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003842 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003843 if (def == NULL) {
3844 xmlFree(name);
3845 return(-1);
3846 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003847 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003848 def->name = name;
3849 if (node->children == NULL) {
3850 if (ctxt->error != NULL)
3851 ctxt->error(ctxt->userData,
3852 "define has no children\n");
3853 ctxt->nbErrors++;
3854 } else {
3855 olddefine = ctxt->define;
3856 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003857 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003858 ctxt->define = olddefine;
3859 }
3860 if (ctxt->grammar->defs == NULL)
3861 ctxt->grammar->defs = xmlHashCreate(10);
3862 if (ctxt->grammar->defs == NULL) {
3863 if (ctxt->error != NULL)
3864 ctxt->error(ctxt->userData,
3865 "Could not create definition hash\n");
3866 ctxt->nbErrors++;
3867 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003868 } else {
3869 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3870 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003871 xmlRelaxNGDefinePtr prev;
3872
3873 prev = xmlHashLookup(ctxt->grammar->defs, name);
3874 if (prev == NULL) {
3875 if (ctxt->error != NULL)
3876 ctxt->error(ctxt->userData,
3877 "Internal error on define aggregation of %s\n",
3878 name);
3879 ctxt->nbErrors++;
3880 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003881 } else {
3882 while (prev->nextHash != NULL)
3883 prev = prev->nextHash;
3884 prev->nextHash = def;
3885 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003886 }
3887 }
3888 }
3889 return(ret);
3890}
3891
3892/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003893 * xmlRelaxNGProcessExternalRef:
3894 * @ctxt: the parser context
3895 * @node: the externlRef node
3896 *
3897 * Process and compile an externlRef node
3898 *
3899 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3900 */
3901static xmlRelaxNGDefinePtr
3902xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3903 xmlRelaxNGDocumentPtr docu;
3904 xmlNodePtr root, tmp;
3905 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003906 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003907 xmlRelaxNGDefinePtr def;
3908
3909 docu = node->_private;
3910 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003911 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003912 if (def == NULL)
3913 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003914 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003915
3916 if (docu->content == NULL) {
3917 /*
3918 * Then do the parsing for good
3919 */
3920 root = xmlDocGetRootElement(docu->doc);
3921 if (root == NULL) {
3922 if (ctxt->error != NULL)
3923 ctxt->error(ctxt->userData,
3924 "xmlRelaxNGParse: %s is empty\n",
3925 ctxt->URL);
3926 ctxt->nbErrors++;
3927 return (NULL);
3928 }
3929 /*
3930 * ns transmission rules
3931 */
3932 ns = xmlGetProp(root, BAD_CAST "ns");
3933 if (ns == NULL) {
3934 tmp = node;
3935 while ((tmp != NULL) &&
3936 (tmp->type == XML_ELEMENT_NODE)) {
3937 ns = xmlGetProp(tmp, BAD_CAST "ns");
3938 if (ns != NULL) {
3939 break;
3940 }
3941 tmp = tmp->parent;
3942 }
3943 if (ns != NULL) {
3944 xmlSetProp(root, BAD_CAST "ns", ns);
3945 newNs = 1;
3946 xmlFree(ns);
3947 }
3948 } else {
3949 xmlFree(ns);
3950 }
3951
3952 /*
3953 * Parsing to get a precompiled schemas.
3954 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00003955 oldflags = ctxt->flags;
3956 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003957 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00003958 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003959 if ((docu->schema != NULL) &&
3960 (docu->schema->topgrammar != NULL)) {
3961 docu->content = docu->schema->topgrammar->start;
3962 }
3963
3964 /*
3965 * the externalRef may be reused in a different ns context
3966 */
3967 if (newNs == 1) {
3968 xmlUnsetProp(root, BAD_CAST "ns");
3969 }
3970 }
3971 def->content = docu->content;
3972 } else {
3973 def = NULL;
3974 }
3975 return(def);
3976}
3977
3978/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003979 * xmlRelaxNGParsePattern:
3980 * @ctxt: a Relax-NG parser context
3981 * @node: the pattern node.
3982 *
3983 * parse the content of a RelaxNG pattern node.
3984 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00003985 * Returns the definition pointer or NULL in case of error or if no
3986 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00003987 */
3988static xmlRelaxNGDefinePtr
3989xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3990 xmlRelaxNGDefinePtr def = NULL;
3991
Daniel Veillardd2298792003-02-14 16:54:11 +00003992 if (node == NULL) {
3993 return(NULL);
3994 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003995 if (IS_RELAXNG(node, "element")) {
3996 def = xmlRelaxNGParseElement(ctxt, node);
3997 } else if (IS_RELAXNG(node, "attribute")) {
3998 def = xmlRelaxNGParseAttribute(ctxt, node);
3999 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004000 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004001 if (def == NULL)
4002 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004003 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004004 if (node->children != NULL) {
4005 if (ctxt->error != NULL)
4006 ctxt->error(ctxt->userData, "empty: had a child node\n");
4007 ctxt->nbErrors++;
4008 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004009 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004010 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004011 if (def == NULL)
4012 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004013 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004014 if (node->children != NULL) {
4015 if (ctxt->error != NULL)
4016 ctxt->error(ctxt->userData, "text: had a child node\n");
4017 ctxt->nbErrors++;
4018 }
4019 } else if (IS_RELAXNG(node, "zeroOrMore")) {
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_ZEROORMORE;
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 {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004030 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004031 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004032 } else if (IS_RELAXNG(node, "oneOrMore")) {
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_ONEORMORE;
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, "optional")) {
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_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004050 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, 1);
4057 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004058 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004059 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004060 if (def == NULL)
4061 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004062 def->type = XML_RELAXNG_CHOICE;
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, "group")) {
4072 def = xmlRelaxNGNewDefine(ctxt, node);
4073 if (def == NULL)
4074 return(NULL);
4075 def->type = XML_RELAXNG_GROUP;
4076 if (node->children == NULL) {
4077 if (ctxt->error != NULL)
4078 ctxt->error(ctxt->userData,
4079 "Element %s is empty\n", node->name);
4080 ctxt->nbErrors++;
4081 } else {
4082 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4083 }
4084 } else if (IS_RELAXNG(node, "ref")) {
4085 def = xmlRelaxNGNewDefine(ctxt, node);
4086 if (def == NULL)
4087 return(NULL);
4088 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004089 def->name = xmlGetProp(node, BAD_CAST "name");
4090 if (def->name == NULL) {
4091 if (ctxt->error != NULL)
4092 ctxt->error(ctxt->userData,
4093 "ref has no name\n");
4094 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004095 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004096 xmlRelaxNGNormExtSpace(def->name);
4097 if (xmlValidateNCName(def->name, 0)) {
4098 if (ctxt->error != NULL)
4099 ctxt->error(ctxt->userData,
4100 "ref name '%s' is not an NCName\n",
4101 def->name);
4102 ctxt->nbErrors++;
4103 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004104 }
4105 if (node->children != NULL) {
4106 if (ctxt->error != NULL)
4107 ctxt->error(ctxt->userData,
4108 "ref is not empty\n");
4109 ctxt->nbErrors++;
4110 }
4111 if (ctxt->grammar->refs == NULL)
4112 ctxt->grammar->refs = xmlHashCreate(10);
4113 if (ctxt->grammar->refs == NULL) {
4114 if (ctxt->error != NULL)
4115 ctxt->error(ctxt->userData,
4116 "Could not create references hash\n");
4117 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004118 def = NULL;
4119 } else {
4120 int tmp;
4121
4122 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4123 if (tmp < 0) {
4124 xmlRelaxNGDefinePtr prev;
4125
4126 prev = (xmlRelaxNGDefinePtr)
4127 xmlHashLookup(ctxt->grammar->refs, def->name);
4128 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004129 if (def->name != NULL) {
4130 if (ctxt->error != NULL)
4131 ctxt->error(ctxt->userData,
4132 "Error refs definitions '%s'\n",
4133 def->name);
4134 } else {
4135 if (ctxt->error != NULL)
4136 ctxt->error(ctxt->userData,
4137 "Error refs definitions\n");
4138 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004139 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004140 def = NULL;
4141 } else {
4142 def->nextHash = prev->nextHash;
4143 prev->nextHash = def;
4144 }
4145 }
4146 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004147 } else if (IS_RELAXNG(node, "data")) {
4148 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004149 } else if (IS_RELAXNG(node, "value")) {
4150 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004151 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004152 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004153 if (def == NULL)
4154 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004155 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004156 if (node->children == NULL) {
4157 if (ctxt->error != NULL)
4158 ctxt->error(ctxt->userData,
4159 "Element %s is empty\n", node->name);
4160 ctxt->nbErrors++;
4161 } else {
4162 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4163 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004164 } else if (IS_RELAXNG(node, "interleave")) {
4165 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004166 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004167 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004168 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004169 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004170 if (def == NULL)
4171 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004172 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004173 if (node->children != NULL) {
4174 if (ctxt->error != NULL)
4175 ctxt->error(ctxt->userData,
4176 "xmlRelaxNGParse: notAllowed element is not empty\n");
4177 ctxt->nbErrors++;
4178 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004179 } else if (IS_RELAXNG(node, "grammar")) {
4180 xmlRelaxNGGrammarPtr grammar, old;
4181 xmlRelaxNGGrammarPtr oldparent;
4182
Daniel Veillardc482e262003-02-26 14:48:48 +00004183#ifdef DEBUG_GRAMMAR
4184 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4185#endif
4186
Daniel Veillard419a7682003-02-03 23:22:49 +00004187 oldparent = ctxt->parentgrammar;
4188 old = ctxt->grammar;
4189 ctxt->parentgrammar = old;
4190 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4191 if (old != NULL) {
4192 ctxt->grammar = old;
4193 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004194#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004195 if (grammar != NULL) {
4196 grammar->next = old->next;
4197 old->next = grammar;
4198 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004199#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004200 }
4201 if (grammar != NULL)
4202 def = grammar->start;
4203 else
4204 def = NULL;
4205 } else if (IS_RELAXNG(node, "parentRef")) {
4206 if (ctxt->parentgrammar == NULL) {
4207 if (ctxt->error != NULL)
4208 ctxt->error(ctxt->userData,
4209 "Use of parentRef without a parent grammar\n");
4210 ctxt->nbErrors++;
4211 return(NULL);
4212 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004213 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004214 if (def == NULL)
4215 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004216 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004217 def->name = xmlGetProp(node, BAD_CAST "name");
4218 if (def->name == NULL) {
4219 if (ctxt->error != NULL)
4220 ctxt->error(ctxt->userData,
4221 "parentRef has no name\n");
4222 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004223 } else {
4224 xmlRelaxNGNormExtSpace(def->name);
4225 if (xmlValidateNCName(def->name, 0)) {
4226 if (ctxt->error != NULL)
4227 ctxt->error(ctxt->userData,
4228 "parentRef name '%s' is not an NCName\n",
4229 def->name);
4230 ctxt->nbErrors++;
4231 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004232 }
4233 if (node->children != NULL) {
4234 if (ctxt->error != NULL)
4235 ctxt->error(ctxt->userData,
4236 "parentRef is not empty\n");
4237 ctxt->nbErrors++;
4238 }
4239 if (ctxt->parentgrammar->refs == NULL)
4240 ctxt->parentgrammar->refs = xmlHashCreate(10);
4241 if (ctxt->parentgrammar->refs == NULL) {
4242 if (ctxt->error != NULL)
4243 ctxt->error(ctxt->userData,
4244 "Could not create references hash\n");
4245 ctxt->nbErrors++;
4246 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004247 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004248 int tmp;
4249
4250 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4251 if (tmp < 0) {
4252 xmlRelaxNGDefinePtr prev;
4253
4254 prev = (xmlRelaxNGDefinePtr)
4255 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4256 if (prev == NULL) {
4257 if (ctxt->error != NULL)
4258 ctxt->error(ctxt->userData,
4259 "Internal error parentRef definitions '%s'\n",
4260 def->name);
4261 ctxt->nbErrors++;
4262 def = NULL;
4263 } else {
4264 def->nextHash = prev->nextHash;
4265 prev->nextHash = def;
4266 }
4267 }
4268 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004269 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004270 if (node->children == NULL) {
4271 if (ctxt->error != NULL)
4272 ctxt->error(ctxt->userData,
4273 "Mixed is empty\n");
4274 ctxt->nbErrors++;
4275 def = NULL;
4276 } else {
4277 def = xmlRelaxNGParseInterleave(ctxt, node);
4278 if (def != NULL) {
4279 xmlRelaxNGDefinePtr tmp;
4280
4281 if ((def->content != NULL) && (def->content->next != NULL)) {
4282 tmp = xmlRelaxNGNewDefine(ctxt, node);
4283 if (tmp != NULL) {
4284 tmp->type = XML_RELAXNG_GROUP;
4285 tmp->content = def->content;
4286 def->content = tmp;
4287 }
4288 }
4289
4290 tmp = xmlRelaxNGNewDefine(ctxt, node);
4291 if (tmp == NULL)
4292 return(def);
4293 tmp->type = XML_RELAXNG_TEXT;
4294 tmp->next = def->content;
4295 def->content = tmp;
4296 }
4297 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004298 } else {
4299 if (ctxt->error != NULL)
4300 ctxt->error(ctxt->userData,
4301 "Unexpected node %s is not a pattern\n",
4302 node->name);
4303 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004304 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004305 }
4306 return(def);
4307}
4308
4309/**
4310 * xmlRelaxNGParseAttribute:
4311 * @ctxt: a Relax-NG parser context
4312 * @node: the element node
4313 *
4314 * parse the content of a RelaxNG attribute node.
4315 *
4316 * Returns the definition pointer or NULL in case of error.
4317 */
4318static xmlRelaxNGDefinePtr
4319xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004320 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004321 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004322 int old_flags;
4323
Daniel Veillardfd573f12003-03-16 17:52:32 +00004324 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004325 if (ret == NULL)
4326 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004327 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004328 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004329 child = node->children;
4330 if (child == NULL) {
4331 if (ctxt->error != NULL)
4332 ctxt->error(ctxt->userData,
4333 "xmlRelaxNGParseattribute: attribute has no children\n");
4334 ctxt->nbErrors++;
4335 return(ret);
4336 }
4337 old_flags = ctxt->flags;
4338 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004339 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4340 if (cur != NULL)
4341 child = child->next;
4342
Daniel Veillardd2298792003-02-14 16:54:11 +00004343 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004344 cur = xmlRelaxNGParsePattern(ctxt, child);
4345 if (cur != NULL) {
4346 switch (cur->type) {
4347 case XML_RELAXNG_EMPTY:
4348 case XML_RELAXNG_NOT_ALLOWED:
4349 case XML_RELAXNG_TEXT:
4350 case XML_RELAXNG_ELEMENT:
4351 case XML_RELAXNG_DATATYPE:
4352 case XML_RELAXNG_VALUE:
4353 case XML_RELAXNG_LIST:
4354 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004355 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004356 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004357 case XML_RELAXNG_DEF:
4358 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004359 case XML_RELAXNG_ZEROORMORE:
4360 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004361 case XML_RELAXNG_CHOICE:
4362 case XML_RELAXNG_GROUP:
4363 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004364 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004365 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004366 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004367 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004368 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004369 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004370 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004371 if (ctxt->error != NULL)
4372 ctxt->error(ctxt->userData,
4373 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004374 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004375 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004376 case XML_RELAXNG_NOOP:
4377 TODO
4378 if (ctxt->error != NULL)
4379 ctxt->error(ctxt->userData,
4380 "Internal error, noop found\n");
4381 ctxt->nbErrors++;
4382 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004383 }
4384 }
4385 child = child->next;
4386 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004387 if (child != NULL) {
4388 if (ctxt->error != NULL)
4389 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4390 ctxt->nbErrors++;
4391 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004392 ctxt->flags = old_flags;
4393 return(ret);
4394}
4395
4396/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004397 * xmlRelaxNGParseExceptNameClass:
4398 * @ctxt: a Relax-NG parser context
4399 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004400 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004401 *
4402 * parse the content of a RelaxNG nameClass node.
4403 *
4404 * Returns the definition pointer or NULL in case of error.
4405 */
4406static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004407xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4408 xmlNodePtr node, int attr) {
4409 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4410 xmlNodePtr child;
4411
Daniel Veillardd2298792003-02-14 16:54:11 +00004412 if (!IS_RELAXNG(node, "except")) {
4413 if (ctxt->error != NULL)
4414 ctxt->error(ctxt->userData,
4415 "Expecting an except node\n");
4416 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004417 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004418 }
4419 if (node->next != NULL) {
4420 if (ctxt->error != NULL)
4421 ctxt->error(ctxt->userData,
4422 "exceptNameClass allows only a single except node\n");
4423 ctxt->nbErrors++;
4424 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004425 if (node->children == NULL) {
4426 if (ctxt->error != NULL)
4427 ctxt->error(ctxt->userData,
4428 "except has no content\n");
4429 ctxt->nbErrors++;
4430 return(NULL);
4431 }
4432
Daniel Veillardfd573f12003-03-16 17:52:32 +00004433 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004434 if (ret == NULL)
4435 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004436 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004437 child = node->children;
4438 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004439 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004440 if (cur == NULL)
4441 break;
4442 if (attr)
4443 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004444 else
4445 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004446
Daniel Veillard419a7682003-02-03 23:22:49 +00004447 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004448 if (last == NULL) {
4449 ret->content = cur;
4450 } else {
4451 last->next = cur;
4452 }
4453 last = cur;
4454 }
4455 child = child->next;
4456 }
4457
4458 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004459}
4460
4461/**
4462 * xmlRelaxNGParseNameClass:
4463 * @ctxt: a Relax-NG parser context
4464 * @node: the nameClass node
4465 * @def: the current definition
4466 *
4467 * parse the content of a RelaxNG nameClass node.
4468 *
4469 * Returns the definition pointer or NULL in case of error.
4470 */
4471static xmlRelaxNGDefinePtr
4472xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4473 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004474 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004475 xmlChar *val;
4476
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004477 ret = def;
4478 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4479 (IS_RELAXNG(node, "nsName"))) {
4480 if ((def->type != XML_RELAXNG_ELEMENT) &&
4481 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004482 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004483 if (ret == NULL)
4484 return(NULL);
4485 ret->parent = def;
4486 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4487 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004488 else
4489 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004490 }
4491 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004492 if (IS_RELAXNG(node, "name")) {
4493 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004494 xmlRelaxNGNormExtSpace(val);
4495 if (xmlValidateNCName(val, 0)) {
4496 if (ctxt->error != NULL) {
4497 if (node->parent != NULL)
4498 ctxt->error(ctxt->userData,
4499 "Element %s name '%s' is not an NCName\n",
4500 node->parent->name, val);
4501 else
4502 ctxt->error(ctxt->userData,
4503 "name '%s' is not an NCName\n",
4504 val);
4505 }
4506 ctxt->nbErrors++;
4507 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004508 ret->name = val;
4509 val = xmlGetProp(node, BAD_CAST "ns");
4510 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004511 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4512 (val != NULL) &&
4513 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4514 ctxt->error(ctxt->userData,
4515 "Attribute with namespace '%s' is not allowed\n",
4516 val);
4517 ctxt->nbErrors++;
4518 }
4519 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4520 (val != NULL) &&
4521 (val[0] == 0) &&
4522 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4523 ctxt->error(ctxt->userData,
4524 "Attribute with QName 'xmlns' is not allowed\n",
4525 val);
4526 ctxt->nbErrors++;
4527 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004528 } else if (IS_RELAXNG(node, "anyName")) {
4529 ret->name = NULL;
4530 ret->ns = NULL;
4531 if (node->children != NULL) {
4532 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004533 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4534 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004535 }
4536 } else if (IS_RELAXNG(node, "nsName")) {
4537 ret->name = NULL;
4538 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4539 if (ret->ns == NULL) {
4540 if (ctxt->error != NULL)
4541 ctxt->error(ctxt->userData,
4542 "nsName has no ns attribute\n");
4543 ctxt->nbErrors++;
4544 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004545 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4546 (ret->ns != NULL) &&
4547 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4548 ctxt->error(ctxt->userData,
4549 "Attribute with namespace '%s' is not allowed\n",
4550 ret->ns);
4551 ctxt->nbErrors++;
4552 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004553 if (node->children != NULL) {
4554 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004555 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4556 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004557 }
4558 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004559 xmlNodePtr child;
4560 xmlRelaxNGDefinePtr last = NULL;
4561
4562 ret = xmlRelaxNGNewDefine(ctxt, node);
4563 if (ret == NULL)
4564 return(NULL);
4565 ret->parent = def;
4566 ret->type = XML_RELAXNG_CHOICE;
4567
Daniel Veillardd2298792003-02-14 16:54:11 +00004568 if (node->children == NULL) {
4569 if (ctxt->error != NULL)
4570 ctxt->error(ctxt->userData,
4571 "Element choice is empty\n");
4572 ctxt->nbErrors++;
4573 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004574
4575 child = node->children;
4576 while (child != NULL) {
4577 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4578 if (tmp != NULL) {
4579 if (last == NULL) {
4580 last = ret->nameClass = tmp;
4581 } else {
4582 last->next = tmp;
4583 last = tmp;
4584 }
4585 }
4586 child = child->next;
4587 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004588 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004589 } else {
4590 if (ctxt->error != NULL)
4591 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004592 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004593 node->name);
4594 ctxt->nbErrors++;
4595 return(NULL);
4596 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004597 if (ret != def) {
4598 if (def->nameClass == NULL) {
4599 def->nameClass = ret;
4600 } else {
4601 tmp = def->nameClass;
4602 while (tmp->next != NULL) {
4603 tmp = tmp->next;
4604 }
4605 tmp->next = ret;
4606 }
4607 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004608 return(ret);
4609}
4610
4611/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004612 * xmlRelaxNGParseElement:
4613 * @ctxt: a Relax-NG parser context
4614 * @node: the element node
4615 *
4616 * parse the content of a RelaxNG element node.
4617 *
4618 * Returns the definition pointer or NULL in case of error.
4619 */
4620static xmlRelaxNGDefinePtr
4621xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4622 xmlRelaxNGDefinePtr ret, cur, last;
4623 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004624 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004625
Daniel Veillardfd573f12003-03-16 17:52:32 +00004626 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004627 if (ret == NULL)
4628 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004629 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004630 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004631 child = node->children;
4632 if (child == NULL) {
4633 if (ctxt->error != NULL)
4634 ctxt->error(ctxt->userData,
4635 "xmlRelaxNGParseElement: element has no children\n");
4636 ctxt->nbErrors++;
4637 return(ret);
4638 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004639 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4640 if (cur != NULL)
4641 child = child->next;
4642
Daniel Veillard6eadf632003-01-23 18:29:16 +00004643 if (child == NULL) {
4644 if (ctxt->error != NULL)
4645 ctxt->error(ctxt->userData,
4646 "xmlRelaxNGParseElement: element has no content\n");
4647 ctxt->nbErrors++;
4648 return(ret);
4649 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004650 olddefine = ctxt->define;
4651 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004652 last = NULL;
4653 while (child != NULL) {
4654 cur = xmlRelaxNGParsePattern(ctxt, child);
4655 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004656 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004657 switch (cur->type) {
4658 case XML_RELAXNG_EMPTY:
4659 case XML_RELAXNG_NOT_ALLOWED:
4660 case XML_RELAXNG_TEXT:
4661 case XML_RELAXNG_ELEMENT:
4662 case XML_RELAXNG_DATATYPE:
4663 case XML_RELAXNG_VALUE:
4664 case XML_RELAXNG_LIST:
4665 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004666 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004667 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004668 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004669 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004670 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004671 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004672 case XML_RELAXNG_CHOICE:
4673 case XML_RELAXNG_GROUP:
4674 case XML_RELAXNG_INTERLEAVE:
4675 if (last == NULL) {
4676 ret->content = last = cur;
4677 } else {
4678 if ((last->type == XML_RELAXNG_ELEMENT) &&
4679 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004680 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004681 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004682 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004683 ret->content->content = last;
4684 } else {
4685 ret->content = last;
4686 }
4687 }
4688 last->next = cur;
4689 last = cur;
4690 }
4691 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004692 case XML_RELAXNG_ATTRIBUTE:
4693 cur->next = ret->attrs;
4694 ret->attrs = cur;
4695 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004696 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004697 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004698 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004699 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004700 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004701 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004702 case XML_RELAXNG_NOOP:
4703 TODO
4704 if (ctxt->error != NULL)
4705 ctxt->error(ctxt->userData,
4706 "Internal error, noop found\n");
4707 ctxt->nbErrors++;
4708 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 }
4710 }
4711 child = child->next;
4712 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004713 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004714 return(ret);
4715}
4716
4717/**
4718 * xmlRelaxNGParsePatterns:
4719 * @ctxt: a Relax-NG parser context
4720 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004721 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 *
4723 * parse the content of a RelaxNG start node.
4724 *
4725 * Returns the definition pointer or NULL in case of error.
4726 */
4727static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004728xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4729 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004730 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004731
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004732 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004733 while (nodes != NULL) {
4734 if (IS_RELAXNG(nodes, "element")) {
4735 cur = xmlRelaxNGParseElement(ctxt, nodes);
4736 if (def == NULL) {
4737 def = last = cur;
4738 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004739 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4740 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004741 def = xmlRelaxNGNewDefine(ctxt, nodes);
4742 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004743 def->content = last;
4744 }
4745 last->next = cur;
4746 last = cur;
4747 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004748 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004749 } else {
4750 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004751 if (cur != NULL) {
4752 if (def == NULL) {
4753 def = last = cur;
4754 } else {
4755 last->next = cur;
4756 last = cur;
4757 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004758 }
4759 }
4760 nodes = nodes->next;
4761 }
4762 return(def);
4763}
4764
4765/**
4766 * xmlRelaxNGParseStart:
4767 * @ctxt: a Relax-NG parser context
4768 * @nodes: start children nodes
4769 *
4770 * parse the content of a RelaxNG start node.
4771 *
4772 * Returns 0 in case of success, -1 in case of error
4773 */
4774static int
4775xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4776 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004777 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004778
Daniel Veillardd2298792003-02-14 16:54:11 +00004779 if (nodes == NULL) {
4780 if (ctxt->error != NULL)
4781 ctxt->error(ctxt->userData,
4782 "start has no children\n");
4783 ctxt->nbErrors++;
4784 return(-1);
4785 }
4786 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004787 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004788 if (def == NULL)
4789 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004790 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004791 if (nodes->children != NULL) {
4792 if (ctxt->error != NULL)
4793 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004794 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004795 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004796 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004797 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004798 if (def == NULL)
4799 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004800 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004801 if (nodes->children != NULL) {
4802 if (ctxt->error != NULL)
4803 ctxt->error(ctxt->userData,
4804 "element notAllowed is not empty\n");
4805 ctxt->nbErrors++;
4806 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004807 } else {
4808 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004809 }
4810 if (ctxt->grammar->start != NULL) {
4811 last = ctxt->grammar->start;
4812 while (last->next != NULL)
4813 last = last->next;
4814 last->next = def;
4815 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004816 ctxt->grammar->start = def;
4817 }
4818 nodes = nodes->next;
4819 if (nodes != NULL) {
4820 if (ctxt->error != NULL)
4821 ctxt->error(ctxt->userData,
4822 "start more than one children\n");
4823 ctxt->nbErrors++;
4824 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004825 }
4826 return(ret);
4827}
4828
4829/**
4830 * xmlRelaxNGParseGrammarContent:
4831 * @ctxt: a Relax-NG parser context
4832 * @nodes: grammar children nodes
4833 *
4834 * parse the content of a RelaxNG grammar node.
4835 *
4836 * Returns 0 in case of success, -1 in case of error
4837 */
4838static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004839xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004840{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004841 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004842
4843 if (nodes == NULL) {
4844 if (ctxt->error != NULL)
4845 ctxt->error(ctxt->userData,
4846 "grammar has no children\n");
4847 ctxt->nbErrors++;
4848 return(-1);
4849 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004850 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004851 if (IS_RELAXNG(nodes, "start")) {
4852 if (nodes->children == NULL) {
4853 if (ctxt->error != NULL)
4854 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004855 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004856 ctxt->nbErrors++;
4857 } else {
4858 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4859 if (tmp != 0)
4860 ret = -1;
4861 }
4862 } else if (IS_RELAXNG(nodes, "define")) {
4863 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4864 if (tmp != 0)
4865 ret = -1;
4866 } else if (IS_RELAXNG(nodes, "include")) {
4867 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4868 if (tmp != 0)
4869 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004870 } else {
4871 if (ctxt->error != NULL)
4872 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004873 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004874 ctxt->nbErrors++;
4875 ret = -1;
4876 }
4877 nodes = nodes->next;
4878 }
4879 return (ret);
4880}
4881
4882/**
4883 * xmlRelaxNGCheckReference:
4884 * @ref: the ref
4885 * @ctxt: a Relax-NG parser context
4886 * @name: the name associated to the defines
4887 *
4888 * Applies the 4.17. combine attribute rule for all the define
4889 * element of a given grammar using the same name.
4890 */
4891static void
4892xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4893 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4894 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004895 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004896
4897 grammar = ctxt->grammar;
4898 if (grammar == NULL) {
4899 if (ctxt->error != NULL)
4900 ctxt->error(ctxt->userData,
4901 "Internal error: no grammar in CheckReference %s\n",
4902 name);
4903 ctxt->nbErrors++;
4904 return;
4905 }
4906 if (ref->content != NULL) {
4907 if (ctxt->error != NULL)
4908 ctxt->error(ctxt->userData,
4909 "Internal error: reference has content in CheckReference %s\n",
4910 name);
4911 ctxt->nbErrors++;
4912 return;
4913 }
4914 if (grammar->defs != NULL) {
4915 def = xmlHashLookup(grammar->defs, name);
4916 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00004917 cur = ref;
4918 while (cur != NULL) {
4919 cur->content = def;
4920 cur = cur->nextHash;
4921 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004922 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00004923 if (ctxt->error != NULL)
4924 ctxt->error(ctxt->userData,
4925 "Reference %s has no matching definition\n",
4926 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004927 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004928 }
Daniel Veillardd4310742003-02-18 21:12:46 +00004929 } else {
4930 if (ctxt->error != NULL)
4931 ctxt->error(ctxt->userData,
4932 "Reference %s has no matching definition\n",
4933 name);
4934 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004935 }
4936 /*
4937 * TODO: make a closure and verify there is no loop !
4938 */
4939}
4940
4941/**
4942 * xmlRelaxNGCheckCombine:
4943 * @define: the define(s) list
4944 * @ctxt: a Relax-NG parser context
4945 * @name: the name associated to the defines
4946 *
4947 * Applies the 4.17. combine attribute rule for all the define
4948 * element of a given grammar using the same name.
4949 */
4950static void
4951xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
4952 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4953 xmlChar *combine;
4954 int choiceOrInterleave = -1;
4955 int missing = 0;
4956 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
4957
4958 if (define->nextHash == NULL)
4959 return;
4960 cur = define;
4961 while (cur != NULL) {
4962 combine = xmlGetProp(cur->node, BAD_CAST "combine");
4963 if (combine != NULL) {
4964 if (xmlStrEqual(combine, BAD_CAST "choice")) {
4965 if (choiceOrInterleave == -1)
4966 choiceOrInterleave = 1;
4967 else if (choiceOrInterleave == 0) {
4968 if (ctxt->error != NULL)
4969 ctxt->error(ctxt->userData,
4970 "Defines for %s use both 'choice' and 'interleave'\n",
4971 name);
4972 ctxt->nbErrors++;
4973 }
Daniel Veillard154877e2003-01-30 12:17:05 +00004974 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004975 if (choiceOrInterleave == -1)
4976 choiceOrInterleave = 0;
4977 else if (choiceOrInterleave == 1) {
4978 if (ctxt->error != NULL)
4979 ctxt->error(ctxt->userData,
4980 "Defines for %s use both 'choice' and 'interleave'\n",
4981 name);
4982 ctxt->nbErrors++;
4983 }
4984 } else {
4985 if (ctxt->error != NULL)
4986 ctxt->error(ctxt->userData,
4987 "Defines for %s use unknown combine value '%s''\n",
4988 name, combine);
4989 ctxt->nbErrors++;
4990 }
4991 xmlFree(combine);
4992 } else {
4993 if (missing == 0)
4994 missing = 1;
4995 else {
4996 if (ctxt->error != NULL)
4997 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00004998 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00004999 name);
5000 ctxt->nbErrors++;
5001 }
5002 }
5003
5004 cur = cur->nextHash;
5005 }
5006#ifdef DEBUG
5007 xmlGenericError(xmlGenericErrorContext,
5008 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5009 name, choiceOrInterleave);
5010#endif
5011 if (choiceOrInterleave == -1)
5012 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005013 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005014 if (cur == NULL)
5015 return;
5016 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005017 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005018 else
5019 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005020 tmp = define;
5021 last = NULL;
5022 while (tmp != NULL) {
5023 if (tmp->content != NULL) {
5024 if (tmp->content->next != NULL) {
5025 /*
5026 * we need first to create a wrapper.
5027 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005028 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005029 if (tmp2 == NULL)
5030 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005031 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005032 tmp2->content = tmp->content;
5033 } else {
5034 tmp2 = tmp->content;
5035 }
5036 if (last == NULL) {
5037 cur->content = tmp2;
5038 } else {
5039 last->next = tmp2;
5040 }
5041 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005042 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005043 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005044 tmp = tmp->nextHash;
5045 }
5046 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005047 if (choiceOrInterleave == 0) {
5048 if (ctxt->interleaves == NULL)
5049 ctxt->interleaves = xmlHashCreate(10);
5050 if (ctxt->interleaves == NULL) {
5051 if (ctxt->error != NULL)
5052 ctxt->error(ctxt->userData,
5053 "Failed to create interleaves hash table\n");
5054 ctxt->nbErrors++;
5055 } else {
5056 char tmpname[32];
5057
5058 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5059 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5060 if (ctxt->error != NULL)
5061 ctxt->error(ctxt->userData,
5062 "Failed to add %s to hash table\n", tmpname);
5063 ctxt->nbErrors++;
5064 }
5065 }
5066 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005067}
5068
5069/**
5070 * xmlRelaxNGCombineStart:
5071 * @ctxt: a Relax-NG parser context
5072 * @grammar: the grammar
5073 *
5074 * Applies the 4.17. combine rule for all the start
5075 * element of a given grammar.
5076 */
5077static void
5078xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5079 xmlRelaxNGGrammarPtr grammar) {
5080 xmlRelaxNGDefinePtr starts;
5081 xmlChar *combine;
5082 int choiceOrInterleave = -1;
5083 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005084 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005085
Daniel Veillard2df2de22003-02-17 23:34:33 +00005086 starts = grammar->start;
5087 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005088 return;
5089 cur = starts;
5090 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005091 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5092 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5093 combine = NULL;
5094 if (ctxt->error != NULL)
5095 ctxt->error(ctxt->userData,
5096 "Internal error: start element not found\n");
5097 ctxt->nbErrors++;
5098 } else {
5099 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5100 }
5101
Daniel Veillard6eadf632003-01-23 18:29:16 +00005102 if (combine != NULL) {
5103 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5104 if (choiceOrInterleave == -1)
5105 choiceOrInterleave = 1;
5106 else if (choiceOrInterleave == 0) {
5107 if (ctxt->error != NULL)
5108 ctxt->error(ctxt->userData,
5109 "<start> use both 'choice' and 'interleave'\n");
5110 ctxt->nbErrors++;
5111 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005112 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005113 if (choiceOrInterleave == -1)
5114 choiceOrInterleave = 0;
5115 else if (choiceOrInterleave == 1) {
5116 if (ctxt->error != NULL)
5117 ctxt->error(ctxt->userData,
5118 "<start> use both 'choice' and 'interleave'\n");
5119 ctxt->nbErrors++;
5120 }
5121 } else {
5122 if (ctxt->error != NULL)
5123 ctxt->error(ctxt->userData,
5124 "<start> uses unknown combine value '%s''\n", combine);
5125 ctxt->nbErrors++;
5126 }
5127 xmlFree(combine);
5128 } else {
5129 if (missing == 0)
5130 missing = 1;
5131 else {
5132 if (ctxt->error != NULL)
5133 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005134 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005135 ctxt->nbErrors++;
5136 }
5137 }
5138
Daniel Veillard2df2de22003-02-17 23:34:33 +00005139 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005140 }
5141#ifdef DEBUG
5142 xmlGenericError(xmlGenericErrorContext,
5143 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5144 choiceOrInterleave);
5145#endif
5146 if (choiceOrInterleave == -1)
5147 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005148 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005149 if (cur == NULL)
5150 return;
5151 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005152 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005153 else
5154 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005155 cur->content = grammar->start;
5156 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005157 if (choiceOrInterleave == 0) {
5158 if (ctxt->interleaves == NULL)
5159 ctxt->interleaves = xmlHashCreate(10);
5160 if (ctxt->interleaves == NULL) {
5161 if (ctxt->error != NULL)
5162 ctxt->error(ctxt->userData,
5163 "Failed to create interleaves hash table\n");
5164 ctxt->nbErrors++;
5165 } else {
5166 char tmpname[32];
5167
5168 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5169 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5170 if (ctxt->error != NULL)
5171 ctxt->error(ctxt->userData,
5172 "Failed to add %s to hash table\n", tmpname);
5173 ctxt->nbErrors++;
5174 }
5175 }
5176 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005177}
5178
5179/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005180 * xmlRelaxNGCheckCycles:
5181 * @ctxt: a Relax-NG parser context
5182 * @nodes: grammar children nodes
5183 * @depth: the counter
5184 *
5185 * Check for cycles.
5186 *
5187 * Returns 0 if check passed, and -1 in case of error
5188 */
5189static int
5190xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5191 xmlRelaxNGDefinePtr cur, int depth) {
5192 int ret = 0;
5193
5194 while ((ret == 0) && (cur != NULL)) {
5195 if ((cur->type == XML_RELAXNG_REF) ||
5196 (cur->type == XML_RELAXNG_PARENTREF)) {
5197 if (cur->depth == -1) {
5198 cur->depth = depth;
5199 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5200 cur->depth = -2;
5201 } else if (depth == cur->depth) {
5202 if (ctxt->error != NULL)
5203 ctxt->error(ctxt->userData,
5204 "Detected a cycle in %s references\n", cur->name);
5205 ctxt->nbErrors++;
5206 return(-1);
5207 }
5208 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5209 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5210 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005211 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005212 }
5213 cur = cur->next;
5214 }
5215 return(ret);
5216}
5217
5218/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005219 * xmlRelaxNGTryUnlink:
5220 * @ctxt: a Relax-NG parser context
5221 * @cur: the definition to unlink
5222 * @parent: the parent definition
5223 * @prev: the previous sibling definition
5224 *
5225 * Try to unlink a definition. If not possble make it a NOOP
5226 *
5227 * Returns the new prev definition
5228 */
5229static xmlRelaxNGDefinePtr
5230xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5231 xmlRelaxNGDefinePtr cur,
5232 xmlRelaxNGDefinePtr parent,
5233 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005234 if (prev != NULL) {
5235 prev->next = cur->next;
5236 } else {
5237 if (parent != NULL) {
5238 if (parent->content == cur)
5239 parent->content = cur->next;
5240 else if (parent->attrs == cur)
5241 parent->attrs = cur->next;
5242 else if (parent->nameClass == cur)
5243 parent->nameClass = cur->next;
5244 } else {
5245 cur->type = XML_RELAXNG_NOOP;
5246 prev = cur;
5247 }
5248 }
5249 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005250}
5251
5252/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005253 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005254 * @ctxt: a Relax-NG parser context
5255 * @nodes: grammar children nodes
5256 *
5257 * Check for simplification of empty and notAllowed
5258 */
5259static void
5260xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5261 xmlRelaxNGDefinePtr cur,
5262 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005263 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005264
Daniel Veillardfd573f12003-03-16 17:52:32 +00005265 while (cur != NULL) {
5266 if ((cur->type == XML_RELAXNG_REF) ||
5267 (cur->type == XML_RELAXNG_PARENTREF)) {
5268 if (cur->depth != -3) {
5269 cur->depth = -3;
5270 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005271 }
5272 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005273 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005274 if ((parent != NULL) &&
5275 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5276 (parent->type == XML_RELAXNG_LIST) ||
5277 (parent->type == XML_RELAXNG_GROUP) ||
5278 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005279 (parent->type == XML_RELAXNG_ONEORMORE) ||
5280 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005281 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005282 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005283 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005284 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005285 (parent->type == XML_RELAXNG_CHOICE)) {
5286 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5287 } else
5288 prev = cur;
5289 } else if (cur->type == XML_RELAXNG_EMPTY){
5290 cur->parent = parent;
5291 if ((parent != NULL) &&
5292 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5293 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005294 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005295 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005296 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005297 if ((parent != NULL) &&
5298 ((parent->type == XML_RELAXNG_GROUP) ||
5299 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5300 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5301 } else
5302 prev = cur;
5303 } else {
5304 cur->parent = parent;
5305 if (cur->content != NULL)
5306 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5307 if (cur->attrs != NULL)
5308 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5309 if (cur->nameClass != NULL)
5310 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5311 /*
5312 * This may result in a simplification
5313 */
5314 if ((cur->type == XML_RELAXNG_GROUP) ||
5315 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5316 if (cur->content == NULL)
5317 cur->type = XML_RELAXNG_EMPTY;
5318 else if (cur->content->next == NULL) {
5319 if ((parent == NULL) && (prev == NULL)) {
5320 cur->type = XML_RELAXNG_NOOP;
5321 } else if (prev == NULL) {
5322 parent->content = cur->content;
5323 cur->content->next = cur->next;
5324 cur = cur->content;
5325 } else {
5326 cur->content->next = cur->next;
5327 prev->next = cur->content;
5328 cur = cur->content;
5329 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005330 }
5331 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005332 /*
5333 * the current node may have been transformed back
5334 */
5335 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5336 (cur->content != NULL) &&
5337 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5338 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5339 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5340 if ((parent != NULL) &&
5341 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5342 (parent->type == XML_RELAXNG_LIST) ||
5343 (parent->type == XML_RELAXNG_GROUP) ||
5344 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5345 (parent->type == XML_RELAXNG_ONEORMORE) ||
5346 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5347 parent->type = XML_RELAXNG_NOT_ALLOWED;
5348 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005349 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005350 if ((parent != NULL) &&
5351 (parent->type == XML_RELAXNG_CHOICE)) {
5352 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5353 } else
5354 prev = cur;
5355 } else if (cur->type == XML_RELAXNG_EMPTY){
5356 if ((parent != NULL) &&
5357 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5358 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5359 parent->type = XML_RELAXNG_EMPTY;
5360 break;
5361 }
5362 if ((parent != NULL) &&
5363 ((parent->type == XML_RELAXNG_GROUP) ||
5364 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5365 (parent->type == XML_RELAXNG_CHOICE))) {
5366 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5367 } else
5368 prev = cur;
5369 } else {
5370 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005371 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005372 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005373 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005374 }
5375}
5376
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005377/**
5378 * xmlRelaxNGGroupContentType:
5379 * @ct1: the first content type
5380 * @ct2: the second content type
5381 *
5382 * Try to group 2 content types
5383 *
5384 * Returns the content type
5385 */
5386static xmlRelaxNGContentType
5387xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5388 xmlRelaxNGContentType ct2) {
5389 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5390 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5391 return(XML_RELAXNG_CONTENT_ERROR);
5392 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5393 return(ct2);
5394 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5395 return(ct1);
5396 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5397 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5398 return(XML_RELAXNG_CONTENT_COMPLEX);
5399 return(XML_RELAXNG_CONTENT_ERROR);
5400}
5401
5402/**
5403 * xmlRelaxNGMaxContentType:
5404 * @ct1: the first content type
5405 * @ct2: the second content type
5406 *
5407 * Compute the max content-type
5408 *
5409 * Returns the content type
5410 */
5411static xmlRelaxNGContentType
5412xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5413 xmlRelaxNGContentType ct2) {
5414 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5415 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5416 return(XML_RELAXNG_CONTENT_ERROR);
5417 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5418 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5419 return(XML_RELAXNG_CONTENT_SIMPLE);
5420 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5421 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5422 return(XML_RELAXNG_CONTENT_COMPLEX);
5423 return(XML_RELAXNG_CONTENT_EMPTY);
5424}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005425
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005426/**
5427 * xmlRelaxNGCheckRules:
5428 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005429 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005430 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005431 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005432 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005433 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005434 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005435 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005436 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005437static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005438xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5439 xmlRelaxNGDefinePtr cur, int flags,
5440 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005441 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005442 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005443
Daniel Veillardfd573f12003-03-16 17:52:32 +00005444 while (cur != NULL) {
5445 ret = XML_RELAXNG_CONTENT_EMPTY;
5446 if ((cur->type == XML_RELAXNG_REF) ||
5447 (cur->type == XML_RELAXNG_PARENTREF)) {
5448 if (flags & XML_RELAXNG_IN_LIST) {
5449 if (ctxt->error != NULL)
5450 ctxt->error(ctxt->userData,
5451 "Found forbidden pattern list//ref\n");
5452 ctxt->nbErrors++;
5453 }
5454 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5455 if (ctxt->error != NULL)
5456 ctxt->error(ctxt->userData,
5457 "Found forbidden pattern data/except//ref\n");
5458 ctxt->nbErrors++;
5459 }
5460 if (cur->depth > -4) {
5461 cur->depth = -4;
5462 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5463 flags, cur->type);
5464 cur->depth = ret - 15 ;
5465 } else if (cur->depth == -4) {
5466 ret = XML_RELAXNG_CONTENT_COMPLEX;
5467 } else {
5468 ret = (xmlRelaxNGContentType) cur->depth + 15;
5469 }
5470 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5471 /*
5472 * The 7.3 Attribute derivation rule for groups is plugged there
5473 */
5474 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5475 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5476 if (ctxt->error != NULL)
5477 ctxt->error(ctxt->userData,
5478 "Found forbidden pattern data/except//element(ref)\n");
5479 ctxt->nbErrors++;
5480 }
5481 if (flags & XML_RELAXNG_IN_LIST) {
5482 if (ctxt->error != NULL)
5483 ctxt->error(ctxt->userData,
5484 "Found forbidden pattern list//element(ref)\n");
5485 ctxt->nbErrors++;
5486 }
5487 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5488 if (ctxt->error != NULL)
5489 ctxt->error(ctxt->userData,
5490 "Found forbidden pattern attribute//element(ref)\n");
5491 ctxt->nbErrors++;
5492 }
5493 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5494 if (ctxt->error != NULL)
5495 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005496 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005497 ctxt->nbErrors++;
5498 }
5499 /*
5500 * reset since in the simple form elements are only child
5501 * of grammar/define
5502 */
5503 nflags = 0;
5504 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5505 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5506 if (ctxt->error != NULL)
5507 ctxt->error(ctxt->userData,
5508 "Element %s attributes have a content type error\n",
5509 cur->name);
5510 ctxt->nbErrors++;
5511 }
5512 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5513 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5514 if (ctxt->error != NULL)
5515 ctxt->error(ctxt->userData,
5516 "Element %s has a content type error\n",
5517 cur->name);
5518 ctxt->nbErrors++;
5519 } else {
5520 ret = XML_RELAXNG_CONTENT_COMPLEX;
5521 }
5522 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5523 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5524 if (ctxt->error != NULL)
5525 ctxt->error(ctxt->userData,
5526 "Found forbidden pattern attribute//attribute\n");
5527 ctxt->nbErrors++;
5528 }
5529 if (flags & XML_RELAXNG_IN_LIST) {
5530 if (ctxt->error != NULL)
5531 ctxt->error(ctxt->userData,
5532 "Found forbidden pattern list//attribute\n");
5533 ctxt->nbErrors++;
5534 }
5535 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5536 if (ctxt->error != NULL)
5537 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005538 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005539 ctxt->nbErrors++;
5540 }
5541 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5542 if (ctxt->error != NULL)
5543 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005544 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005545 ctxt->nbErrors++;
5546 }
5547 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5548 if (ctxt->error != NULL)
5549 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005550 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005551 ctxt->nbErrors++;
5552 }
5553 if (flags & XML_RELAXNG_IN_START) {
5554 if (ctxt->error != NULL)
5555 ctxt->error(ctxt->userData,
5556 "Found forbidden pattern start//attribute\n");
5557 ctxt->nbErrors++;
5558 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005559 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5560 if (cur->ns == NULL) {
5561 if (ctxt->error != NULL)
5562 ctxt->error(ctxt->userData,
5563 "Found anyName attribute without oneOrMore ancestor\n");
5564 ctxt->nbErrors++;
5565 } else {
5566 if (ctxt->error != NULL)
5567 ctxt->error(ctxt->userData,
5568 "Found nsName attribute without oneOrMore ancestor\n");
5569 ctxt->nbErrors++;
5570 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005571 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005572 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5573 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5574 ret = XML_RELAXNG_CONTENT_EMPTY;
5575 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5576 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5577 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5578 if (ctxt->error != NULL)
5579 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005580 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005581 ctxt->nbErrors++;
5582 }
5583 if (flags & XML_RELAXNG_IN_START) {
5584 if (ctxt->error != NULL)
5585 ctxt->error(ctxt->userData,
5586 "Found forbidden pattern start//oneOrMore\n");
5587 ctxt->nbErrors++;
5588 }
5589 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5590 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5591 ret = xmlRelaxNGGroupContentType(ret, ret);
5592 } else if (cur->type == XML_RELAXNG_LIST) {
5593 if (flags & XML_RELAXNG_IN_LIST) {
5594 if (ctxt->error != NULL)
5595 ctxt->error(ctxt->userData,
5596 "Found forbidden pattern list//list\n");
5597 ctxt->nbErrors++;
5598 }
5599 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5600 if (ctxt->error != NULL)
5601 ctxt->error(ctxt->userData,
5602 "Found forbidden pattern data/except//list\n");
5603 ctxt->nbErrors++;
5604 }
5605 if (flags & XML_RELAXNG_IN_START) {
5606 if (ctxt->error != NULL)
5607 ctxt->error(ctxt->userData,
5608 "Found forbidden pattern start//list\n");
5609 ctxt->nbErrors++;
5610 }
5611 nflags = flags | XML_RELAXNG_IN_LIST;
5612 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5613 } else if (cur->type == XML_RELAXNG_GROUP) {
5614 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5615 if (ctxt->error != NULL)
5616 ctxt->error(ctxt->userData,
5617 "Found forbidden pattern data/except//group\n");
5618 ctxt->nbErrors++;
5619 }
5620 if (flags & XML_RELAXNG_IN_START) {
5621 if (ctxt->error != NULL)
5622 ctxt->error(ctxt->userData,
5623 "Found forbidden pattern start//group\n");
5624 ctxt->nbErrors++;
5625 }
5626 if (flags & XML_RELAXNG_IN_ONEORMORE)
5627 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5628 else
5629 nflags = flags;
5630 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5631 /*
5632 * The 7.3 Attribute derivation rule for groups is plugged there
5633 */
5634 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5635 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5636 if (flags & XML_RELAXNG_IN_LIST) {
5637 if (ctxt->error != NULL)
5638 ctxt->error(ctxt->userData,
5639 "Found forbidden pattern list//interleave\n");
5640 ctxt->nbErrors++;
5641 }
5642 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5643 if (ctxt->error != NULL)
5644 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005645 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005646 ctxt->nbErrors++;
5647 }
5648 if (flags & XML_RELAXNG_IN_START) {
5649 if (ctxt->error != NULL)
5650 ctxt->error(ctxt->userData,
5651 "Found forbidden pattern start//interleave\n");
5652 ctxt->nbErrors++;
5653 }
5654 if (flags & XML_RELAXNG_IN_ONEORMORE)
5655 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5656 else
5657 nflags = flags;
5658 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5659 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5660 if ((cur->parent != NULL) &&
5661 (cur->parent->type == XML_RELAXNG_DATATYPE))
5662 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5663 else
5664 nflags = flags;
5665 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5666 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5667 if (flags & XML_RELAXNG_IN_START) {
5668 if (ctxt->error != NULL)
5669 ctxt->error(ctxt->userData,
5670 "Found forbidden pattern start//data\n");
5671 ctxt->nbErrors++;
5672 }
5673 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5674 ret = XML_RELAXNG_CONTENT_SIMPLE;
5675 } else if (cur->type == XML_RELAXNG_VALUE) {
5676 if (flags & XML_RELAXNG_IN_START) {
5677 if (ctxt->error != NULL)
5678 ctxt->error(ctxt->userData,
5679 "Found forbidden pattern start//value\n");
5680 ctxt->nbErrors++;
5681 }
5682 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5683 ret = XML_RELAXNG_CONTENT_SIMPLE;
5684 } else if (cur->type == XML_RELAXNG_TEXT) {
5685 if (flags & XML_RELAXNG_IN_LIST) {
5686 if (ctxt->error != NULL)
5687 ctxt->error(ctxt->userData,
5688 "Found forbidden pattern list//text\n");
5689 ctxt->nbErrors++;
5690 }
5691 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5692 if (ctxt->error != NULL)
5693 ctxt->error(ctxt->userData,
5694 "Found forbidden pattern data/except//text\n");
5695 ctxt->nbErrors++;
5696 }
5697 if (flags & XML_RELAXNG_IN_START) {
5698 if (ctxt->error != NULL)
5699 ctxt->error(ctxt->userData,
5700 "Found forbidden pattern start//text\n");
5701 ctxt->nbErrors++;
5702 }
5703 ret = XML_RELAXNG_CONTENT_COMPLEX;
5704 } else if (cur->type == XML_RELAXNG_EMPTY) {
5705 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5706 if (ctxt->error != NULL)
5707 ctxt->error(ctxt->userData,
5708 "Found forbidden pattern data/except//empty\n");
5709 ctxt->nbErrors++;
5710 }
5711 if (flags & XML_RELAXNG_IN_START) {
5712 if (ctxt->error != NULL)
5713 ctxt->error(ctxt->userData,
5714 "Found forbidden pattern start//empty\n");
5715 ctxt->nbErrors++;
5716 }
5717 ret = XML_RELAXNG_CONTENT_EMPTY;
5718 } else if (cur->type == XML_RELAXNG_CHOICE) {
5719 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5720 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5721 } else {
5722 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5723 }
5724 cur = cur->next;
5725 if (ptype == XML_RELAXNG_GROUP) {
5726 val = xmlRelaxNGGroupContentType(val, ret);
5727 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5728 tmp = xmlRelaxNGGroupContentType(val, ret);
5729 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5730 tmp = xmlRelaxNGMaxContentType(val, ret);
5731 } else if (ptype == XML_RELAXNG_CHOICE) {
5732 val = xmlRelaxNGMaxContentType(val, ret);
5733 } else if (ptype == XML_RELAXNG_LIST) {
5734 val = XML_RELAXNG_CONTENT_SIMPLE;
5735 } else if (ptype == XML_RELAXNG_EXCEPT) {
5736 if (ret == XML_RELAXNG_CONTENT_ERROR)
5737 val = XML_RELAXNG_CONTENT_ERROR;
5738 else
5739 val = XML_RELAXNG_CONTENT_SIMPLE;
5740 } else {
5741 val = xmlRelaxNGGroupContentType(val, ret);
5742 }
5743
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005744 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005745 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005746}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005747
5748/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005749 * xmlRelaxNGParseGrammar:
5750 * @ctxt: a Relax-NG parser context
5751 * @nodes: grammar children nodes
5752 *
5753 * parse a Relax-NG <grammar> node
5754 *
5755 * Returns the internal xmlRelaxNGGrammarPtr built or
5756 * NULL in case of error
5757 */
5758static xmlRelaxNGGrammarPtr
5759xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5760 xmlRelaxNGGrammarPtr ret, tmp, old;
5761
Daniel Veillardc482e262003-02-26 14:48:48 +00005762#ifdef DEBUG_GRAMMAR
5763 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5764#endif
5765
Daniel Veillard6eadf632003-01-23 18:29:16 +00005766 ret = xmlRelaxNGNewGrammar(ctxt);
5767 if (ret == NULL)
5768 return(NULL);
5769
5770 /*
5771 * Link the new grammar in the tree
5772 */
5773 ret->parent = ctxt->grammar;
5774 if (ctxt->grammar != NULL) {
5775 tmp = ctxt->grammar->children;
5776 if (tmp == NULL) {
5777 ctxt->grammar->children = ret;
5778 } else {
5779 while (tmp->next != NULL)
5780 tmp = tmp->next;
5781 tmp->next = ret;
5782 }
5783 }
5784
5785 old = ctxt->grammar;
5786 ctxt->grammar = ret;
5787 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5788 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005789 if (ctxt->grammar == NULL) {
5790 if (ctxt->error != NULL)
5791 ctxt->error(ctxt->userData,
5792 "Failed to parse <grammar> content\n");
5793 ctxt->nbErrors++;
5794 } else if (ctxt->grammar->start == NULL) {
5795 if (ctxt->error != NULL)
5796 ctxt->error(ctxt->userData,
5797 "Element <grammar> has no <start>\n");
5798 ctxt->nbErrors++;
5799 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005800
5801 /*
5802 * Apply 4.17 mergingd rules to defines and starts
5803 */
5804 xmlRelaxNGCombineStart(ctxt, ret);
5805 if (ret->defs != NULL) {
5806 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5807 ctxt);
5808 }
5809
5810 /*
5811 * link together defines and refs in this grammar
5812 */
5813 if (ret->refs != NULL) {
5814 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5815 ctxt);
5816 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005817
Daniel Veillard6eadf632003-01-23 18:29:16 +00005818 ctxt->grammar = old;
5819 return(ret);
5820}
5821
5822/**
5823 * xmlRelaxNGParseDocument:
5824 * @ctxt: a Relax-NG parser context
5825 * @node: the root node of the RelaxNG schema
5826 *
5827 * parse a Relax-NG definition resource and build an internal
5828 * xmlRelaxNG struture which can be used to validate instances.
5829 *
5830 * Returns the internal XML RelaxNG structure built or
5831 * NULL in case of error
5832 */
5833static xmlRelaxNGPtr
5834xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5835 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005836 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005837 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005838
5839 if ((ctxt == NULL) || (node == NULL))
5840 return (NULL);
5841
5842 schema = xmlRelaxNGNewRelaxNG(ctxt);
5843 if (schema == NULL)
5844 return(NULL);
5845
Daniel Veillard276be4a2003-01-24 01:03:34 +00005846 olddefine = ctxt->define;
5847 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005848 if (IS_RELAXNG(node, "grammar")) {
5849 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5850 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005851 xmlRelaxNGGrammarPtr tmp, ret;
5852
5853 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005854 if (schema->topgrammar == NULL) {
5855 return(schema);
5856 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005857 /*
5858 * Link the new grammar in the tree
5859 */
5860 ret->parent = ctxt->grammar;
5861 if (ctxt->grammar != NULL) {
5862 tmp = ctxt->grammar->children;
5863 if (tmp == NULL) {
5864 ctxt->grammar->children = ret;
5865 } else {
5866 while (tmp->next != NULL)
5867 tmp = tmp->next;
5868 tmp->next = ret;
5869 }
5870 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005871 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005872 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005873 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005874 if (old != NULL)
5875 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005876 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005877 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005878 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005879 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005880 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005881 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5882 while ((schema->topgrammar->start != NULL) &&
5883 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5884 (schema->topgrammar->start->next != NULL))
5885 schema->topgrammar->start = schema->topgrammar->start->content;
5886 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5887 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005888 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005889 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005890
5891#ifdef DEBUG
5892 if (schema == NULL)
5893 xmlGenericError(xmlGenericErrorContext,
5894 "xmlRelaxNGParseDocument() failed\n");
5895#endif
5896
5897 return (schema);
5898}
5899
5900/************************************************************************
5901 * *
5902 * Reading RelaxNGs *
5903 * *
5904 ************************************************************************/
5905
5906/**
5907 * xmlRelaxNGNewParserCtxt:
5908 * @URL: the location of the schema
5909 *
5910 * Create an XML RelaxNGs parse context for that file/resource expected
5911 * to contain an XML RelaxNGs file.
5912 *
5913 * Returns the parser context or NULL in case of error
5914 */
5915xmlRelaxNGParserCtxtPtr
5916xmlRelaxNGNewParserCtxt(const char *URL) {
5917 xmlRelaxNGParserCtxtPtr ret;
5918
5919 if (URL == NULL)
5920 return(NULL);
5921
5922 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5923 if (ret == NULL) {
5924 xmlGenericError(xmlGenericErrorContext,
5925 "Failed to allocate new schama parser context for %s\n", URL);
5926 return (NULL);
5927 }
5928 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5929 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005930 ret->error = xmlGenericError;
5931 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005932 return (ret);
5933}
5934
5935/**
5936 * xmlRelaxNGNewMemParserCtxt:
5937 * @buffer: a pointer to a char array containing the schemas
5938 * @size: the size of the array
5939 *
5940 * Create an XML RelaxNGs parse context for that memory buffer expected
5941 * to contain an XML RelaxNGs file.
5942 *
5943 * Returns the parser context or NULL in case of error
5944 */
5945xmlRelaxNGParserCtxtPtr
5946xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
5947 xmlRelaxNGParserCtxtPtr ret;
5948
5949 if ((buffer == NULL) || (size <= 0))
5950 return(NULL);
5951
5952 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
5953 if (ret == NULL) {
5954 xmlGenericError(xmlGenericErrorContext,
5955 "Failed to allocate new schama parser context\n");
5956 return (NULL);
5957 }
5958 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
5959 ret->buffer = buffer;
5960 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005961 ret->error = xmlGenericError;
5962 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005963 return (ret);
5964}
5965
5966/**
5967 * xmlRelaxNGFreeParserCtxt:
5968 * @ctxt: the schema parser context
5969 *
5970 * Free the resources associated to the schema parser context
5971 */
5972void
5973xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
5974 if (ctxt == NULL)
5975 return;
5976 if (ctxt->URL != NULL)
5977 xmlFree(ctxt->URL);
5978 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005979 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005980 if (ctxt->interleaves != NULL)
5981 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005982 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005983 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00005984 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00005985 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005986 if (ctxt->docTab != NULL)
5987 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00005988 if (ctxt->incTab != NULL)
5989 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00005990 if (ctxt->defTab != NULL) {
5991 int i;
5992
5993 for (i = 0;i < ctxt->defNr;i++)
5994 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
5995 xmlFree(ctxt->defTab);
5996 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005997 xmlFree(ctxt);
5998}
5999
Daniel Veillard6eadf632003-01-23 18:29:16 +00006000/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006001 * xmlRelaxNGNormExtSpace:
6002 * @value: a value
6003 *
6004 * Removes the leading and ending spaces of the value
6005 * The string is modified "in situ"
6006 */
6007static void
6008xmlRelaxNGNormExtSpace(xmlChar *value) {
6009 xmlChar *start = value;
6010 xmlChar *cur = value;
6011 if (value == NULL)
6012 return;
6013
6014 while (IS_BLANK(*cur)) cur++;
6015 if (cur == start) {
6016 do {
6017 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6018 if (*cur == 0)
6019 return;
6020 start = cur;
6021 while (IS_BLANK(*cur)) cur++;
6022 if (*cur == 0) {
6023 *start = 0;
6024 return;
6025 }
6026 } while (1);
6027 } else {
6028 do {
6029 while ((*cur != 0) && (!IS_BLANK(*cur)))
6030 *start++ = *cur++;
6031 if (*cur == 0) {
6032 *start = 0;
6033 return;
6034 }
6035 /* don't try to normalize the inner spaces */
6036 while (IS_BLANK(*cur)) cur++;
6037 *start++ = *cur++;
6038 if (*cur == 0) {
6039 *start = 0;
6040 return;
6041 }
6042 } while (1);
6043 }
6044}
6045
6046/**
6047 * xmlRelaxNGCheckAttributes:
6048 * @ctxt: a Relax-NG parser context
6049 * @node: a Relax-NG node
6050 *
6051 * Check all the attributes on the given node
6052 */
6053static void
6054xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6055 xmlAttrPtr cur, next;
6056
6057 cur = node->properties;
6058 while (cur != NULL) {
6059 next = cur->next;
6060 if ((cur->ns == NULL) ||
6061 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6062 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6063 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6064 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6065 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6066 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006067 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006068 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6069 if (ctxt->error != NULL)
6070 ctxt->error(ctxt->userData,
6071 "Attribute %s is not allowed on %s\n",
6072 cur->name, node->name);
6073 ctxt->nbErrors++;
6074 }
6075 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6076 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6077 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6078 if (ctxt->error != NULL)
6079 ctxt->error(ctxt->userData,
6080 "Attribute %s is not allowed on %s\n",
6081 cur->name, node->name);
6082 ctxt->nbErrors++;
6083 }
6084 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6085 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6086 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6087 if (ctxt->error != NULL)
6088 ctxt->error(ctxt->userData,
6089 "Attribute %s is not allowed on %s\n",
6090 cur->name, node->name);
6091 ctxt->nbErrors++;
6092 }
6093 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6094 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6095 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6096 if (ctxt->error != NULL)
6097 ctxt->error(ctxt->userData,
6098 "Attribute %s is not allowed on %s\n",
6099 cur->name, node->name);
6100 ctxt->nbErrors++;
6101 }
6102 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6103 xmlChar *val;
6104 xmlURIPtr uri;
6105
6106 val = xmlNodeListGetString(node->doc, cur->children, 1);
6107 if (val != NULL) {
6108 if (val[0] != 0) {
6109 uri = xmlParseURI((const char *) val);
6110 if (uri == NULL) {
6111 if (ctxt->error != NULL)
6112 ctxt->error(ctxt->userData,
6113 "Attribute %s contains invalid URI %s\n",
6114 cur->name, val);
6115 ctxt->nbErrors++;
6116 } else {
6117 if (uri->scheme == NULL) {
6118 if (ctxt->error != NULL)
6119 ctxt->error(ctxt->userData,
6120 "Attribute %s URI %s is not absolute\n",
6121 cur->name, val);
6122 ctxt->nbErrors++;
6123 }
6124 if (uri->fragment != NULL) {
6125 if (ctxt->error != NULL)
6126 ctxt->error(ctxt->userData,
6127 "Attribute %s URI %s has a fragment ID\n",
6128 cur->name, val);
6129 ctxt->nbErrors++;
6130 }
6131 xmlFreeURI(uri);
6132 }
6133 }
6134 xmlFree(val);
6135 }
6136 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6137 if (ctxt->error != NULL)
6138 ctxt->error(ctxt->userData,
6139 "Unknown attribute %s on %s\n",
6140 cur->name, node->name);
6141 ctxt->nbErrors++;
6142 }
6143 }
6144 cur = next;
6145 }
6146}
6147
6148/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006149 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006150 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006151 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006152 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006153 * Cleanup the subtree from unwanted nodes for parsing, resolve
6154 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006155 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006156static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006157xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006158 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006159
Daniel Veillard6eadf632003-01-23 18:29:16 +00006160 delete = NULL;
6161 cur = root;
6162 while (cur != NULL) {
6163 if (delete != NULL) {
6164 xmlUnlinkNode(delete);
6165 xmlFreeNode(delete);
6166 delete = NULL;
6167 }
6168 if (cur->type == XML_ELEMENT_NODE) {
6169 /*
6170 * Simplification 4.1. Annotations
6171 */
6172 if ((cur->ns == NULL) ||
6173 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006174 if ((cur->parent != NULL) &&
6175 (cur->parent->type == XML_ELEMENT_NODE) &&
6176 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6177 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6178 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6179 if (ctxt->error != NULL)
6180 ctxt->error(ctxt->userData,
6181 "element %s doesn't allow foreign elements\n",
6182 cur->parent->name);
6183 ctxt->nbErrors++;
6184 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006185 delete = cur;
6186 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006187 } else {
6188 xmlRelaxNGCleanupAttributes(ctxt, cur);
6189 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6190 xmlChar *href, *ns, *base, *URL;
6191 xmlRelaxNGDocumentPtr docu;
6192 xmlNodePtr tmp;
6193
6194 ns = xmlGetProp(cur, BAD_CAST "ns");
6195 if (ns == NULL) {
6196 tmp = cur->parent;
6197 while ((tmp != NULL) &&
6198 (tmp->type == XML_ELEMENT_NODE)) {
6199 ns = xmlGetProp(tmp, BAD_CAST "ns");
6200 if (ns != NULL)
6201 break;
6202 tmp = tmp->parent;
6203 }
6204 }
6205 href = xmlGetProp(cur, BAD_CAST "href");
6206 if (href == NULL) {
6207 if (ctxt->error != NULL)
6208 ctxt->error(ctxt->userData,
6209 "xmlRelaxNGParse: externalRef has no href attribute\n");
6210 ctxt->nbErrors++;
6211 delete = cur;
6212 goto skip_children;
6213 }
6214 base = xmlNodeGetBase(cur->doc, cur);
6215 URL = xmlBuildURI(href, base);
6216 if (URL == NULL) {
6217 if (ctxt->error != NULL)
6218 ctxt->error(ctxt->userData,
6219 "Failed to compute URL for externalRef %s\n", href);
6220 ctxt->nbErrors++;
6221 if (href != NULL)
6222 xmlFree(href);
6223 if (base != NULL)
6224 xmlFree(base);
6225 delete = cur;
6226 goto skip_children;
6227 }
6228 if (href != NULL)
6229 xmlFree(href);
6230 if (base != NULL)
6231 xmlFree(base);
6232 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6233 if (docu == NULL) {
6234 if (ctxt->error != NULL)
6235 ctxt->error(ctxt->userData,
6236 "Failed to load externalRef %s\n", URL);
6237 ctxt->nbErrors++;
6238 xmlFree(URL);
6239 delete = cur;
6240 goto skip_children;
6241 }
6242 if (ns != NULL)
6243 xmlFree(ns);
6244 xmlFree(URL);
6245 cur->_private = docu;
6246 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6247 xmlChar *href, *ns, *base, *URL;
6248 xmlRelaxNGIncludePtr incl;
6249 xmlNodePtr tmp;
6250
6251 href = xmlGetProp(cur, BAD_CAST "href");
6252 if (href == NULL) {
6253 if (ctxt->error != NULL)
6254 ctxt->error(ctxt->userData,
6255 "xmlRelaxNGParse: include has no href attribute\n");
6256 ctxt->nbErrors++;
6257 delete = cur;
6258 goto skip_children;
6259 }
6260 base = xmlNodeGetBase(cur->doc, cur);
6261 URL = xmlBuildURI(href, base);
6262 if (URL == NULL) {
6263 if (ctxt->error != NULL)
6264 ctxt->error(ctxt->userData,
6265 "Failed to compute URL for include %s\n", href);
6266 ctxt->nbErrors++;
6267 if (href != NULL)
6268 xmlFree(href);
6269 if (base != NULL)
6270 xmlFree(base);
6271 delete = cur;
6272 goto skip_children;
6273 }
6274 if (href != NULL)
6275 xmlFree(href);
6276 if (base != NULL)
6277 xmlFree(base);
6278 ns = xmlGetProp(cur, BAD_CAST "ns");
6279 if (ns == NULL) {
6280 tmp = cur->parent;
6281 while ((tmp != NULL) &&
6282 (tmp->type == XML_ELEMENT_NODE)) {
6283 ns = xmlGetProp(tmp, BAD_CAST "ns");
6284 if (ns != NULL)
6285 break;
6286 tmp = tmp->parent;
6287 }
6288 }
6289 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6290 if (ns != NULL)
6291 xmlFree(ns);
6292 if (incl == NULL) {
6293 if (ctxt->error != NULL)
6294 ctxt->error(ctxt->userData,
6295 "Failed to load include %s\n", URL);
6296 ctxt->nbErrors++;
6297 xmlFree(URL);
6298 delete = cur;
6299 goto skip_children;
6300 }
6301 xmlFree(URL);
6302 cur->_private = incl;
6303 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6304 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6305 xmlChar *name, *ns;
6306 xmlNodePtr text = NULL;
6307
6308 /*
6309 * Simplification 4.8. name attribute of element
6310 * and attribute elements
6311 */
6312 name = xmlGetProp(cur, BAD_CAST "name");
6313 if (name != NULL) {
6314 if (cur->children == NULL) {
6315 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6316 name);
6317 } else {
6318 xmlNodePtr node;
6319 node = xmlNewNode(cur->ns, BAD_CAST "name");
6320 if (node != NULL) {
6321 xmlAddPrevSibling(cur->children, node);
6322 text = xmlNewText(name);
6323 xmlAddChild(node, text);
6324 text = node;
6325 }
6326 }
6327 if (text == NULL) {
6328 if (ctxt->error != NULL)
6329 ctxt->error(ctxt->userData,
6330 "Failed to create a name %s element\n", name);
6331 ctxt->nbErrors++;
6332 }
6333 xmlUnsetProp(cur, BAD_CAST "name");
6334 xmlFree(name);
6335 ns = xmlGetProp(cur, BAD_CAST "ns");
6336 if (ns != NULL) {
6337 if (text != NULL) {
6338 xmlSetProp(text, BAD_CAST "ns", ns);
6339 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6340 }
6341 xmlFree(ns);
6342 } else if (xmlStrEqual(cur->name,
6343 BAD_CAST "attribute")) {
6344 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6345 }
6346 }
6347 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6348 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6349 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6350 /*
6351 * Simplification 4.8. name attribute of element
6352 * and attribute elements
6353 */
6354 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6355 xmlNodePtr node;
6356 xmlChar *ns = NULL;
6357
6358 node = cur->parent;
6359 while ((node != NULL) &&
6360 (node->type == XML_ELEMENT_NODE)) {
6361 ns = xmlGetProp(node, BAD_CAST "ns");
6362 if (ns != NULL) {
6363 break;
6364 }
6365 node = node->parent;
6366 }
6367 if (ns == NULL) {
6368 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6369 } else {
6370 xmlSetProp(cur, BAD_CAST "ns", ns);
6371 xmlFree(ns);
6372 }
6373 }
6374 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6375 xmlChar *name, *local, *prefix;
6376
6377 /*
6378 * Simplification: 4.10. QNames
6379 */
6380 name = xmlNodeGetContent(cur);
6381 if (name != NULL) {
6382 local = xmlSplitQName2(name, &prefix);
6383 if (local != NULL) {
6384 xmlNsPtr ns;
6385
6386 ns = xmlSearchNs(cur->doc, cur, prefix);
6387 if (ns == NULL) {
6388 if (ctxt->error != NULL)
6389 ctxt->error(ctxt->userData,
6390 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6391 ctxt->nbErrors++;
6392 } else {
6393 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6394 xmlNodeSetContent(cur, local);
6395 }
6396 xmlFree(local);
6397 xmlFree(prefix);
6398 }
6399 xmlFree(name);
6400 }
6401 }
6402 /*
6403 * 4.16
6404 */
6405 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6406 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6407 if (ctxt->error != NULL)
6408 ctxt->error(ctxt->userData,
6409 "Found nsName/except//nsName forbidden construct\n");
6410 ctxt->nbErrors++;
6411 }
6412 }
6413 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6414 (cur != root)) {
6415 int oldflags = ctxt->flags;
6416
6417 /*
6418 * 4.16
6419 */
6420 if ((cur->parent != NULL) &&
6421 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6422 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6423 xmlRelaxNGCleanupTree(ctxt, cur);
6424 ctxt->flags = oldflags;
6425 goto skip_children;
6426 } else if ((cur->parent != NULL) &&
6427 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6428 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6429 xmlRelaxNGCleanupTree(ctxt, cur);
6430 ctxt->flags = oldflags;
6431 goto skip_children;
6432 }
6433 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6434 /*
6435 * 4.16
6436 */
6437 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6438 if (ctxt->error != NULL)
6439 ctxt->error(ctxt->userData,
6440 "Found anyName/except//anyName forbidden construct\n");
6441 ctxt->nbErrors++;
6442 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6443 if (ctxt->error != NULL)
6444 ctxt->error(ctxt->userData,
6445 "Found nsName/except//anyName forbidden construct\n");
6446 ctxt->nbErrors++;
6447 }
6448 }
6449 /*
6450 * Thisd is not an else since "include" is transformed
6451 * into a div
6452 */
6453 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6454 xmlChar *ns;
6455 xmlNodePtr child, ins, tmp;
6456
6457 /*
6458 * implements rule 4.11
6459 */
6460
6461 ns = xmlGetProp(cur, BAD_CAST "ns");
6462
6463 child = cur->children;
6464 ins = cur;
6465 while (child != NULL) {
6466 if (ns != NULL) {
6467 if (!xmlHasProp(child, BAD_CAST "ns")) {
6468 xmlSetProp(child, BAD_CAST "ns", ns);
6469 }
6470 }
6471 tmp = child->next;
6472 xmlUnlinkNode(child);
6473 ins = xmlAddNextSibling(ins, child);
6474 child = tmp;
6475 }
6476 if (ns != NULL)
6477 xmlFree(ns);
6478 delete = cur;
6479 goto skip_children;
6480 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006481 }
6482 }
6483 /*
6484 * Simplification 4.2 whitespaces
6485 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006486 else if ((cur->type == XML_TEXT_NODE) ||
6487 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006488 if (IS_BLANK_NODE(cur)) {
6489 if (cur->parent->type == XML_ELEMENT_NODE) {
6490 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6491 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6492 delete = cur;
6493 } else {
6494 delete = cur;
6495 goto skip_children;
6496 }
6497 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006498 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006499 delete = cur;
6500 goto skip_children;
6501 }
6502
6503 /*
6504 * Skip to next node
6505 */
6506 if (cur->children != NULL) {
6507 if ((cur->children->type != XML_ENTITY_DECL) &&
6508 (cur->children->type != XML_ENTITY_REF_NODE) &&
6509 (cur->children->type != XML_ENTITY_NODE)) {
6510 cur = cur->children;
6511 continue;
6512 }
6513 }
6514skip_children:
6515 if (cur->next != NULL) {
6516 cur = cur->next;
6517 continue;
6518 }
6519
6520 do {
6521 cur = cur->parent;
6522 if (cur == NULL)
6523 break;
6524 if (cur == root) {
6525 cur = NULL;
6526 break;
6527 }
6528 if (cur->next != NULL) {
6529 cur = cur->next;
6530 break;
6531 }
6532 } while (cur != NULL);
6533 }
6534 if (delete != NULL) {
6535 xmlUnlinkNode(delete);
6536 xmlFreeNode(delete);
6537 delete = NULL;
6538 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006539}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006540
Daniel Veillardc5312d72003-02-21 17:14:10 +00006541/**
6542 * xmlRelaxNGCleanupDoc:
6543 * @ctxt: a Relax-NG parser context
6544 * @doc: an xmldocPtr document pointer
6545 *
6546 * Cleanup the document from unwanted nodes for parsing, resolve
6547 * Include and externalRef lookups.
6548 *
6549 * Returns the cleaned up document or NULL in case of error
6550 */
6551static xmlDocPtr
6552xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6553 xmlNodePtr root;
6554
6555 /*
6556 * Extract the root
6557 */
6558 root = xmlDocGetRootElement(doc);
6559 if (root == NULL) {
6560 if (ctxt->error != NULL)
6561 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6562 ctxt->URL);
6563 ctxt->nbErrors++;
6564 return (NULL);
6565 }
6566 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006567 return(doc);
6568}
6569
6570/**
6571 * xmlRelaxNGParse:
6572 * @ctxt: a Relax-NG parser context
6573 *
6574 * parse a schema definition resource and build an internal
6575 * XML Shema struture which can be used to validate instances.
6576 * *WARNING* this interface is highly subject to change
6577 *
6578 * Returns the internal XML RelaxNG structure built from the resource or
6579 * NULL in case of error
6580 */
6581xmlRelaxNGPtr
6582xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6583{
6584 xmlRelaxNGPtr ret = NULL;
6585 xmlDocPtr doc;
6586 xmlNodePtr root;
6587
6588 xmlRelaxNGInitTypes();
6589
6590 if (ctxt == NULL)
6591 return (NULL);
6592
6593 /*
6594 * First step is to parse the input document into an DOM/Infoset
6595 */
6596 if (ctxt->URL != NULL) {
6597 doc = xmlParseFile((const char *) ctxt->URL);
6598 if (doc == NULL) {
6599 if (ctxt->error != NULL)
6600 ctxt->error(ctxt->userData,
6601 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6602 ctxt->nbErrors++;
6603 return (NULL);
6604 }
6605 } else if (ctxt->buffer != NULL) {
6606 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6607 if (doc == NULL) {
6608 if (ctxt->error != NULL)
6609 ctxt->error(ctxt->userData,
6610 "xmlRelaxNGParse: could not parse schemas\n");
6611 ctxt->nbErrors++;
6612 return (NULL);
6613 }
6614 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6615 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6616 } else {
6617 if (ctxt->error != NULL)
6618 ctxt->error(ctxt->userData,
6619 "xmlRelaxNGParse: nothing to parse\n");
6620 ctxt->nbErrors++;
6621 return (NULL);
6622 }
6623 ctxt->document = doc;
6624
6625 /*
6626 * Some preprocessing of the document content
6627 */
6628 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6629 if (doc == NULL) {
6630 xmlFreeDoc(ctxt->document);
6631 ctxt->document = NULL;
6632 return(NULL);
6633 }
6634
Daniel Veillard6eadf632003-01-23 18:29:16 +00006635 /*
6636 * Then do the parsing for good
6637 */
6638 root = xmlDocGetRootElement(doc);
6639 if (root == NULL) {
6640 if (ctxt->error != NULL)
6641 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6642 ctxt->URL);
6643 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006644 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006645 return (NULL);
6646 }
6647 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006648 if (ret == NULL) {
6649 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006650 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006651 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006652
6653 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006654 * Check the ref/defines links
6655 */
6656 /*
6657 * try to preprocess interleaves
6658 */
6659 if (ctxt->interleaves != NULL) {
6660 xmlHashScan(ctxt->interleaves,
6661 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6662 }
6663
6664 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006665 * if there was a parsing error return NULL
6666 */
6667 if (ctxt->nbErrors > 0) {
6668 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006669 ctxt->document = NULL;
6670 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006671 return(NULL);
6672 }
6673
6674 /*
6675 * Transfer the pointer for cleanup at the schema level.
6676 */
6677 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006678 ctxt->document = NULL;
6679 ret->documents = ctxt->documents;
6680 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006681
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006682 ret->includes = ctxt->includes;
6683 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006684 ret->defNr = ctxt->defNr;
6685 ret->defTab = ctxt->defTab;
6686 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006687 if (ctxt->idref == 1)
6688 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006689
6690 return (ret);
6691}
6692
6693/**
6694 * xmlRelaxNGSetParserErrors:
6695 * @ctxt: a Relax-NG validation context
6696 * @err: the error callback
6697 * @warn: the warning callback
6698 * @ctx: contextual data for the callbacks
6699 *
6700 * Set the callback functions used to handle errors for a validation context
6701 */
6702void
6703xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6704 xmlRelaxNGValidityErrorFunc err,
6705 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6706 if (ctxt == NULL)
6707 return;
6708 ctxt->error = err;
6709 ctxt->warning = warn;
6710 ctxt->userData = ctx;
6711}
6712/************************************************************************
6713 * *
6714 * Dump back a compiled form *
6715 * *
6716 ************************************************************************/
6717static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6718
6719/**
6720 * xmlRelaxNGDumpDefines:
6721 * @output: the file output
6722 * @defines: a list of define structures
6723 *
6724 * Dump a RelaxNG structure back
6725 */
6726static void
6727xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6728 while (defines != NULL) {
6729 xmlRelaxNGDumpDefine(output, defines);
6730 defines = defines->next;
6731 }
6732}
6733
6734/**
6735 * xmlRelaxNGDumpDefine:
6736 * @output: the file output
6737 * @define: a define structure
6738 *
6739 * Dump a RelaxNG structure back
6740 */
6741static void
6742xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6743 if (define == NULL)
6744 return;
6745 switch(define->type) {
6746 case XML_RELAXNG_EMPTY:
6747 fprintf(output, "<empty/>\n");
6748 break;
6749 case XML_RELAXNG_NOT_ALLOWED:
6750 fprintf(output, "<notAllowed/>\n");
6751 break;
6752 case XML_RELAXNG_TEXT:
6753 fprintf(output, "<text/>\n");
6754 break;
6755 case XML_RELAXNG_ELEMENT:
6756 fprintf(output, "<element>\n");
6757 if (define->name != NULL) {
6758 fprintf(output, "<name");
6759 if (define->ns != NULL)
6760 fprintf(output, " ns=\"%s\"", define->ns);
6761 fprintf(output, ">%s</name>\n", define->name);
6762 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006763 xmlRelaxNGDumpDefines(output, define->attrs);
6764 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006765 fprintf(output, "</element>\n");
6766 break;
6767 case XML_RELAXNG_LIST:
6768 fprintf(output, "<list>\n");
6769 xmlRelaxNGDumpDefines(output, define->content);
6770 fprintf(output, "</list>\n");
6771 break;
6772 case XML_RELAXNG_ONEORMORE:
6773 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006774 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006775 fprintf(output, "</oneOrMore>\n");
6776 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006777 case XML_RELAXNG_ZEROORMORE:
6778 fprintf(output, "<zeroOrMore>\n");
6779 xmlRelaxNGDumpDefines(output, define->content);
6780 fprintf(output, "</zeroOrMore>\n");
6781 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006782 case XML_RELAXNG_CHOICE:
6783 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006784 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006785 fprintf(output, "</choice>\n");
6786 break;
6787 case XML_RELAXNG_GROUP:
6788 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006789 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006790 fprintf(output, "</group>\n");
6791 break;
6792 case XML_RELAXNG_INTERLEAVE:
6793 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006794 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006795 fprintf(output, "</interleave>\n");
6796 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006797 case XML_RELAXNG_OPTIONAL:
6798 fprintf(output, "<optional>\n");
6799 xmlRelaxNGDumpDefines(output, define->content);
6800 fprintf(output, "</optional>\n");
6801 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006802 case XML_RELAXNG_ATTRIBUTE:
6803 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006804 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006805 fprintf(output, "</attribute>\n");
6806 break;
6807 case XML_RELAXNG_DEF:
6808 fprintf(output, "<define");
6809 if (define->name != NULL)
6810 fprintf(output, " name=\"%s\"", define->name);
6811 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006812 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006813 fprintf(output, "</define>\n");
6814 break;
6815 case XML_RELAXNG_REF:
6816 fprintf(output, "<ref");
6817 if (define->name != NULL)
6818 fprintf(output, " name=\"%s\"", define->name);
6819 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006820 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006821 fprintf(output, "</ref>\n");
6822 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006823 case XML_RELAXNG_PARENTREF:
6824 fprintf(output, "<parentRef");
6825 if (define->name != NULL)
6826 fprintf(output, " name=\"%s\"", define->name);
6827 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006828 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006829 fprintf(output, "</parentRef>\n");
6830 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006831 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006832 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006833 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006834 fprintf(output, "</externalRef>\n");
6835 break;
6836 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006837 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006838 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006839 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006840 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006841 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006842 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006843 TODO
6844 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006845 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006846 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006847 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006848 }
6849}
6850
6851/**
6852 * xmlRelaxNGDumpGrammar:
6853 * @output: the file output
6854 * @grammar: a grammar structure
6855 * @top: is this a top grammar
6856 *
6857 * Dump a RelaxNG structure back
6858 */
6859static void
6860xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6861{
6862 if (grammar == NULL)
6863 return;
6864
6865 fprintf(output, "<grammar");
6866 if (top)
6867 fprintf(output,
6868 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6869 switch(grammar->combine) {
6870 case XML_RELAXNG_COMBINE_UNDEFINED:
6871 break;
6872 case XML_RELAXNG_COMBINE_CHOICE:
6873 fprintf(output, " combine=\"choice\"");
6874 break;
6875 case XML_RELAXNG_COMBINE_INTERLEAVE:
6876 fprintf(output, " combine=\"interleave\"");
6877 break;
6878 default:
6879 fprintf(output, " <!-- invalid combine value -->");
6880 }
6881 fprintf(output, ">\n");
6882 if (grammar->start == NULL) {
6883 fprintf(output, " <!-- grammar had no start -->");
6884 } else {
6885 fprintf(output, "<start>\n");
6886 xmlRelaxNGDumpDefine(output, grammar->start);
6887 fprintf(output, "</start>\n");
6888 }
6889 /* TODO ? Dump the defines ? */
6890 fprintf(output, "</grammar>\n");
6891}
6892
6893/**
6894 * xmlRelaxNGDump:
6895 * @output: the file output
6896 * @schema: a schema structure
6897 *
6898 * Dump a RelaxNG structure back
6899 */
6900void
6901xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6902{
6903 if (schema == NULL) {
6904 fprintf(output, "RelaxNG empty or failed to compile\n");
6905 return;
6906 }
6907 fprintf(output, "RelaxNG: ");
6908 if (schema->doc == NULL) {
6909 fprintf(output, "no document\n");
6910 } else if (schema->doc->URL != NULL) {
6911 fprintf(output, "%s\n", schema->doc->URL);
6912 } else {
6913 fprintf(output, "\n");
6914 }
6915 if (schema->topgrammar == NULL) {
6916 fprintf(output, "RelaxNG has no top grammar\n");
6917 return;
6918 }
6919 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
6920}
6921
Daniel Veillardfebcca42003-02-16 15:44:18 +00006922/**
6923 * xmlRelaxNGDumpTree:
6924 * @output: the file output
6925 * @schema: a schema structure
6926 *
6927 * Dump the transformed RelaxNG tree.
6928 */
6929void
6930xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
6931{
6932 if (schema == NULL) {
6933 fprintf(output, "RelaxNG empty or failed to compile\n");
6934 return;
6935 }
6936 if (schema->doc == NULL) {
6937 fprintf(output, "no document\n");
6938 } else {
6939 xmlDocDump(output, schema->doc);
6940 }
6941}
6942
Daniel Veillard6eadf632003-01-23 18:29:16 +00006943/************************************************************************
6944 * *
6945 * Validation implementation *
6946 * *
6947 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00006948static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6949 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00006950static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
6951 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006952
6953/**
6954 * xmlRelaxNGSkipIgnored:
6955 * @ctxt: a schema validation context
6956 * @node: the top node.
6957 *
6958 * Skip ignorable nodes in that context
6959 *
6960 * Returns the new sibling or NULL in case of error.
6961 */
6962static xmlNodePtr
6963xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
6964 xmlNodePtr node) {
6965 /*
6966 * TODO complete and handle entities
6967 */
6968 while ((node != NULL) &&
6969 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00006970 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006971 (((node->type == XML_TEXT_NODE) ||
6972 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00006973 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
6974 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006975 node = node->next;
6976 }
6977 return(node);
6978}
6979
6980/**
Daniel Veillardedc91922003-01-26 00:52:04 +00006981 * xmlRelaxNGNormalize:
6982 * @ctxt: a schema validation context
6983 * @str: the string to normalize
6984 *
6985 * Implements the normalizeWhiteSpace( s ) function from
6986 * section 6.2.9 of the spec
6987 *
6988 * Returns the new string or NULL in case of error.
6989 */
6990static xmlChar *
6991xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
6992 xmlChar *ret, *p;
6993 const xmlChar *tmp;
6994 int len;
6995
6996 if (str == NULL)
6997 return(NULL);
6998 tmp = str;
6999 while (*tmp != 0) tmp++;
7000 len = tmp - str;
7001
7002 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7003 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007004 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007005 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007006 } else {
7007 xmlGenericError(xmlGenericErrorContext,
7008 "xmlRelaxNGNormalize: out of memory\n");
7009 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007010 return(NULL);
7011 }
7012 p = ret;
7013 while (IS_BLANK(*str)) str++;
7014 while (*str != 0) {
7015 if (IS_BLANK(*str)) {
7016 while (IS_BLANK(*str)) str++;
7017 if (*str == 0)
7018 break;
7019 *p++ = ' ';
7020 } else
7021 *p++ = *str++;
7022 }
7023 *p = 0;
7024 return(ret);
7025}
7026
7027/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007028 * xmlRelaxNGValidateDatatype:
7029 * @ctxt: a Relax-NG validation context
7030 * @value: the string value
7031 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007032 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007033 *
7034 * Validate the given value against the dataype
7035 *
7036 * Returns 0 if the validation succeeded or an error code.
7037 */
7038static int
7039xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007040 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007041 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007042 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007043 void *result = NULL;
7044 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007045
7046 if ((define == NULL) || (define->data == NULL)) {
7047 return(-1);
7048 }
7049 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007050 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007051 if ((define->attrs != NULL) &&
7052 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007053 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007054 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007055 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007056 }
7057 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007058 ret = -1;
7059 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007060 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007061 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7062 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007063 return(-1);
7064 } else if (ret == 1) {
7065 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007066 } else if (ret == 2) {
7067 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007068 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007069 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007070 ret = -1;
7071 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007072 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007073 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7074 if (lib->facet != NULL) {
7075 tmp = lib->facet(lib->data, define->name, cur->name,
7076 cur->value, value, result);
7077 if (tmp != 0)
7078 ret = -1;
7079 }
7080 cur = cur->next;
7081 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007082 if ((ret == 0) && (define->content != NULL)) {
7083 const xmlChar *oldvalue, *oldendvalue;
7084
7085 oldvalue = ctxt->state->value;
7086 oldendvalue = ctxt->state->endvalue;
7087 ctxt->state->value = (xmlChar *) value;
7088 ctxt->state->endvalue = NULL;
7089 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7090 ctxt->state->value = (xmlChar *) oldvalue;
7091 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7092 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007093 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7094 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007095 return(ret);
7096}
7097
7098/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007099 * xmlRelaxNGNextValue:
7100 * @ctxt: a Relax-NG validation context
7101 *
7102 * Skip to the next value when validating within a list
7103 *
7104 * Returns 0 if the operation succeeded or an error code.
7105 */
7106static int
7107xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7108 xmlChar *cur;
7109
7110 cur = ctxt->state->value;
7111 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7112 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007113 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007114 return(0);
7115 }
7116 while (*cur != 0) cur++;
7117 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7118 if (cur == ctxt->state->endvalue)
7119 ctxt->state->value = NULL;
7120 else
7121 ctxt->state->value = cur;
7122 return(0);
7123}
7124
7125/**
7126 * xmlRelaxNGValidateValueList:
7127 * @ctxt: a Relax-NG validation context
7128 * @defines: the list of definitions to verify
7129 *
7130 * Validate the given set of definitions for the current value
7131 *
7132 * Returns 0 if the validation succeeded or an error code.
7133 */
7134static int
7135xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7136 xmlRelaxNGDefinePtr defines) {
7137 int ret = 0;
7138
7139 while (defines != NULL) {
7140 ret = xmlRelaxNGValidateValue(ctxt, defines);
7141 if (ret != 0)
7142 break;
7143 defines = defines->next;
7144 }
7145 return(ret);
7146}
7147
7148/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007149 * xmlRelaxNGValidateValue:
7150 * @ctxt: a Relax-NG validation context
7151 * @define: the definition to verify
7152 *
7153 * Validate the given definition for the current value
7154 *
7155 * Returns 0 if the validation succeeded or an error code.
7156 */
7157static int
7158xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7159 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007160 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007161 xmlChar *value;
7162
7163 value = ctxt->state->value;
7164 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007165 case XML_RELAXNG_EMPTY: {
7166 if ((value != NULL) && (value[0] != 0)) {
7167 int idx = 0;
7168
7169 while (IS_BLANK(value[idx]))
7170 idx++;
7171 if (value[idx] != 0)
7172 ret = -1;
7173 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007174 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007175 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007176 case XML_RELAXNG_TEXT:
7177 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007178 case XML_RELAXNG_VALUE: {
7179 if (!xmlStrEqual(value, define->value)) {
7180 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007181 xmlRelaxNGTypeLibraryPtr lib;
7182
7183 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
7184 if ((lib != NULL) && (lib->comp != NULL))
7185 ret = lib->comp(lib->data, define->name, value,
7186 define->value);
7187 else
7188 ret = -1;
7189 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007190 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007191 return(-1);
7192 } else if (ret == 1) {
7193 ret = 0;
7194 } else {
7195 ret = -1;
7196 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007197 } else {
7198 xmlChar *nval, *nvalue;
7199
7200 /*
7201 * TODO: trivial optimizations are possible by
7202 * computing at compile-time
7203 */
7204 nval = xmlRelaxNGNormalize(ctxt, define->value);
7205 nvalue = xmlRelaxNGNormalize(ctxt, value);
7206
Daniel Veillardea3f3982003-01-26 19:45:18 +00007207 if ((nval == NULL) || (nvalue == NULL) ||
7208 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007209 ret = -1;
7210 if (nval != NULL)
7211 xmlFree(nval);
7212 if (nvalue != NULL)
7213 xmlFree(nvalue);
7214 }
7215 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007216 if (ret == 0)
7217 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007218 break;
7219 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007220 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007221 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7222 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007223 if (ret == 0)
7224 xmlRelaxNGNextValue(ctxt);
7225
7226 break;
7227 }
7228 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007229 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007230 xmlChar *oldvalue;
7231
7232 oldflags = ctxt->flags;
7233 ctxt->flags |= FLAGS_IGNORABLE;
7234
7235 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007236 while (list != NULL) {
7237 ret = xmlRelaxNGValidateValue(ctxt, list);
7238 if (ret == 0) {
7239 break;
7240 }
7241 ctxt->state->value = oldvalue;
7242 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007243 }
7244 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007245 if (ret != 0) {
7246 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7247 xmlRelaxNGDumpValidError(ctxt);
7248 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007249 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007250 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007251 if (ret == 0)
7252 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007253 break;
7254 }
7255 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007256 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007257 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007258#ifdef DEBUG_LIST
7259 int nb_values = 0;
7260#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007261
7262 oldvalue = ctxt->state->value;
7263 oldend = ctxt->state->endvalue;
7264
7265 val = xmlStrdup(oldvalue);
7266 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007267 val = xmlStrdup(BAD_CAST "");
7268 }
7269 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007270 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007271 return(-1);
7272 }
7273 cur = val;
7274 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007275 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007276 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007277 cur++;
7278#ifdef DEBUG_LIST
7279 nb_values++;
7280#endif
7281 while (IS_BLANK(*cur))
7282 *cur++ = 0;
7283 } else
7284 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007285 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007286#ifdef DEBUG_LIST
7287 xmlGenericError(xmlGenericErrorContext,
7288 "list value: '%s' found %d items\n", oldvalue, nb_values);
7289 nb_values = 0;
7290#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007291 ctxt->state->endvalue = cur;
7292 cur = val;
7293 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007294
Daniel Veillardfd573f12003-03-16 17:52:32 +00007295 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007296
Daniel Veillardfd573f12003-03-16 17:52:32 +00007297 while (list != NULL) {
7298 if (ctxt->state->value == ctxt->state->endvalue)
7299 ctxt->state->value = NULL;
7300 ret = xmlRelaxNGValidateValue(ctxt, list);
7301 if (ret != 0) {
7302#ifdef DEBUG_LIST
7303 xmlGenericError(xmlGenericErrorContext,
7304 "Failed to validate value: '%s' with %d rule\n",
7305 ctxt->state->value, nb_values);
7306#endif
7307 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007308 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007309#ifdef DEBUG_LIST
7310 nb_values++;
7311#endif
7312 list = list->next;
7313 }
7314
7315 if ((ret == 0) && (ctxt->state->value != NULL) &&
7316 (ctxt->state->value != ctxt->state->endvalue)) {
7317 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7318 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007319 }
7320 xmlFree(val);
7321 ctxt->state->value = oldvalue;
7322 ctxt->state->endvalue = oldend;
7323 break;
7324 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007325 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007326 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7327 if (ret != 0) {
7328 break;
7329 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007330 /* no break on purpose */
7331 case XML_RELAXNG_ZEROORMORE: {
7332 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007333
7334 oldflags = ctxt->flags;
7335 ctxt->flags |= FLAGS_IGNORABLE;
7336 cur = ctxt->state->value;
7337 temp = NULL;
7338 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7339 (temp != cur)) {
7340 temp = cur;
7341 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7342 if (ret != 0) {
7343 ctxt->state->value = temp;
7344 ret = 0;
7345 break;
7346 }
7347 cur = ctxt->state->value;
7348 }
7349 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007350 if (ret != 0) {
7351 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7352 xmlRelaxNGDumpValidError(ctxt);
7353 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007354 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007355 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007356 break;
7357 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007358 case XML_RELAXNG_EXCEPT: {
7359 xmlRelaxNGDefinePtr list;
7360
7361 list = define->content;
7362 while (list != NULL) {
7363 ret = xmlRelaxNGValidateValue(ctxt, list);
7364 if (ret == 0) {
7365 ret = -1;
7366 break;
7367 } else
7368 ret = 0;
7369 list = list->next;
7370 }
7371 break;
7372 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007373 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007374 case XML_RELAXNG_GROUP: {
7375 xmlRelaxNGDefinePtr list;
7376
7377 list = define->content;
7378 while (list != NULL) {
7379 ret = xmlRelaxNGValidateValue(ctxt, list);
7380 if (ret != 0) {
7381 ret = -1;
7382 break;
7383 } else
7384 ret = 0;
7385 list = list->next;
7386 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007387 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007388 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007389 case XML_RELAXNG_REF:
7390 case XML_RELAXNG_PARENTREF:
7391 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7392 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007393 default:
7394 TODO
7395 ret = -1;
7396 }
7397 return(ret);
7398}
7399
7400/**
7401 * xmlRelaxNGValidateValueContent:
7402 * @ctxt: a Relax-NG validation context
7403 * @defines: the list of definitions to verify
7404 *
7405 * Validate the given definitions for the current value
7406 *
7407 * Returns 0 if the validation succeeded or an error code.
7408 */
7409static int
7410xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7411 xmlRelaxNGDefinePtr defines) {
7412 int ret = 0;
7413
7414 while (defines != NULL) {
7415 ret = xmlRelaxNGValidateValue(ctxt, defines);
7416 if (ret != 0)
7417 break;
7418 defines = defines->next;
7419 }
7420 return(ret);
7421}
7422
7423/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007424 * xmlRelaxNGAttributeMatch:
7425 * @ctxt: a Relax-NG validation context
7426 * @define: the definition to check
7427 * @prop: the attribute
7428 *
7429 * Check if the attribute matches the definition nameClass
7430 *
7431 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7432 */
7433static int
7434xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7435 xmlRelaxNGDefinePtr define,
7436 xmlAttrPtr prop) {
7437 int ret;
7438
7439 if (define->name != NULL) {
7440 if (!xmlStrEqual(define->name, prop->name))
7441 return(0);
7442 }
7443 if (define->ns != NULL) {
7444 if (define->ns[0] == 0) {
7445 if (prop->ns != NULL)
7446 return(0);
7447 } else {
7448 if ((prop->ns == NULL) ||
7449 (!xmlStrEqual(define->ns, prop->ns->href)))
7450 return(0);
7451 }
7452 }
7453 if (define->nameClass == NULL)
7454 return(1);
7455 define = define->nameClass;
7456 if (define->type == XML_RELAXNG_EXCEPT) {
7457 xmlRelaxNGDefinePtr list;
7458
7459 list = define->content;
7460 while (list != NULL) {
7461 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7462 if (ret == 1)
7463 return(0);
7464 if (ret < 0)
7465 return(ret);
7466 list = list->next;
7467 }
7468 } else {
7469 TODO
7470 }
7471 return(1);
7472}
7473
7474/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007475 * xmlRelaxNGValidateAttribute:
7476 * @ctxt: a Relax-NG validation context
7477 * @define: the definition to verify
7478 *
7479 * Validate the given attribute definition for that node
7480 *
7481 * Returns 0 if the validation succeeded or an error code.
7482 */
7483static int
7484xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7485 xmlRelaxNGDefinePtr define) {
7486 int ret = 0, i;
7487 xmlChar *value, *oldvalue;
7488 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007489 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007490
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007491 if (ctxt->state->nbAttrLeft <= 0)
7492 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007493 if (define->name != NULL) {
7494 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7495 tmp = ctxt->state->attrs[i];
7496 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7497 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7498 (tmp->ns == NULL)) ||
7499 ((tmp->ns != NULL) &&
7500 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7501 prop = tmp;
7502 break;
7503 }
7504 }
7505 }
7506 if (prop != NULL) {
7507 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7508 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007509 oldseq = ctxt->state->seq;
7510 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007511 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007512 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007513 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007514 if (ctxt->state->value != NULL)
7515 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007516 if (value != NULL)
7517 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007518 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007519 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007520 if (ret == 0) {
7521 /*
7522 * flag the attribute as processed
7523 */
7524 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007525 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007526 }
7527 } else {
7528 ret = -1;
7529 }
7530#ifdef DEBUG
7531 xmlGenericError(xmlGenericErrorContext,
7532 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7533#endif
7534 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007535 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7536 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007537 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007538 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007539 prop = tmp;
7540 break;
7541 }
7542 }
7543 if (prop != NULL) {
7544 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7545 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007546 oldseq = ctxt->state->seq;
7547 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007548 ctxt->state->value = value;
7549 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007550 if (ctxt->state->value != NULL)
7551 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007552 if (value != NULL)
7553 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007554 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007555 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007556 if (ret == 0) {
7557 /*
7558 * flag the attribute as processed
7559 */
7560 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007561 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007562 }
7563 } else {
7564 ret = -1;
7565 }
7566#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007567 if (define->ns != NULL) {
7568 xmlGenericError(xmlGenericErrorContext,
7569 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7570 define->ns, ret);
7571 } else {
7572 xmlGenericError(xmlGenericErrorContext,
7573 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7574 ret);
7575 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007576#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007577 }
7578
7579 return(ret);
7580}
7581
7582/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007583 * xmlRelaxNGValidateAttributeList:
7584 * @ctxt: a Relax-NG validation context
7585 * @define: the list of definition to verify
7586 *
7587 * Validate the given node against the list of attribute definitions
7588 *
7589 * Returns 0 if the validation succeeded or an error code.
7590 */
7591static int
7592xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7593 xmlRelaxNGDefinePtr defines) {
7594 int ret = 0;
7595 while (defines != NULL) {
7596 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7597 ret = -1;
7598 defines = defines->next;
7599 }
7600 return(ret);
7601}
7602
7603/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007604 * xmlRelaxNGNodeMatchesList:
7605 * @node: the node
7606 * @list: a NULL terminated array of definitions
7607 *
7608 * Check if a node can be matched by one of the definitions
7609 *
7610 * Returns 1 if matches 0 otherwise
7611 */
7612static int
7613xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7614 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007615 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007616
7617 if ((node == NULL) || (list == NULL))
7618 return(0);
7619
7620 cur = list[i++];
7621 while (cur != NULL) {
7622 if ((node->type == XML_ELEMENT_NODE) &&
7623 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007624 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7625 if (tmp == 1)
7626 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007627 } else if (((node->type == XML_TEXT_NODE) ||
7628 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007629 (cur->type == XML_RELAXNG_TEXT)) {
7630 return(1);
7631 }
7632 cur = list[i++];
7633 }
7634 return(0);
7635}
7636
7637/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007638 * xmlRelaxNGValidateInterleave:
7639 * @ctxt: a Relax-NG validation context
7640 * @define: the definition to verify
7641 *
7642 * Validate an interleave definition for a node.
7643 *
7644 * Returns 0 if the validation succeeded or an error code.
7645 */
7646static int
7647xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7648 xmlRelaxNGDefinePtr define) {
7649 int ret = 0, i, nbgroups, left;
7650 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007651 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007652
7653 xmlRelaxNGValidStatePtr oldstate;
7654 xmlRelaxNGPartitionPtr partitions;
7655 xmlRelaxNGInterleaveGroupPtr group = NULL;
7656 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7657 xmlNodePtr *list = NULL, *lasts = NULL;
7658
7659 if (define->data != NULL) {
7660 partitions = (xmlRelaxNGPartitionPtr) define->data;
7661 nbgroups = partitions->nbgroups;
7662 left = nbgroups;
7663 } else {
7664 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7665 return(-1);
7666 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007667 /*
7668 * Optimizations for MIXED
7669 */
7670 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007671 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007672 ctxt->flags |= FLAGS_MIXED_CONTENT;
7673 if (nbgroups == 2) {
7674 /*
7675 * this is a pure <mixed> case
7676 */
7677 if (ctxt->state != NULL)
7678 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7679 ctxt->state->seq);
7680 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7681 ret = xmlRelaxNGValidateDefinition(ctxt,
7682 partitions->groups[1]->rule);
7683 else
7684 ret = xmlRelaxNGValidateDefinition(ctxt,
7685 partitions->groups[0]->rule);
7686 if (ret == 0) {
7687 if (ctxt->state != NULL)
7688 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7689 ctxt->state->seq);
7690 }
7691 ctxt->flags = oldflags;
7692 return(ret);
7693 }
7694 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007695
7696 /*
7697 * Build arrays to store the first and last node of the chain
7698 * pertaining to each group
7699 */
7700 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7701 if (list == NULL) {
7702 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7703 return(-1);
7704 }
7705 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7706 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7707 if (lasts == NULL) {
7708 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7709 return(-1);
7710 }
7711 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7712
7713 /*
7714 * Walk the sequence of children finding the right group and
7715 * sorting them in sequences.
7716 */
7717 cur = ctxt->state->seq;
7718 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7719 start = cur;
7720 while (cur != NULL) {
7721 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007722 if ((partitions->triage != NULL) &&
7723 (partitions->flags & IS_DETERMINIST)) {
7724 void *tmp = NULL;
7725
7726 if ((cur->type == XML_TEXT_NODE) ||
7727 (cur->type == XML_CDATA_SECTION_NODE)) {
7728 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7729 NULL);
7730 } else if (cur->type == XML_ELEMENT_NODE) {
7731 if (cur->ns != NULL) {
7732 tmp = xmlHashLookup2(partitions->triage, cur->name,
7733 cur->ns->href);
7734 if (tmp == NULL)
7735 tmp = xmlHashLookup2(partitions->triage,
7736 BAD_CAST "#any", cur->ns->href);
7737 } else
7738 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7739 if (tmp == NULL)
7740 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7741 NULL);
7742 }
7743
7744 if (tmp == NULL) {
7745 i = nbgroups;
7746 } else {
7747 i = ((long) tmp) - 1;
7748 if (partitions->flags & IS_NEEDCHECK) {
7749 group = partitions->groups[i];
7750 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7751 i = nbgroups;
7752 }
7753 }
7754 } else {
7755 for (i = 0;i < nbgroups;i++) {
7756 group = partitions->groups[i];
7757 if (group == NULL)
7758 continue;
7759 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7760 break;
7761 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007762 }
7763 /*
7764 * We break as soon as an element not matched is found
7765 */
7766 if (i >= nbgroups) {
7767 break;
7768 }
7769 if (lasts[i] != NULL) {
7770 lasts[i]->next = cur;
7771 lasts[i] = cur;
7772 } else {
7773 list[i] = cur;
7774 lasts[i] = cur;
7775 }
7776 if (cur->next != NULL)
7777 lastchg = cur->next;
7778 else
7779 lastchg = cur;
7780 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7781 }
7782 if (ret != 0) {
7783 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7784 ret = -1;
7785 goto done;
7786 }
7787 lastelem = cur;
7788 oldstate = ctxt->state;
7789 for (i = 0;i < nbgroups;i++) {
7790 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7791 group = partitions->groups[i];
7792 if (lasts[i] != NULL) {
7793 last = lasts[i]->next;
7794 lasts[i]->next = NULL;
7795 }
7796 ctxt->state->seq = list[i];
7797 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7798 if (ret != 0)
7799 break;
7800 if (ctxt->state != NULL) {
7801 cur = ctxt->state->seq;
7802 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007803 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007804 oldstate = ctxt->state;
7805 ctxt->state = NULL;
7806 if (cur != NULL) {
7807 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7808 ret = -1;
7809 ctxt->state = oldstate;
7810 goto done;
7811 }
7812 } else if (ctxt->states != NULL) {
7813 int j;
7814 int found = 0;
7815
7816 for (j = 0;j < ctxt->states->nbState;j++) {
7817 cur = ctxt->states->tabState[j]->seq;
7818 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7819 if (cur == NULL) {
7820 found = 1;
7821 break;
7822 }
7823 }
7824 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007825 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007826 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7827 }
7828 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007829 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007830 }
7831 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7832 ctxt->states = NULL;
7833 if (found == 0) {
7834 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7835 ret = -1;
7836 ctxt->state = oldstate;
7837 goto done;
7838 }
7839 } else {
7840 ret = -1;
7841 break;
7842 }
7843 if (lasts[i] != NULL) {
7844 lasts[i]->next = last;
7845 }
7846 }
7847 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007848 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007849 ctxt->state = oldstate;
7850 ctxt->state->seq = lastelem;
7851 if (ret != 0) {
7852 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7853 ret = -1;
7854 goto done;
7855 }
7856
7857done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007858 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007859 /*
7860 * builds the next links chain from the prev one
7861 */
7862 cur = lastchg;
7863 while (cur != NULL) {
7864 if ((cur == start) || (cur->prev == NULL))
7865 break;
7866 cur->prev->next = cur;
7867 cur = cur->prev;
7868 }
7869 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007870 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007871 }
7872
7873 xmlFree(list);
7874 xmlFree(lasts);
7875 return(ret);
7876}
7877
7878/**
7879 * xmlRelaxNGValidateDefinitionList:
7880 * @ctxt: a Relax-NG validation context
7881 * @define: the list of definition to verify
7882 *
7883 * Validate the given node content against the (list) of definitions
7884 *
7885 * Returns 0 if the validation succeeded or an error code.
7886 */
7887static int
7888xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7889 xmlRelaxNGDefinePtr defines) {
7890 int ret = 0, res;
7891
7892
Daniel Veillard952379b2003-03-17 15:37:12 +00007893 if (defines == NULL) {
7894 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7895 return(-1);
7896 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007897 while (defines != NULL) {
7898 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7899 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7900 if (res < 0)
7901 ret = -1;
7902 } else {
7903 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7904 return(-1);
7905 }
7906 if (ret < 0)
7907 break;
7908 defines = defines->next;
7909 }
7910
7911 return(ret);
7912}
7913
7914/**
7915 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00007916 * @ctxt: a Relax-NG validation context
7917 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00007918 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00007919 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007920 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00007921 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00007922 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00007923 */
7924static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00007925xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
7926 xmlRelaxNGDefinePtr define,
7927 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00007928 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007929
Daniel Veillardfd573f12003-03-16 17:52:32 +00007930 if (define->name != NULL) {
7931 if (!xmlStrEqual(elem->name, define->name)) {
7932 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
7933 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007934 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007935 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007936 if ((define->ns != NULL) && (define->ns[0] != 0)) {
7937 if (elem->ns == NULL) {
7938 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
7939 elem->name);
7940 return(0);
7941 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
7942 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
7943 elem->name, define->ns);
7944 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007945 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007946 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
7947 (define->name == NULL)) {
7948 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7949 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007950 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007951 } else if ((elem->ns != NULL) && (define->name != NULL)) {
7952 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
7953 define->name);
7954 return(0);
7955 }
7956
7957 if (define->nameClass == NULL)
7958 return(1);
7959
7960 define = define->nameClass;
7961 if (define->type == XML_RELAXNG_EXCEPT) {
7962 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007963 if (ctxt != NULL) {
7964 oldflags = ctxt->flags;
7965 ctxt->flags |= FLAGS_IGNORABLE;
7966 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007967
7968 list = define->content;
7969 while (list != NULL) {
7970 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7971 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007972 if (ctxt != NULL)
7973 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007974 return(0);
7975 }
7976 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007977 if (ctxt != NULL)
7978 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007979 return(ret);
7980 }
7981 list = list->next;
7982 }
7983 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007984 if (ctxt != NULL) {
7985 ctxt->flags = oldflags;
7986 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007987 } else if (define->type == XML_RELAXNG_CHOICE) {
7988 xmlRelaxNGDefinePtr list;
7989
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007990 if (ctxt != NULL) {
7991 oldflags = ctxt->flags;
7992 ctxt->flags |= FLAGS_IGNORABLE;
7993 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007994
7995 list = define->nameClass;
7996 while (list != NULL) {
7997 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
7998 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007999 if (ctxt != NULL)
8000 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008001 return(1);
8002 }
8003 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008004 if (ctxt != NULL)
8005 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008006 return(ret);
8007 }
8008 list = list->next;
8009 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008010 if (ctxt != NULL) {
8011 if (ret != 0) {
8012 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8013 xmlRelaxNGDumpValidError(ctxt);
8014 } else {
8015 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8016 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008017 }
8018 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008019 if (ctxt != NULL) {
8020 ctxt->flags = oldflags;
8021 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008022 } else {
8023 TODO
8024 ret = -1;
8025 }
8026 return(ret);
8027}
8028
8029/**
8030 * xmlRelaxNGValidateElementEnd:
8031 * @ctxt: a Relax-NG validation context
8032 *
8033 * Validate the end of the element, implements check that
8034 * there is nothing left not consumed in the element content
8035 * or in the attribute list.
8036 *
8037 * Returns 0 if the validation succeeded or an error code.
8038 */
8039static int
8040xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8041 int ret = 0, i;
8042 xmlRelaxNGValidStatePtr state;
8043
8044 state = ctxt->state;
8045 if (state->seq != NULL) {
8046 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8047 if (state->seq != NULL) {
8048 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8049 state->node->name, state->seq->name);
8050 ret = -1;
8051 }
8052 }
8053 for (i = 0;i < state->nbAttrs;i++) {
8054 if (state->attrs[i] != NULL) {
8055 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8056 state->attrs[i]->name, state->node->name);
8057 ret = -1;
8058 }
8059 }
8060 return(ret);
8061}
8062
8063/**
8064 * xmlRelaxNGValidateState:
8065 * @ctxt: a Relax-NG validation context
8066 * @define: the definition to verify
8067 *
8068 * Validate the current state against the definition
8069 *
8070 * Returns 0 if the validation succeeded or an error code.
8071 */
8072static int
8073xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8074 xmlRelaxNGDefinePtr define) {
8075 xmlNodePtr node;
8076 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008077 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008078
8079 if (define == NULL) {
8080 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8081 return(-1);
8082 }
8083
8084 if (ctxt->state != NULL) {
8085 node = ctxt->state->seq;
8086 } else {
8087 node = NULL;
8088 }
8089#ifdef DEBUG
8090 for (i = 0;i < ctxt->depth;i++)
8091 xmlGenericError(xmlGenericErrorContext, " ");
8092 xmlGenericError(xmlGenericErrorContext,
8093 "Start validating %s ", xmlRelaxNGDefName(define));
8094 if (define->name != NULL)
8095 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8096 if ((node != NULL) && (node->name != NULL))
8097 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8098 else
8099 xmlGenericError(xmlGenericErrorContext, "\n");
8100#endif
8101 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008102 switch (define->type) {
8103 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008104 node = xmlRelaxNGSkipIgnored(ctxt, node);
8105 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008106 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008107 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008108 ret = -1;
8109 break;
8110 case XML_RELAXNG_TEXT:
8111 while ((node != NULL) &&
8112 ((node->type == XML_TEXT_NODE) ||
8113 (node->type == XML_COMMENT_NODE) ||
8114 (node->type == XML_PI_NODE) ||
8115 (node->type == XML_CDATA_SECTION_NODE)))
8116 node = node->next;
8117 ctxt->state->seq = node;
8118 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008119 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008120 errNr = ctxt->errNr;
8121 node = xmlRelaxNGSkipIgnored(ctxt, node);
8122 if (node == NULL) {
8123 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8124 ret = -1;
8125 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8126 xmlRelaxNGDumpValidError(ctxt);
8127 break;
8128 }
8129 if (node->type != XML_ELEMENT_NODE) {
8130 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8131 ret = -1;
8132 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8133 xmlRelaxNGDumpValidError(ctxt);
8134 break;
8135 }
8136 /*
8137 * This node was already validated successfully against
8138 * this definition.
8139 */
8140 if (node->_private == define) {
8141 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard580ced82003-03-21 21:22:48 +00008142 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008143 if (ctxt->errNr != 0) {
8144 while ((ctxt->err != NULL) &&
8145 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8146 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008147 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8148 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008149 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8150 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8151 xmlRelaxNGValidErrorPop(ctxt);
8152 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008153 break;
8154 }
8155
8156 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8157 if (ret <= 0) {
8158 ret = -1;
8159 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8160 xmlRelaxNGDumpValidError(ctxt);
8161 break;
8162 }
8163 ret = 0;
8164 if (ctxt->errNr != 0) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008165 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008166 while ((ctxt->err != NULL) &&
8167 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8168 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008169 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8170 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00008171 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8172 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8173 xmlRelaxNGValidErrorPop(ctxt);
8174 }
8175 errNr = ctxt->errNr;
8176
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008177 oldflags = ctxt->flags;
8178 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8179 ctxt->flags -= FLAGS_MIXED_CONTENT;
8180 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008181 state = xmlRelaxNGNewValidState(ctxt, node);
8182 if (state == NULL) {
8183 ret = -1;
8184 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8185 xmlRelaxNGDumpValidError(ctxt);
8186 break;
8187 }
8188
8189 oldstate = ctxt->state;
8190 ctxt->state = state;
8191 if (define->attrs != NULL) {
8192 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8193 if (tmp != 0) {
8194 ret = -1;
8195 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8196 }
8197 }
8198 if (define->content != NULL) {
8199 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8200 if (tmp != 0) {
8201 ret = -1;
8202 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8203 }
8204 }
8205 if (ctxt->states != NULL) {
8206 tmp = -1;
8207
Daniel Veillardfd573f12003-03-16 17:52:32 +00008208 ctxt->flags |= FLAGS_IGNORABLE;
8209
8210 for (i = 0;i < ctxt->states->nbState;i++) {
8211 state = ctxt->states->tabState[i];
8212 ctxt->state = state;
8213
8214 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8215 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008216 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008217 }
8218 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8219 ctxt->flags = oldflags;
8220 ctxt->states = NULL;
8221 if ((ret == 0) && (tmp == -1))
8222 ret = -1;
8223 } else {
8224 state = ctxt->state;
8225 if (ret == 0)
8226 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008227 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008228 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008229 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008230 ctxt->state = oldstate;
8231 if (oldstate != NULL)
8232 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8233 if (ret == 0) {
8234 node->_private = define;
8235 }
8236 if (ret != 0) {
8237 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8238 xmlRelaxNGDumpValidError(ctxt);
8239 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008240 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008241 }
8242
8243#ifdef DEBUG
8244 xmlGenericError(xmlGenericErrorContext,
8245 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8246 node->name, ret);
8247 if (oldstate == NULL)
8248 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8249 else if (oldstate->seq == NULL)
8250 xmlGenericError(xmlGenericErrorContext, ": done\n");
8251 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8252 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8253 oldstate->seq->name);
8254 else
8255 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8256 oldstate->seq->name, oldstate->seq->type);
8257#endif
8258 break;
8259 case XML_RELAXNG_OPTIONAL: {
8260 oldflags = ctxt->flags;
8261 ctxt->flags |= FLAGS_IGNORABLE;
8262 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8263 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8264 if (ret != 0) {
8265 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008266 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008267 ctxt->state = oldstate;
8268 ctxt->flags = oldflags;
8269 ret = 0;
8270 break;
8271 }
8272 if (ctxt->states != NULL) {
8273 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8274 } else {
8275 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8276 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008277 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008278 ctxt->flags = oldflags;
8279 ret = -1;
8280 break;
8281 }
8282 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8283 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8284 ctxt->state = NULL;
8285 }
8286 ctxt->flags = oldflags;
8287 ret = 0;
8288 break;
8289 }
8290 case XML_RELAXNG_ONEORMORE:
8291 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8292 if (ret != 0) {
8293 break;
8294 }
8295 /* no break on purpose */
8296 case XML_RELAXNG_ZEROORMORE: {
8297 int progress;
8298 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8299 int base, j;
8300
8301 res = xmlRelaxNGNewStates(ctxt, 1);
8302 if (res == NULL) {
8303 ret = -1;
8304 break;
8305 }
8306 /*
8307 * All the input states are also exit states
8308 */
8309 if (ctxt->state != NULL) {
8310 xmlRelaxNGAddStates(ctxt, res,
8311 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8312 } else {
8313 for (j = 0;j < ctxt->states->nbState;j++) {
8314 xmlRelaxNGAddStates(ctxt, res,
8315 xmlRelaxNGCopyValidState(ctxt,
8316 ctxt->states->tabState[j]));
8317 }
8318 }
8319 oldflags = ctxt->flags;
8320 ctxt->flags |= FLAGS_IGNORABLE;
8321 do {
8322 progress = 0;
8323 base = res->nbState;
8324
8325 if (ctxt->states != NULL) {
8326 states = ctxt->states;
8327 for (i = 0;i < states->nbState;i++) {
8328 ctxt->state = states->tabState[i];
8329 ctxt->states = NULL;
8330 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8331 define->content);
8332 if (ret == 0) {
8333 if (ctxt->state != NULL) {
8334 tmp = xmlRelaxNGAddStates(ctxt, res,
8335 ctxt->state);
8336 ctxt->state = NULL;
8337 if (tmp == 1)
8338 progress = 1;
8339 } else if (ctxt->states != NULL) {
8340 for (j = 0;j < ctxt->states->nbState;j++) {
8341 tmp = xmlRelaxNGAddStates(ctxt, res,
8342 ctxt->states->tabState[j]);
8343 if (tmp == 1)
8344 progress = 1;
8345 }
8346 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8347 ctxt->states = NULL;
8348 }
8349 } else {
8350 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008351 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008352 ctxt->state = NULL;
8353 }
8354 }
8355 }
8356 } else {
8357 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8358 define->content);
8359 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008360 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008361 ctxt->state = NULL;
8362 } else {
8363 base = res->nbState;
8364 if (ctxt->state != NULL) {
8365 tmp = xmlRelaxNGAddStates(ctxt, res,
8366 ctxt->state);
8367 ctxt->state = NULL;
8368 if (tmp == 1)
8369 progress = 1;
8370 } else if (ctxt->states != NULL) {
8371 for (j = 0;j < ctxt->states->nbState;j++) {
8372 tmp = xmlRelaxNGAddStates(ctxt, res,
8373 ctxt->states->tabState[j]);
8374 if (tmp == 1)
8375 progress = 1;
8376 }
8377 if (states == NULL) {
8378 states = ctxt->states;
8379 } else {
8380 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8381 }
8382 ctxt->states = NULL;
8383 }
8384 }
8385 }
8386 if (progress) {
8387 /*
8388 * Collect all the new nodes added at that step
8389 * and make them the new node set
8390 */
8391 if (res->nbState - base == 1) {
8392 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8393 res->tabState[base]);
8394 } else {
8395 if (states == NULL) {
8396 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8397 }
8398 states->nbState = 0;
8399 for (i = base;i < res->nbState;i++)
8400 xmlRelaxNGAddStates(ctxt, states,
8401 xmlRelaxNGCopyValidState(ctxt,
8402 res->tabState[i]));
8403 ctxt->states = states;
8404 }
8405 }
8406 } while (progress == 1);
8407 if (states != NULL) {
8408 xmlRelaxNGFreeStates(ctxt, states);
8409 }
8410 ctxt->states = res;
8411 ctxt->flags = oldflags;
8412 ret = 0;
8413 break;
8414 }
8415 case XML_RELAXNG_CHOICE: {
Daniel Veillard580ced82003-03-21 21:22:48 +00008416 xmlRelaxNGDefinePtr list = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008417 xmlRelaxNGStatesPtr states = NULL;
8418
Daniel Veillarde063f482003-03-21 16:53:17 +00008419 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008420
Daniel Veillarde063f482003-03-21 16:53:17 +00008421 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8422 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8423
8424 /*
8425 * Something we can optimize cleanly there is only one
8426 * possble branch out !
8427 */
8428 if (node == NULL) {
8429 ret = -1;
8430 break;
8431 }
8432 if ((node->type == XML_TEXT_NODE) ||
8433 (node->type == XML_CDATA_SECTION_NODE)) {
8434 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8435 } else if (node->type == XML_ELEMENT_NODE) {
8436 if (node->ns != NULL) {
8437 list = xmlHashLookup2(triage, node->name,
8438 node->ns->href);
8439 if (list == NULL)
8440 list = xmlHashLookup2(triage, BAD_CAST "#any",
8441 node->ns->href);
8442 } else
8443 list = xmlHashLookup2(triage, node->name, NULL);
8444 if (list == NULL)
8445 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8446 }
8447 if (list == NULL) {
8448 ret = -1;
8449 break;
8450 }
8451 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8452 break;
8453 }
8454
8455 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008456 oldflags = ctxt->flags;
8457 errNr = ctxt->errNr;
8458 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008459
8460 while (list != NULL) {
8461 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8462 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8463 if (ret == 0) {
8464 if (states == NULL) {
8465 states = xmlRelaxNGNewStates(ctxt, 1);
8466 }
8467 if (ctxt->state != NULL) {
8468 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8469 } else if (ctxt->states != NULL) {
8470 for (i = 0;i < ctxt->states->nbState;i++) {
8471 xmlRelaxNGAddStates(ctxt, states,
8472 ctxt->states->tabState[i]);
8473 }
8474 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8475 ctxt->states = NULL;
8476 }
8477 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008478 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008479 }
8480 ctxt->state = oldstate;
8481 list = list->next;
8482 }
8483 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008484 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008485 ctxt->states = states;
8486 ctxt->state = NULL;
8487 ret = 0;
8488 } else {
8489 ctxt->states = NULL;
8490 }
8491 ctxt->flags = oldflags;
8492 if (ret != 0) {
8493 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8494 xmlRelaxNGDumpValidError(ctxt);
8495 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008496 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008497 }
8498 break;
8499 }
8500 case XML_RELAXNG_DEF:
8501 case XML_RELAXNG_GROUP:
8502 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008503 break;
8504 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008505 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008506 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008507 case XML_RELAXNG_ATTRIBUTE:
8508 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8509 break;
8510 case XML_RELAXNG_NOOP:
8511 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008512 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008513 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8514 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008515 case XML_RELAXNG_PARENTREF:
8516 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8517 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008518 case XML_RELAXNG_DATATYPE: {
8519 xmlNodePtr child;
8520 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008521
Daniel Veillardfd573f12003-03-16 17:52:32 +00008522 child = node;
8523 while (child != NULL) {
8524 if (child->type == XML_ELEMENT_NODE) {
8525 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8526 node->parent->name);
8527 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008528 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008529 } else if ((child->type == XML_TEXT_NODE) ||
8530 (child->type == XML_CDATA_SECTION_NODE)) {
8531 content = xmlStrcat(content, child->content);
8532 }
8533 /* TODO: handle entities ... */
8534 child = child->next;
8535 }
8536 if (ret == -1) {
8537 if (content != NULL)
8538 xmlFree(content);
8539 break;
8540 }
8541 if (content == NULL) {
8542 content = xmlStrdup(BAD_CAST "");
8543 if (content == NULL) {
8544 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8545 ret = -1;
8546 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008547 }
8548 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008549 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8550 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008551 if (ret == -1) {
8552 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8553 } else if (ret == 0) {
8554 ctxt->state->seq = NULL;
8555 }
8556 if (content != NULL)
8557 xmlFree(content);
8558 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008559 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008560 case XML_RELAXNG_VALUE: {
8561 xmlChar *content = NULL;
8562 xmlChar *oldvalue;
8563 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008564
Daniel Veillardfd573f12003-03-16 17:52:32 +00008565 child = node;
8566 while (child != NULL) {
8567 if (child->type == XML_ELEMENT_NODE) {
8568 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8569 node->parent->name);
8570 ret = -1;
8571 break;
8572 } else if ((child->type == XML_TEXT_NODE) ||
8573 (child->type == XML_CDATA_SECTION_NODE)) {
8574 content = xmlStrcat(content, child->content);
8575 }
8576 /* TODO: handle entities ... */
8577 child = child->next;
8578 }
8579 if (ret == -1) {
8580 if (content != NULL)
8581 xmlFree(content);
8582 break;
8583 }
8584 if (content == NULL) {
8585 content = xmlStrdup(BAD_CAST "");
8586 if (content == NULL) {
8587 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8588 ret = -1;
8589 break;
8590 }
8591 }
8592 oldvalue = ctxt->state->value;
8593 ctxt->state->value = content;
8594 ret = xmlRelaxNGValidateValue(ctxt, define);
8595 ctxt->state->value = oldvalue;
8596 if (ret == -1) {
8597 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8598 } else if (ret == 0) {
8599 ctxt->state->seq = NULL;
8600 }
8601 if (content != NULL)
8602 xmlFree(content);
8603 break;
8604 }
8605 case XML_RELAXNG_LIST: {
8606 xmlChar *content;
8607 xmlNodePtr child;
8608 xmlChar *oldvalue, *oldendvalue;
8609 int len;
8610
8611 /*
8612 * Make sure it's only text nodes
8613 */
8614
8615 content = NULL;
8616 child = node;
8617 while (child != NULL) {
8618 if (child->type == XML_ELEMENT_NODE) {
8619 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8620 node->parent->name);
8621 ret = -1;
8622 break;
8623 } else if ((child->type == XML_TEXT_NODE) ||
8624 (child->type == XML_CDATA_SECTION_NODE)) {
8625 content = xmlStrcat(content, child->content);
8626 }
8627 /* TODO: handle entities ... */
8628 child = child->next;
8629 }
8630 if (ret == -1) {
8631 if (content != NULL)
8632 xmlFree(content);
8633 break;
8634 }
8635 if (content == NULL) {
8636 content = xmlStrdup(BAD_CAST "");
8637 if (content == NULL) {
8638 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8639 ret = -1;
8640 break;
8641 }
8642 }
8643 len = xmlStrlen(content);
8644 oldvalue = ctxt->state->value;
8645 oldendvalue = ctxt->state->endvalue;
8646 ctxt->state->value = content;
8647 ctxt->state->endvalue = content + len;
8648 ret = xmlRelaxNGValidateValue(ctxt, define);
8649 ctxt->state->value = oldvalue;
8650 ctxt->state->endvalue = oldendvalue;
8651 if (ret == -1) {
8652 VALID_ERR(XML_RELAXNG_ERR_LIST);
8653 } else if ((ret == 0) && (node != NULL)) {
8654 ctxt->state->seq = node->next;
8655 }
8656 if (content != NULL)
8657 xmlFree(content);
8658 break;
8659 }
8660 case XML_RELAXNG_START:
8661 case XML_RELAXNG_EXCEPT:
8662 case XML_RELAXNG_PARAM:
8663 TODO
8664 ret = -1;
8665 break;
8666 }
8667 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008668#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008669 for (i = 0;i < ctxt->depth;i++)
8670 xmlGenericError(xmlGenericErrorContext, " ");
8671 xmlGenericError(xmlGenericErrorContext,
8672 "Validating %s ", xmlRelaxNGDefName(define));
8673 if (define->name != NULL)
8674 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8675 if (ret == 0)
8676 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8677 else
8678 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008679#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008680 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008681}
8682
8683/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008684 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008685 * @ctxt: a Relax-NG validation context
8686 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008687 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008688 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008689 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008690 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008691 */
8692static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008693xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8694 xmlRelaxNGDefinePtr define) {
8695 xmlRelaxNGStatesPtr states, res;
8696 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008697
Daniel Veillardfd573f12003-03-16 17:52:32 +00008698 /*
8699 * We should NOT have both ctxt->state and ctxt->states
8700 */
8701 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8702 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008703 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008704 ctxt->state = NULL;
8705 }
8706
8707 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8708 if (ctxt->states != NULL) {
8709 ctxt->state = ctxt->states->tabState[0];
8710 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8711 ctxt->states = NULL;
8712 }
8713 ret = xmlRelaxNGValidateState(ctxt, define);
8714 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8715 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008716 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008717 ctxt->state = NULL;
8718 }
8719 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8720 ctxt->state = ctxt->states->tabState[0];
8721 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8722 ctxt->states = NULL;
8723 }
8724 return(ret);
8725 }
8726
8727 states = ctxt->states;
8728 ctxt->states = NULL;
8729 res = NULL;
8730 j = 0;
8731 oldflags = ctxt->flags;
8732 ctxt->flags |= FLAGS_IGNORABLE;
8733 for (i = 0;i < states->nbState;i++) {
8734 ctxt->state = states->tabState[i];
8735 ctxt->states = NULL;
8736 ret = xmlRelaxNGValidateState(ctxt, define);
8737 /*
8738 * We should NOT have both ctxt->state and ctxt->states
8739 */
8740 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8741 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008742 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008743 ctxt->state = NULL;
8744 }
8745 if (ret == 0) {
8746 if (ctxt->states == NULL) {
8747 if (res != NULL) {
8748 /* add the state to the container */
8749 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8750 ctxt->state = NULL;
8751 } else {
8752 /* add the state directly in states */
8753 states->tabState[j++] = ctxt->state;
8754 ctxt->state = NULL;
8755 }
8756 } else {
8757 if (res == NULL) {
8758 /* make it the new container and copy other results */
8759 res = ctxt->states;
8760 ctxt->states = NULL;
8761 for (k = 0;k < j;k++)
8762 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8763 } else {
8764 /* add all the new results to res and reff the container */
8765 for (k = 0;k < ctxt->states->nbState;k++)
8766 xmlRelaxNGAddStates(ctxt, res,
8767 ctxt->states->tabState[k]);
8768 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8769 ctxt->states = NULL;
8770 }
8771 }
8772 } else {
8773 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008774 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008775 ctxt->state = NULL;
8776 } else if (ctxt->states != NULL) {
8777 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008778 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008779 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8780 ctxt->states = NULL;
8781 }
8782 }
8783 }
8784 ctxt->flags = oldflags;
8785 if (res != NULL) {
8786 xmlRelaxNGFreeStates(ctxt, states);
8787 ctxt->states = res;
8788 ret = 0;
8789 } else if (j > 1) {
8790 states->nbState = j;
8791 ctxt->states = states;
8792 ret =0;
8793 } else if (j == 1) {
8794 ctxt->state = states->tabState[0];
8795 xmlRelaxNGFreeStates(ctxt, states);
8796 ret = 0;
8797 } else {
8798 ret = -1;
8799 xmlRelaxNGFreeStates(ctxt, states);
8800 if (ctxt->states != NULL) {
8801 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8802 ctxt->states = NULL;
8803 }
8804 }
8805 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8806 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008807 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008808 ctxt->state = NULL;
8809 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008810 return(ret);
8811}
8812
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008813/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008814 * xmlRelaxNGValidateDocument:
8815 * @ctxt: a Relax-NG validation context
8816 * @doc: the document
8817 *
8818 * Validate the given document
8819 *
8820 * Returns 0 if the validation succeeded or an error code.
8821 */
8822static int
8823xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8824 int ret;
8825 xmlRelaxNGPtr schema;
8826 xmlRelaxNGGrammarPtr grammar;
8827 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008828 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008829
8830 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8831 return(-1);
8832
8833 schema = ctxt->schema;
8834 grammar = schema->topgrammar;
8835 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008836 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008837 return(-1);
8838 }
8839 state = xmlRelaxNGNewValidState(ctxt, NULL);
8840 ctxt->state = state;
8841 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008842 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8843 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008844 node = state->seq;
8845 node = xmlRelaxNGSkipIgnored(ctxt, node);
8846 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008847 if (ret != -1) {
8848 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8849 ret = -1;
8850 }
8851 }
8852 } else if (ctxt->states != NULL) {
8853 int i;
8854 int tmp = -1;
8855
8856 for (i = 0;i < ctxt->states->nbState;i++) {
8857 state = ctxt->states->tabState[i];
8858 node = state->seq;
8859 node = xmlRelaxNGSkipIgnored(ctxt, node);
8860 if (node == NULL)
8861 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008862 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008863 }
8864 if (tmp == -1) {
8865 if (ret != -1) {
8866 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8867 ret = -1;
8868 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008869 }
8870 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008871 if (ctxt->state != NULL) {
8872 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8873 ctxt->state = NULL;
8874 }
Daniel Veillard580ced82003-03-21 21:22:48 +00008875 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00008876 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00008877#ifdef DEBUG
8878 else if (ctxt->errNr != 0) {
8879 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
8880 ctxt->errNr);
8881 xmlRelaxNGDumpValidError(ctxt);
8882 }
8883#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008884 if (ctxt->idref == 1) {
8885 xmlValidCtxt vctxt;
8886
8887 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8888 vctxt.valid = 1;
8889 vctxt.error = ctxt->error;
8890 vctxt.warning = ctxt->warning;
8891 vctxt.userData = ctxt->userData;
8892
8893 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8894 ret = -1;
8895 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008896
8897 return(ret);
8898}
8899
Daniel Veillardfd573f12003-03-16 17:52:32 +00008900/************************************************************************
8901 * *
8902 * Validation interfaces *
8903 * *
8904 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008905/**
8906 * xmlRelaxNGNewValidCtxt:
8907 * @schema: a precompiled XML RelaxNGs
8908 *
8909 * Create an XML RelaxNGs validation context based on the given schema
8910 *
8911 * Returns the validation context or NULL in case of error
8912 */
8913xmlRelaxNGValidCtxtPtr
8914xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
8915 xmlRelaxNGValidCtxtPtr ret;
8916
8917 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
8918 if (ret == NULL) {
8919 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00008920 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00008921 return (NULL);
8922 }
8923 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
8924 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00008925 ret->error = xmlGenericError;
8926 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008927 ret->errNr = 0;
8928 ret->errMax = 0;
8929 ret->err = NULL;
8930 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008931 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00008932 ret->states = NULL;
8933 ret->freeState = NULL;
8934 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008935 return (ret);
8936}
8937
8938/**
8939 * xmlRelaxNGFreeValidCtxt:
8940 * @ctxt: the schema validation context
8941 *
8942 * Free the resources associated to the schema validation context
8943 */
8944void
8945xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008946 int k;
8947
Daniel Veillard6eadf632003-01-23 18:29:16 +00008948 if (ctxt == NULL)
8949 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008950 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008951 xmlRelaxNGFreeStates(NULL, ctxt->states);
8952 if (ctxt->freeState != NULL) {
8953 for (k = 0;k < ctxt->freeState->nbState;k++) {
8954 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
8955 }
8956 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
8957 }
Daniel Veillard798024a2003-03-19 10:36:09 +00008958 if (ctxt->freeStates != NULL) {
8959 for (k = 0;k < ctxt->freeStatesNr;k++) {
8960 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
8961 }
8962 xmlFree(ctxt->freeStates);
8963 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00008964 if (ctxt->errTab != NULL)
8965 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008966 xmlFree(ctxt);
8967}
8968
8969/**
8970 * xmlRelaxNGSetValidErrors:
8971 * @ctxt: a Relax-NG validation context
8972 * @err: the error function
8973 * @warn: the warning function
8974 * @ctx: the functions context
8975 *
8976 * Set the error and warning callback informations
8977 */
8978void
8979xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
8980 xmlRelaxNGValidityErrorFunc err,
8981 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
8982 if (ctxt == NULL)
8983 return;
8984 ctxt->error = err;
8985 ctxt->warning = warn;
8986 ctxt->userData = ctx;
8987}
8988
8989/**
8990 * xmlRelaxNGValidateDoc:
8991 * @ctxt: a Relax-NG validation context
8992 * @doc: a parsed document tree
8993 *
8994 * Validate a document tree in memory.
8995 *
8996 * Returns 0 if the document is valid, a positive error code
8997 * number otherwise and -1 in case of internal or API error.
8998 */
8999int
9000xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9001 int ret;
9002
9003 if ((ctxt == NULL) || (doc == NULL))
9004 return(-1);
9005
9006 ctxt->doc = doc;
9007
9008 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009009 /*
9010 * TODO: build error codes
9011 */
9012 if (ret == -1)
9013 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009014 return(ret);
9015}
9016
9017#endif /* LIBXML_SCHEMAS_ENABLED */
9018